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