Package Gnumed :: Package wxpython :: Module gmMacro
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmMacro

  1  """GNUmed macro primitives. 
  2   
  3  This module implements functions a macro can legally use. 
  4  """ 
  5  #===================================================================== 
  6  __version__ = "$Revision: 1.51 $" 
  7  __author__ = "K.Hilbert <karsten.hilbert@gmx.net>" 
  8   
  9  import sys, time, random, types, logging 
 10   
 11   
 12  import wx 
 13   
 14   
 15  if __name__ == '__main__': 
 16          sys.path.insert(0, '../../') 
 17  from Gnumed.pycommon import gmI18N, gmGuiBroker, gmExceptions, gmBorg, gmTools 
 18  from Gnumed.pycommon import gmCfg2, gmDateTime 
 19  from Gnumed.business import gmPerson, gmDemographicRecord, gmMedication 
 20  from Gnumed.wxpython import gmGuiHelpers, gmPlugin, gmPatSearchWidgets, gmNarrativeWidgets 
 21   
 22   
 23  _log = logging.getLogger('gm.scripting') 
 24  _cfg = gmCfg2.gmCfgData() 
 25   
 26  #===================================================================== 
 27  known_placeholders = [ 
 28          'lastname', 
 29          'firstname', 
 30          'title', 
 31          'date_of_birth', 
 32          'progress_notes', 
 33          'soap', 
 34          'soap_s', 
 35          'soap_o', 
 36          'soap_a', 
 37          'soap_p', 
 38          u'client_version', 
 39          u'current_provider', 
 40          u'allergy_state' 
 41  ] 
 42   
 43   
 44  # those must satisfy the pattern "$name::args::optional length$" when used 
 45  known_variant_placeholders = [ 
 46          u'soap', 
 47          u'progress_notes', 
 48          u'date_of_birth', 
 49          u'adr_street',                          # "data" holds: type of address 
 50          u'adr_number', 
 51          u'adr_location', 
 52          u'adr_postcode', 
 53          u'gender_mapper',                       # "data" holds: value for male // value for female 
 54          u'current_meds',                        # "data" holds: line template 
 55          u'current_meds_table',          # "data" holds: format, options 
 56          u'today',                                       # "data" holds: strftime format 
 57          u'tex_escape',                          # "data" holds: string to escape 
 58          u'allergies',                           # "data" holds: line template, one allergy per line 
 59          u'allergy_list',                        # "data" holds: template per allergy, allergies on one line 
 60          u'problems',                            # "data" holds: line template, one problem per line 
 61          u'name'                                         # "data" holds: template for name parts arrangement 
 62  ] 
 63   
 64  default_placeholder_regex = r'\$<.+?>\$'                                # this one works (except that OOo cannot be non-greedy |-( ) 
 65   
 66  #_regex_parts = [ 
 67  #       r'\$<\w+::.*(?::)\d+>\$', 
 68  #       r'\$<\w+::.+(?!>\$)>\$', 
 69  #       r'\$<\w+?>\$' 
 70  #] 
 71  #default_placeholder_regex = r'|'.join(_regex_parts) 
 72   
 73  default_placeholder_start = u'$<' 
 74  default_placeholder_end = u'>$' 
 75  #===================================================================== 
