Changeset 9672
- Timestamp:
- 17 Nov 2012, 22:43:58 (12 years ago)
- Location:
- main/waeup.kofa/trunk/src/waeup/kofa
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.kofa/trunk/src/waeup/kofa/browser/reports.py
r9667 r9672 48 48 self.context.delete_report_entry(entry) 49 49 self.flash('Report discarded: %s' % job_id) 50 self.entries = self.context.get_report_jobs_description() 50 self.entries = self._generate_entries(user_id=None) 51 #self.entries = self.context.get_report_jobs_description() 51 52 if job_id and DOWNLOAD: 52 53 self.redirect(self._report_url(job_id)) 53 54 return 54 55 return 56 57 def _generate_entries(self, user_id=None): 58 entries = [] 59 for entry in self.context.get_running_report_jobs(user_id=user_id): 60 job_id, gen_name, user = entry 61 job = getUtility(IJobManager).get(job_id) 62 descr = '%r, %r' % (job.args, job.kwargs) 63 new_entry = (job_id, descr, job.status, job.finished, job.finished and not job.failed, not job.finished, job.begin_after, user) 64 entries.append(new_entry) 65 return entries 55 66 56 67 -
main/waeup.kofa/trunk/src/waeup/kofa/reports.py
r9670 r9672 22 22 from persistent.list import PersistentList 23 23 from zope import schema 24 from zope.component import ( 25 getUtility, getUtilitiesFor, queryUtility) 24 from zope.component import getUtility, getUtilitiesFor 26 25 from zope.component.hooks import setSite 27 26 from zope.interface import implementer … … 29 28 from waeup.kofa.async import AsyncJob 30 29 from waeup.kofa.interfaces import ( 31 IJobManager, JOB_STATUS_MAP, IKofaPluggable, IKofaObject , IKofaUtils)30 IJobManager, JOB_STATUS_MAP, IKofaPluggable, IKofaObject) 32 31 from waeup.kofa.interfaces import MessageFactory as _ 33 32 from waeup.kofa.utils.helpers import now 34 35 #: A status map that reflects the really interesting types of status36 #: for reports.37 #:38 #: For reports we want to know whether a job was finished39 #: and/or whether it failed. All the other possible states ('new',40 #: etc.) are not really interesting in that regard.41 STATUS_MAP = {42 'unknown': _('unknown'),43 'running': _('running'),44 'finished': _('finished'),45 'failed': _('FAILED'),46 }47 33 48 34 class IReport(Interface): … … 58 44 """not when any output was created.""") 59 45 60 title = schema.TextLine(61 title = u"A human readable short description for a report.",62 default = u'Untitled',63 )64 65 description = schema.Text(66 title = u"A human readable text describing a report.",67 default = u'No description'68 )69 70 46 def create_pdf(): 71 47 """Generate a PDF copy. … … 93 69 title = u"`True` iff the job finished and didn't provide a report.", 94 70 default = None, 95 )96 97 description = schema.TextLine(98 title = u"""Textual representation of arguments and keywords.""",99 default = u"",100 )101 102 report_status = schema.TextLine(103 title = u"""Translated status string.""",104 default = STATUS_MAP['unknown'],105 71 ) 106 72 … … 150 116 """ 151 117 152 def get_report_jobs_description(user_id=None):153 """Get running/completed report jobs for `user_id` as list of tuples.154 155 The results contain enough information to render a status page156 or similar. Each tuple holds::157 158 (``<job_id>, <description>, <status_translated>,159 <discardable>, <downloadable>, <starttime>, <user_name>``)160 161 in that order, with162 163 ``<job_id>``164 The job id of the represented job. A string.165 166 ``<description>``167 A human readable description of the report run.168 169 ``<status_translated>``170 The status of report jobs' status (translated)171 172 ``<discardable>``173 Boolean indicating whether the job can be discarded.174 Only completed jobs can be discarded.175 176 ``<downloadable>``177 Boolean indicating whether the job result can be178 downloaded. This is only true if the job finished and179 didn't raised exceptions.180 181 ``<starttime>``182 String indicating when the job was started.183 184 ``<user_name>``185 Name of user that started the job.186 187 If ``user_id`` is ``None``, all jobs are returned.188 """189 190 118 def delete_report_entry(entry): 191 119 """Delete the report job denoted by `entry`. … … 233 161 def title(self): 234 162 return _(u'A report') 235 236 @property237 def description(self):238 return _(u'A dummy report')239 163 240 164 def __init__(self, args=[], kwargs={}): … … 245 169 def create_pdf(self): 246 170 raise NotImplementedError() 247 248 def __repr__(self):249 return 'Report(args=%r, kwargs=%r)' % (self.args, self.kwargs)250 251 171 252 172 @implementer(IReportGenerator) … … 324 244 return True 325 245 return False 326 327 @property328 def report_status(self):329 """The status of a report as translated string.330 """331 if not self.finished:332 return STATUS_MAP['running']333 if self.failed:334 return STATUS_MAP['failed']335 return STATUS_MAP['finished']336 337 @property338 def description(self):339 """A description gives a representation of the report to generate.340 341 The description contains the name of the report generator342 (trying to fetch the `name` attribute of the requested report343 generator) and the arguments and keywords passed in.344 345 Please note that this method is expensive!346 """347 args = self.kwargs.get('args', [])348 kw = self.kwargs.get('kw', dict())349 args = ', '.join(["%r" % x for x in args])350 kw = ', '.join(['%s' % val for val in kw.values()])351 if len(args) and len(kw):352 str_repr = args + ', ' + kw353 else:354 str_repr = args + kw355 str_repr = '(' + str_repr + ')'356 try:357 generator = getUtility(358 IReportGenerator, name=self._generator_name)359 name = generator.title360 except:361 name = _('Unregistered Report Generator')362 return name + ' ' + str_repr363 246 364 247 @implementer(IReportJobContainer) … … 439 322 return result 440 323 441 def get_report_jobs_description(self, user_id=None):442 """Get running/completed report jobs fur `user_id` as list of tuples.443 444 The results contain enough information to render a status page445 or similar. Each tuple holds::446 447 (``<job_id>, <description>, <status_translated>,448 <discardable>, <downloadable>, <starttime>, <user_name>``)449 450 in that order, with451 452 ``<job_id>``453 The job id of the represented job. A string.454 455 ``<description>``456 A human readable description of the report run.457 458 ``<status_translated>``459 The status of report jobs' status (translated)460 461 ``<discardable>``462 Boolean indicating whether the job can be discarded.463 Only completed jobs can be discarded.464 465 ``<downloadable>``466 Boolean indicating whether the job result can be467 downloaded. This is only true if the job finished and468 didn't raised exceptions.469 470 ``<starttime>``471 String indicating when the job was started.472 473 ``<user_name>``474 Name of user that started the job.475 476 If ``user_id`` is ``None``, all jobs are returned.477 """478 entries = self.get_running_report_jobs(user_id)479 result = []480 for (job_id, gen_name, user_name) in entries:481 manager = getUtility(IJobManager)482 job = manager.get(job_id)483 status = job.report_status484 discardable = job.finished485 downloadable = job.finished and not job.failed486 running = not (downloadable or discardable)487 starttime = getattr(job, 'begin_after', None)488 if starttime:489 starttime = starttime.astimezone(getUtility(IKofaUtils).tzinfo)490 starttime = starttime.strftime("%Y-%m-%d %H:%M:%S %Z")491 if not hasattr(job, 'description'):492 continue493 result.append((job_id, job.description, status,494 discardable, downloadable, running,495 starttime, user_name),)496 return result497 498 324 def delete_report_entry(self, entry): 499 325 """Delete the report job denoted by `entry`. -
main/waeup.kofa/trunk/src/waeup/kofa/students/reports.py
r9670 r9672 128 128 self.data = get_students_by(session, mode) 129 129 130 def __repr__(self):131 """Creates an executable representation of a StudentsReport object.132 """133 return 'StudentsReport(%r, %r, author=%r)' % (134 self.args[0], self.mode, self.author)135 136 #def __str__(self):137 # """A nice human readable representation of a StudentsReport.138 139 # Includes infos about session, mode and creation datetime.140 # """141 # return 'Students Report [session=%s, mode=%s] of %s ' % (142 # self.session, self.mode, self._creation_dt_string)143 144 130 @property 145 131 def title(self): … … 169 155 title = _('Students') 170 156 grok.name('students_by') 171 172 @property173 def description(self):174 return self.title175 157 176 158 def generate(self, site, session=None, mode=None, author=None): -
main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_reports.py
r9671 r9672 20 20 verifyObject(IStudentsReport, obj) 21 21 return 22 23 def test_repr(self):24 # exec(students_report.__repr__()) <=> students_report25 obj1 = StudentsReport(2010, 'Undergraduate Full-Time', author='Bob')26 self.assertEqual(27 obj1.__repr__(),28 "StudentsReport(2010, 'Undergraduate Full-Time', author='Bob')")29 obj_from_str = eval(obj1.__repr__())30 self.assertEqual(obj_from_str.session, '2010/2011')31 self.assertEqual(obj_from_str.mode, 'Undergraduate Full-Time')32 self.assertEqual(obj_from_str.author, 'Bob')33 return34 35 #def test_str(self):36 # # StudentsReport provide a nice string representation37 # obj = StudentsReport(2010, 'Undergraduate Full-Time', author='Bob')38 # self.assertEqual(39 # obj.__str__()[:65],40 # 'Students Report '41 # '[session=2010/2011, mode=Undergraduate Full-Time]')42 # return43 22 44 23 def test_title(self): -
main/waeup.kofa/trunk/src/waeup/kofa/tests/test_reports.py
r9670 r9672 211 211 return 212 212 213 def test_description(self):214 # IReportJobs provide a description of the started job215 self.register_generator('report1')216 args, kw = ['a', 'b'], dict(a=1, b=2)217 job = AsyncReportJob(self.root_folder, 'report1', args=args, kw=kw)218 self.assertEqual(219 job.description,220 "Report 1 ('a', 'b', 1, 2)")221 # w/o args nor kwargs222 job = AsyncReportJob(self.root_folder, 'report1')223 self.assertEqual(224 job.description,225 'Report 1 ()')226 # with args only227 job = AsyncReportJob(self.root_folder, 'report1', args=args)228 self.assertEqual(229 job.description, "Report 1 ('a', 'b')")230 # with keywords only231 job = AsyncReportJob(self.root_folder, 'report1', kw=kw)232 self.assertEqual(233 job.description, "Report 1 (1, 2)")234 return235 236 def test_description_invalid_generator(self):237 # We can get a description even with an invalid generator238 job = AsyncReportJob(self.root_folder, 'NOT EXISTENT')239 self.assertEqual(240 job.description, u'Unregistered Report Generator ()')241 # with args set (no kws)242 job = AsyncReportJob(243 self.root_folder, 'NOT EXISTENT', args=['a', 'b'])244 self.assertEqual(245 job.description, u"Unregistered Report Generator ('a', 'b')")246 # with kw set (no args)247 job = AsyncReportJob(248 self.root_folder, 'NOT_EXISTENT', kw=dict(a=1, b=2))249 self.assertEqual(250 job.description, u'Unregistered Report Generator (1, 2)')251 # with args and kws set252 job = AsyncReportJob(253 self.root_folder, 'NOT_EXISTENT', args=['a'], kw=dict(b=2))254 self.assertEqual(255 job.description, u"Unregistered Report Generator ('a', 2)")256 return257 258 def test_report_status(self):259 # We can get a report status apart from the job status260 job = AsyncReportJob(self.root_folder, 'report1')261 self.assertEqual(job.report_status, u'running')262 return263 264 def test_report_status_failed(self):265 # A failed job is reflected in report_status266 job = AsyncReportJob(self.root_folder, None) # no report generator267 setSite(self.root_folder)268 self.assertTrue(job.failed is None)269 manager = getUtility(IJobManager)270 manager.put(job)271 wait_for_result(job)272 self.assertEqual(job.report_status, u'FAILED')273 return274 275 def test_report_status_finished(self):276 # A finished report is reflected in report_status277 job = AsyncReportJob(self.root_folder, 'report1')278 setSite(self.root_folder)279 manager = getUtility(IJobManager)280 manager.put(job)281 wait_for_result(job)282 self.assertEqual(job.report_status, u'finished')283 return284 285 213 class FakeJobWithResult(FakeJob): 286 214 … … 383 311 [('new', u'new', u'Report 1'), 384 312 ('completed', u'completed', u'Report 1')] 385 )386 return387 388 def test_get_report_job_description(self):389 # we can get the descriptions of jobs...390 container = ReportJobContainer()391 container.start_report_job('report1', 'alice')392 container.start_report_job('report1', 'bob')393 result = container.get_report_jobs_description(user_id='bob')394 # we'll get the job id, a description and the status395 self.assertEqual(396 result,397 [('2', 'Report 1 ()', u'running', False, False, True, None, 'bob'),]398 313 ) 399 314 return
Note: See TracChangeset for help on using the changeset viewer.