76 -class gmPlaceholderHandler(gmBorg.cBorg):
77 """Replaces placeholders in forms, fields, etc. 78 79 - patient related placeholders operate on the currently active patient 80 - is passed to the forms handling code, for example 81 82 Note that this cannot be called from a non-gui thread unless 83 wrapped in wx.CallAfter. 84 85 There are currently three types of placeholders: 86 87 simple static placeholders 88 - those are listed in known_placeholders 89 - they are used as-is 90 91 extended static placeholders 92 - those are like the static ones but have "::::<NUMBER>" appended 93 where <NUMBER> is the maximum length 94 95 variant placeholders 96 - those are listed in known_variant_placeholders 97 - they are parsed into placeholder, data, and maximum length 98 - the length is optional 99 - data is passed to the handler 100 """
101 - def __init__(self, *args, **kwargs):
102 103 self.pat = gmPerson.gmCurrentPatient() 104 self.debug = False 105 106 self.invalid_placeholder_template = _('invalid placeholder [%s]')
107 #-------------------------------------------------------- 108 # __getitem__ API 109 #--------------------------------------------------------
110 - def __getitem__(self, placeholder):
111 """Map self['placeholder'] to self.placeholder. 112 113 This is useful for replacing placeholders parsed out 114 of documents as strings. 115 116 Unknown/invalid placeholders still deliver a result but 117 it will be glaringly obvious if debugging is enabled. 118 """ 119 _log.debug('replacing [%s]', placeholder) 120 121 original_placeholder = placeholder 122 123 if placeholder.startswith(default_placeholder_start): 124 placeholder = placeholder[len(default_placeholder_start):] 125 if placeholder.endswith(default_placeholder_end): 126 placeholder = placeholder[:-len(default_placeholder_end)] 127 else: 128 _log.debug('placeholder must either start with [%s] and end with [%s] or neither of both', default_placeholder_start, default_placeholder_end) 129 if self.debug: 130 return self.invalid_placeholder_template % original_placeholder 131 return None 132 133 # simple static placeholder ? 134 if placeholder in known_placeholders: 135 return getattr(self, placeholder) 136 137 # extended static placeholder ? 138 parts = placeholder.split('::::', 1) 139 if len(parts) == 2: 140 name, lng = parts 141 try: 142 return getattr(self, name)[:int(lng)] 143 except: 144 _log.exception('placeholder handling error: %s', original_placeholder) 145 if self.debug: 146 return self.invalid_placeholder_template % original_placeholder 147 return None 148 149 # variable placeholders 150 parts = placeholder.split('::', 2) 151 if len(parts) == 2: 152 name, data = parts 153 lng = None 154 elif len(parts) == 3: 155 name, data, lng = parts 156 try: 157 lng = int(lng) 158 except: 159 _log.exception('placeholder length definition error: %s, discarding length', original_placeholder) 160 lng = None 161 else: 162 _log.warning('invalid placeholder layout: %s', original_placeholder) 163 if self.debug: 164 return self.invalid_placeholder_template % original_placeholder 165 return None 166 167 handler = getattr(self, '_get_variant_%s' % name, None) 168 if handler is None: 169 _log.warning('no handler <_get_variant_%s> for placeholder %s', name, original_placeholder) 170 if self.debug: 171 return self.invalid_placeholder_template % original_placeholder 172 return None 173 174 try: 175 if lng is None: 176 return handler(data = data) 177 return handler(data = data)[:lng] 178 except: 179 _log.exception('placeholder handling error: %s', original_placeholder) 180 if self.debug: 181 return self.invalid_placeholder_template % original_placeholder 182 return None 183 184 _log.error('something went wrong, should never get here') 185 return None
186 #-------------------------------------------------------- 187 # properties actually handling placeholders 188 #-------------------------------------------------------- 189 # property helpers 190 #--------------------------------------------------------
191 - def _setter_noop(self, val):
192 """This does nothing, used as a NOOP properties setter.""" 193 pass
194 #--------------------------------------------------------
195 - def _get_lastname(self):
196 return self.pat.get_active_name()['lastnames']
197 #--------------------------------------------------------
198 - def _get_firstname(self):
199 return self.pat.get_active_name()['firstnames']
200 #--------------------------------------------------------
201 - def _get_title(self):
202 return gmTools.coalesce(self.pat.get_active_name()['title'], u'')
203 #--------------------------------------------------------
204 - def _get_dob(self):
205 return self._get_variant_date_of_birth(data='%x')
206 #--------------------------------------------------------
207 - def _get_progress_notes(self):
208 return self._get_variant_soap()
209 #--------------------------------------------------------
210 - def _get_soap_s(self):
211 return self._get_variant_soap(data = u's')
212 #--------------------------------------------------------
213 - def _get_soap_o(self):
214 return self._get_variant_soap(data = u'o')
215 #--------------------------------------------------------
216 - def _get_soap_a(self):
217 return self._get_variant_soap(data = u'a')
218 #--------------------------------------------------------
219 - def _get_soap_p(self):
220 return self._get_variant_soap(data = u'p')
221 #--------------------------------------------------------
222 - def _get_soap_admin(self):
223 return self._get_variant_soap(soap_cats = None)
224 #--------------------------------------------------------
225 - def _get_client_version(self):
226 return gmTools.coalesce ( 227 _cfg.get(option = u'client_version'), 228 u'%s' % self.__class__.__name__ 229 )
230 #--------------------------------------------------------
231 - def _get_current_provider(self):
232 prov = gmPerson.gmCurrentProvider() 233 234 title = gmTools.coalesce ( 235 prov['title'], 236 gmPerson.map_gender2salutation(prov['gender']) 237 ) 238 239 tmp = u'%s %s. %s' % ( 240 title, 241 prov['firstnames'][:1], 242 prov['lastnames'] 243 ) 244 245 return tmp
246 #--------------------------------------------------------
247 - def _get_allergy_state(self):
248 allg_state = self.pat.get_emr().allergy_state 249 tmp = u'%s (%s)' % ( 250 allg_state.state_string, 251 allg_state['last_confirmed'].strftime('%Y %B %d').decode(gmI18N.get_encoding()) 252 ) 253 return tmp
254 #-------------------------------------------------------- 255 # property definitions for static placeholders 256 #-------------------------------------------------------- 257 placeholder_regex = property(lambda x: default_placeholder_regex, _setter_noop) 258 259 # placeholders 260 lastname = property(_get_lastname, _setter_noop) 261 firstname = property(_get_firstname, _setter_noop) 262 title = property(_get_title, _setter_noop) 263 date_of_birth = property(_get_dob, _setter_noop) 264 265 progress_notes = property(_get_progress_notes, _setter_noop) 266 soap = property(_get_progress_notes, _setter_noop) 267 soap_s = property(_get_soap_s, _setter_noop) 268 soap_o = property(_get_soap_o, _setter_noop) 269 soap_a = property(_get_soap_a, _setter_noop) 270 soap_p = property(_get_soap_p, _setter_noop) 271 soap_admin = property(_get_soap_admin, _setter_noop) 272 273 allergy_state = property(_get_allergy_state, _setter_noop) 274 275 client_version = property(_get_client_version, _setter_noop) 276 277 current_provider = property(_get_current_provider, _setter_noop) 278 #-------------------------------------------------------- 279 # variant handlers 280 #--------------------------------------------------------
281 - def _get_variant_progress_notes(self, data=None):
282 return self._get_variant_soap(data=data)
283 #--------------------------------------------------------
284 - def _get_variant_soap(self, data=None):
285 if data is None: 286 cats = list(data) 287 template = u'%s' 288 else: 289 parts = data.split('//', 2) 290 if len(parts) == 1: 291 cats = list(parts) 292 template = u'%s' 293 else: 294 cats = list(parts[0]) 295 template = parts[1] 296 297 narr = gmNarrativeWidgets.select_narrative_from_episodes(soap_cats = cats) 298 299 if len(narr) == 0: 300 return u'' 301 302 narr = [ template % n['narrative'] for n in narr ] 303 304 return u'\n'.join(narr)
305 #--------------------------------------------------------
306 - def _get_variant_name(self, data=None):
307 if data is None: 308 return [_('template is missing')] 309 310 name = self.pat.get_active_name() 311 312 parts = { 313 'title': gmTools.coalesce(name['title'], u''), 314 'firstnames': name['firstnames'], 315 'lastnames': name['lastnames'], 316 'preferred': gmTools.coalesce ( 317 initial = name['preferred'], 318 instead = u' ', 319 template_initial = u' "%s" ' 320 ) 321 } 322 323 return data % parts
324 #--------------------------------------------------------
325 - def _get_variant_date_of_birth(self, data='%x'):
326 return self.pat.get_formatted_dob(format = str(data), encoding = gmI18N.get_encoding())
327 #-------------------------------------------------------- 328 # FIXME: extend to all supported genders
329 - def _get_variant_gender_mapper(self, data='male//female//other'):
330 values = data.split('//', 2) 331 332 if len(values) == 2: 333 male_value, female_value = values 334 other_value = u'<unkown gender>' 335 elif len(values) == 3: 336 male_value, female_value, other_value = values 337 else: 338 return _('invalid gender mapping layout: [%s]') % data 339 340 if self.pat['gender'] == u'm': 341 return male_value 342 343 if self.pat['gender'] == u'f': 344 return female_value 345 346 return other_value
347 #--------------------------------------------------------
348 - def _get_variant_adr_street(self, data=u'?'):
349 # if data == u'?': 350 # types = xxxxxxxxxxx 351 adrs = self.pat.get_addresses(address_type=data) 352 if len(adrs) == 0: 353 return _('no street for address type [%s]') % data 354 return adrs[0]['street']
355 #--------------------------------------------------------
356 - def _get_variant_adr_number(self, data=u'?'):
357 adrs = self.pat.get_addresses(address_type=data) 358 if len(adrs) == 0: 359 return _('no number for address type [%s]') % data 360 return adrs[0]['number']
361 #--------------------------------------------------------
362 - def _get_variant_adr_location(self, data=u'?'):
363 adrs = self.pat.get_addresses(address_type=data) 364 if len(adrs) == 0: 365 return _('no location for address type [%s]') % data 366 return adrs[0]['urb']
367 #--------------------------------------------------------
368 - def _get_variant_adr_postcode(self, data=u'?'):
369 adrs = self.pat.get_addresses(address_type=data) 370 if len(adrs) == 0: 371 return _('no postcode for address type [%s]') % data 372 return adrs[0]['postcode']
373 #--------------------------------------------------------
374 - def _get_variant_allergy_list(self, data=None):
375 if data is None: 376 return [_('template is missing')] 377 378 template, separator = data.split('//', 2) 379 380 emr = self.pat.get_emr() 381 return separator.join([ template % a for a in emr.get_allergies() ])
382 #--------------------------------------------------------
383 - def _get_variant_allergies(self, data=None):
384 385 if data is None: 386 return [_('template is missing')] 387 388 emr = self.pat.get_emr() 389 return u'\n'.join([ data % a for a in emr.get_allergies() ])
390 #--------------------------------------------------------
391 - def _get_variant_current_meds(self, data=None):
392 393 if data is None: 394 return [_('template is missing')] 395 396 emr = self.pat.get_emr() 397 current_meds = emr.get_current_substance_intake ( 398 include_inactive = False, 399 include_unapproved = False, 400 order_by = u'brand, substance' 401 ) 402 403 # FIXME: we should be dealing with translating None to u'' here 404 405 return u'\n'.join([ data % m for m in current_meds ])
406 #--------------------------------------------------------
407 - def _get_variant_current_meds_table(self, data=None):
408 409 options = data.split('//') 410 411 if u'latex' in options: 412 return gmMedication.format_substance_intake ( 413 emr = self.pat.get_emr(), 414 output_format = u'latex', 415 table_type = u'by-brand' 416 ) 417 418 _log.error('no known current medications table formatting style in [%]', data) 419 return _('unknown current medication table formatting style')
420 #--------------------------------------------------------
421 - def _get_variant_problems(self, data=None):
422 423 if data is None: 424 return [_('template is missing')] 425 426 probs = self.pat.get_emr().get_problems() 427 428 return u'\n'.join([ data % p for p in probs ])
429 #--------------------------------------------------------
430 - def _get_variant_today(self, data='%x'):
432 #--------------------------------------------------------
433 - def _get_variant_tex_escape(self, data=None):
434 return gmTools.tex_escape_string(text = data)
435 #-------------------------------------------------------- 436 # internal helpers 437 #-------------------------------------------------------- 438 439 #=====================================================================
440 -class cMacroPrimitives:
441 """Functions a macro can legally use. 442 443 An instance of this class is passed to the GNUmed scripting 444 listener. Hence, all actions a macro can legally take must 445 be defined in this class. Thus we achieve some screening for 446 security and also thread safety handling. 447 """ 448 #-----------------------------------------------------------------
449 - def __init__(self, personality = None):
450 if personality is None: 451 raise gmExceptions.ConstructorError, 'must specify personality' 452 self.__personality = personality 453 self.__attached = 0 454 self._get_source_personality = None 455 self.__user_done = False 456 self.__user_answer = 'no answer yet' 457 self.__pat = gmPerson.gmCurrentPatient() 458 459 self.__auth_cookie = str(random.random()) 460 self.__pat_lock_cookie = str(random.random()) 461 self.__lock_after_load_cookie = str(random.random()) 462 463 _log.info('slave mode personality is [%s]', personality)
464 #----------------------------------------------------------------- 465 # public API 466 #-----------------------------------------------------------------
467 - def attach(self, personality = None):
468 if self.__attached: 469 _log.error('attach with [%s] rejected, already serving a client', personality) 470 return (0, _('attach rejected, already serving a client')) 471 if personality != self.__personality: 472 _log.error('rejecting attach to personality [%s], only servicing [%s]' % (personality, self.__personality)) 473 return (0, _('attach to personality [%s] rejected') % personality) 474 self.__attached = 1 475 self.__auth_cookie = str(random.random()) 476 return (1, self.__auth_cookie)
477 #-----------------------------------------------------------------
478 - def detach(self, auth_cookie=None):
479 if not self.__attached: 480 return 1 481 if auth_cookie != self.__auth_cookie: 482 _log.error('rejecting detach() with cookie [%s]' % auth_cookie) 483 return 0 484 self.__attached = 0 485 return 1
486 #-----------------------------------------------------------------
487 - def force_detach(self):
488 if not self.__attached: 489 return 1 490 self.__user_done = False 491 # FIXME: use self.__sync_cookie for syncing with user interaction 492 wx.CallAfter(self._force_detach) 493 return 1
494 #-----------------------------------------------------------------
495 - def version(self):
496 ver = _cfg.get(option = u'client_version') 497 return "GNUmed %s, %s $Revision: 1.51 $" % (ver, self.__class__.__name__)
498 #-----------------------------------------------------------------
499 - def shutdown_gnumed(self, auth_cookie=None, forced=False):
500 """Shuts down this client instance.""" 501 if not self.__attached: 502 return 0 503 if auth_cookie != self.__auth_cookie: 504 _log.error('non-authenticated shutdown_gnumed()') 505 return 0 506 wx.CallAfter(self._shutdown_gnumed, forced) 507 return 1
508 #-----------------------------------------------------------------
509 - def raise_gnumed(self, auth_cookie = None):
510 """Raise ourselves to the top of the desktop.""" 511 if not self.__attached: 512 return 0 513 if auth_cookie != self.__auth_cookie: 514 _log.error('non-authenticated raise_gnumed()') 515 return 0 516 return "cMacroPrimitives.raise_gnumed() not implemented"
517 #-----------------------------------------------------------------
518 - def get_loaded_plugins(self, auth_cookie = None):
519 if not self.__attached: 520 return 0 521 if auth_cookie != self.__auth_cookie: 522 _log.error('non-authenticated get_loaded_plugins()') 523 return 0 524 gb = gmGuiBroker.GuiBroker() 525 return gb['horstspace.notebook.gui'].keys()
526 #-----------------------------------------------------------------
527 - def raise_notebook_plugin(self, auth_cookie = None, a_plugin = None):
528 """Raise a notebook plugin within GNUmed.""" 529 if not self.__attached: 530 return 0 531 if auth_cookie != self.__auth_cookie: 532 _log.error('non-authenticated raise_notebook_plugin()') 533 return 0 534 # FIXME: use semaphore 535 wx.CallAfter(gmPlugin.raise_notebook_plugin, a_plugin) 536 return 1
537 #-----------------------------------------------------------------
538 - def load_patient_from_external_source(self, auth_cookie = None):
539 """Load external patient, perhaps create it. 540 541 Callers must use get_user_answer() to get status information. 542 It is unsafe to proceed without knowing the completion state as 543 the controlled client may be waiting for user input from a 544 patient selection list. 545 """ 546 if not self.__attached: 547 return (0, _('request rejected, you are not attach()ed')) 548 if auth_cookie != self.__auth_cookie: 549 _log.error('non-authenticated load_patient_from_external_source()') 550 return (0, _('rejected load_patient_from_external_source(), not authenticated')) 551 if self.__pat.locked: 552 _log.error('patient is locked, cannot load from external source') 553 return (0, _('current patient is locked')) 554 self.__user_done = False 555 wx.CallAfter(self._load_patient_from_external_source) 556 self.__lock_after_load_cookie = str(random.random()) 557 return (1, self.__lock_after_load_cookie)
558 #-----------------------------------------------------------------
559 - def lock_loaded_patient(self, auth_cookie = None, lock_after_load_cookie = None):
560 if not self.__attached: 561 return (0, _('request rejected, you are not attach()ed')) 562 if auth_cookie != self.__auth_cookie: 563 _log.error('non-authenticated lock_load_patient()') 564 return (0, _('rejected lock_load_patient(), not authenticated')) 565 # FIXME: ask user what to do about wrong cookie 566 if lock_after_load_cookie != self.__lock_after_load_cookie: 567 _log.warning('patient lock-after-load request rejected due to wrong cookie [%s]' % lock_after_load_cookie) 568 return (0, 'patient lock-after-load request rejected, wrong cookie provided') 569 self.__pat.locked = True 570 self.__pat_lock_cookie = str(random.random()) 571 return (1, self.__pat_lock_cookie)
572 #-----------------------------------------------------------------
573 - def lock_into_patient(self, auth_cookie = None, search_params = None):
574 if not self.__attached: 575 return (0, _('request rejected, you are not attach()ed')) 576 if auth_cookie != self.__auth_cookie: 577 _log.error('non-authenticated lock_into_patient()') 578 return (0, _('rejected lock_into_patient(), not authenticated')) 579 if self.__pat.locked: 580 _log.error('patient is already locked') 581 return (0, _('already locked into a patient')) 582 searcher = gmPerson.cPatientSearcher_SQL() 583 if type(search_params) == types.DictType: 584 idents = searcher.get_identities(search_dict=search_params) 585 print "must use dto, not search_dict" 586 print xxxxxxxxxxxxxxxxx 587 else: 588 idents = searcher.get_identities(search_term=search_params) 589 if idents is None: 590 return (0, _('error searching for patient with [%s]/%s') % (search_term, search_dict)) 591 if len(idents) == 0: 592 return (0, _('no patient found for [%s]/%s') % (search_term, search_dict)) 593 # FIXME: let user select patient 594 if len(idents) > 1: 595 return (0, _('several matching patients found for [%s]/%s') % (search_term, search_dict)) 596 if not gmPatSearchWidgets.set_active_patient(patient = idents[0]): 597 return (0, _('cannot activate patient [%s] (%s/%s)') % (str(idents[0]), search_term, search_dict)) 598 self.__pat.locked = True 599 self.__pat_lock_cookie = str(random.random()) 600 return (1, self.__pat_lock_cookie)
601 #-----------------------------------------------------------------
602 - def unlock_patient(self, auth_cookie = None, unlock_cookie = None):
603 if not self.__attached: 604 return (0, _('request rejected, you are not attach()ed')) 605 if auth_cookie != self.__auth_cookie: 606 _log.error('non-authenticated unlock_patient()') 607 return (0, _('rejected unlock_patient, not authenticated')) 608 # we ain't locked anyways, so succeed 609 if not self.__pat.locked: 610 return (1, '') 611 # FIXME: ask user what to do about wrong cookie 612 if unlock_cookie != self.__pat_lock_cookie: 613 _log.warning('patient unlock request rejected due to wrong cookie [%s]' % unlock_cookie) 614 return (0, 'patient unlock request rejected, wrong cookie provided') 615 self.__pat.locked = False 616 return (1, '')
617 #-----------------------------------------------------------------
618 - def assume_staff_identity(self, auth_cookie = None, staff_name = "Dr.Jekyll", staff_creds = None):
619 if not self.__attached: 620 return 0 621 if auth_cookie != self.__auth_cookie: 622 _log.error('non-authenticated select_identity()') 623 return 0 624 return "cMacroPrimitives.assume_staff_identity() not implemented"
625 #-----------------------------------------------------------------
626 - def get_user_answer(self):
627 if not self.__user_done: 628 return (0, 'still waiting') 629 self.__user_done = False 630 return (1, self.__user_answer)
631 #----------------------------------------------------------------- 632 # internal API 633 #-----------------------------------------------------------------
634 - def _force_detach(self):
635 msg = _( 636 'Someone tries to forcibly break the existing\n' 637 'controlling connection. This may or may not\n' 638 'have legitimate reasons.\n\n' 639 'Do you want to allow breaking the connection ?' 640 ) 641 can_break_conn = gmGuiHelpers.gm_show_question ( 642 aMessage = msg, 643 aTitle = _('forced detach attempt') 644 ) 645 if can_break_conn: 646 self.__user_answer = 1 647 else: 648 self.__user_answer = 0 649 self.__user_done = True 650 if can_break_conn: 651 self.__pat.locked = False 652 self.__attached = 0 653 return 1
654 #-----------------------------------------------------------------
655 - def _shutdown_gnumed(self, forced=False):
656 top_win = wx.GetApp().GetTopWindow() 657 if forced: 658 top_win.Destroy() 659 else: 660 top_win.Close()
661 #-----------------------------------------------------------------
663 patient = gmPatSearchWidgets.get_person_from_external_sources(search_immediately = True, activate_immediately = True) 664 if patient is not None: 665 self.__user_answer = 1 666 else: 667 self.__user_answer = 0 668 self.__user_done = True 669 return 1
670 #===================================================================== 671 # main 672 #===================================================================== 673 if __name__ == '__main__': 674 675 if len(sys.argv) < 2: 676 sys.exit() 677 678 if sys.argv[1] != 'test': 679 sys.exit() 680 681 gmI18N.activate_locale() 682 gmI18N.install_domain() 683 684 #--------------------------------------------------------
685 - def test_placeholders():
686 handler = gmPlaceholderHandler() 687 handler.debug = True 688 689 for placeholder in ['a', 'b']: 690 print handler[placeholder] 691 692 pat = gmPerson.ask_for_patient() 693 if pat is None: 694 return 695 696 gmPatSearchWidgets.set_active_patient(patient = pat) 697 698 print 'DOB (YYYY-MM-DD):', handler['date_of_birth::%Y-%m-%d'] 699 700 app = wx.PyWidgetTester(size = (200, 50)) 701 for placeholder in known_placeholders: 702 print placeholder, "=", handler[placeholder] 703 704 ph = 'progress_notes::ap' 705 print '%s: %s' % (ph, handler[ph])
706 #--------------------------------------------------------
707 - def test_new_variant_placeholders():
708 709 tests = [ 710 # should work: 711 '$<lastname>$', 712 '$<lastname::::3>$', 713 '$<name::%(title)s %(firstnames)s%(preferred)s%(lastnames)s>$', 714 715 # should fail: 716 'lastname', 717 '$<lastname', 718 '$<lastname::', 719 '$<lastname::>$', 720 '$<lastname::abc>$', 721 '$<lastname::abc::>$', 722 '$<lastname::abc::3>$', 723 '$<lastname::abc::xyz>$', 724 '$<lastname::::>$', 725 '$<lastname::::xyz>$', 726 727 '$<date_of_birth::%Y-%m-%d>$', 728 '$<date_of_birth::%Y-%m-%d::3>$', 729 '$<date_of_birth::%Y-%m-%d::>$', 730 731 # should work: 732 '$<adr_location::home::35>$', 733 '$<gender_mapper::male//female//other::5>$', 734 '$<current_meds::==> %(brand)s %(preparation)s (%(substance)s) <==\n::50>$', 735 '$<allergy_list::%(descriptor)s, >$', 736 '$<current_meds_table::latex//by-brand>$' 737 738 # 'firstname', 739 # 'title', 740 # 'date_of_birth', 741 # 'progress_notes', 742 # 'soap', 743 # 'soap_s', 744 # 'soap_o', 745 # 'soap_a', 746 # 'soap_p', 747 748 # 'soap', 749 # 'progress_notes', 750 # 'date_of_birth' 751 ] 752 753 pat = gmPerson.ask_for_patient() 754 if pat is None: 755 return 756 757 gmPatSearchWidgets.set_active_patient(patient = pat) 758 759 handler = gmPlaceholderHandler() 760 handler.debug = True 761 762 for placeholder in tests: 763 print placeholder, "=>", handler[placeholder] 764 print "--------------" 765 raw_input()
766 767 # print 'DOB (YYYY-MM-DD):', handler['date_of_birth::%Y-%m-%d'] 768 769 # app = wx.PyWidgetTester(size = (200, 50)) 770 # for placeholder in known_placeholders: 771 # print placeholder, "=", handler[placeholder] 772 773 # ph = 'progress_notes::ap' 774 # print '%s: %s' % (ph, handler[ph]) 775 776 #--------------------------------------------------------
777 - def test_scripting():
778 from Gnumed.pycommon import gmScriptingListener 779 import xmlrpclib 780 listener = gmScriptingListener.cScriptingListener(macro_executor = cMacroPrimitives(personality='unit test'), port=9999) 781 782 s = xmlrpclib.ServerProxy('http://localhost:9999') 783 print "should fail:", s.attach() 784 print "should fail:", s.attach('wrong cookie') 785 print "should work:", s.version() 786 print "should fail:", s.raise_gnumed() 787 print "should fail:", s.raise_notebook_plugin('test plugin') 788 print "should fail:", s.lock_into_patient('kirk, james') 789 print "should fail:", s.unlock_patient() 790 status, conn_auth = s.attach('unit test') 791 print "should work:", status, conn_auth 792 print "should work:", s.version() 793 print "should work:", s.raise_gnumed(conn_auth) 794 status, pat_auth = s.lock_into_patient(conn_auth, 'kirk, james') 795 print "should work:", status, pat_auth 796 print "should fail:", s.unlock_patient(conn_auth, 'bogus patient unlock cookie') 797 print "should work", s.unlock_patient(conn_auth, pat_auth) 798 data = {'firstname': 'jame', 'lastnames': 'Kirk', 'gender': 'm'} 799 status, pat_auth = s.lock_into_patient(conn_auth, data) 800 print "should work:", status, pat_auth 801 print "should work", s.unlock_patient(conn_auth, pat_auth) 802 print s.detach('bogus detach cookie') 803 print s.detach(conn_auth) 804 del s 805 806 listener.shutdown()
807 #--------------------------------------------------------
808 - def test_placeholder_regex():
809 810 import re as regex 811 812 tests = [ 813 ' $<lastname>$ ', 814 ' $<lastname::::3>$ ', 815 816 # should fail: 817 '$<date_of_birth::%Y-%m-%d>$', 818 '$<date_of_birth::%Y-%m-%d::3>$', 819 '$<date_of_birth::%Y-%m-%d::>$', 820 821 '$<adr_location::home::35>$', 822 '$<gender_mapper::male//female//other::5>$', 823 '$<current_meds::==> %(brand)s %(preparation)s (%(substance)s) <==\\n::50>$', 824 '$<allergy_list::%(descriptor)s, >$', 825 826 '\\noindent Patient: $<lastname>$, $<firstname>$', 827 '$<allergies::%(descriptor)s & %(l10n_type)s & {\\footnotesize %(reaction)s} \tabularnewline \hline >$', 828 '$<current_meds:: \item[%(substance)s] {\\footnotesize (%(brand)s)} %(preparation)s %(strength)s: %(schedule)s >$' 829 ] 830 831 tests = [ 832 833 'junk $<lastname::::3>$ junk', 834 'junk $<lastname::abc::3>$ junk', 835 'junk $<lastname::abc>$ junk', 836 'junk $<lastname>$ junk', 837 838 'junk $<lastname>$ junk $<firstname>$ junk', 839 'junk $<lastname::abc>$ junk $<fiststname::abc>$ junk', 840 'junk $<lastname::abc::3>$ junk $<firstname::abc::3>$ junk', 841 'junk $<lastname::::3>$ junk $<firstname::::3>$ junk' 842 843 ] 844 845 print "testing placeholder regex:", default_placeholder_regex 846 print "" 847 848 for t in tests: 849 print 'line: "%s"' % t 850 print "placeholders:" 851 for p in regex.findall(default_placeholder_regex, t, regex.IGNORECASE): 852 print ' => "%s"' % p 853 print " "
854 #-------------------------------------------------------- 855 856 #test_placeholders() 857 test_new_variant_placeholders() 858 #test_scripting() 859 #test_placeholder_regex() 860 861 #===================================================================== 862