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 251 if allg_state['last_confirmed'] is None: 252 date_confirmed = u'' 253 else: 254 date_confirmed = u' (%s)' % allg_state['last_confirmed'].strftime('%Y %B %d').decode(gmI18N.get_encoding()) 255 256 tmp = u'%s%s' % ( 257 allg_state.state_string, 258 date_confirmed 259 ) 260 return tmp
261 #-------------------------------------------------------- 262 # property definitions for static placeholders 263 #-------------------------------------------------------- 264 placeholder_regex = property(lambda x: default_placeholder_regex, _setter_noop) 265 266 # placeholders 267 lastname = property(_get_lastname, _setter_noop) 268 firstname = property(_get_firstname, _setter_noop) 269 title = property(_get_title, _setter_noop) 270 date_of_birth = property(_get_dob, _setter_noop) 271 272 progress_notes = property(_get_progress_notes, _setter_noop) 273 soap = property(_get_progress_notes, _setter_noop) 274 soap_s = property(_get_soap_s, _setter_noop) 275 soap_o = property(_get_soap_o, _setter_noop) 276 soap_a = property(_get_soap_a, _setter_noop) 277 soap_p = property(_get_soap_p, _setter_noop) 278 soap_admin = property(_get_soap_admin, _setter_noop) 279 280 allergy_state = property(_get_allergy_state, _setter_noop) 281 282 client_version = property(_get_client_version, _setter_noop) 283 284 current_provider = property(_get_current_provider, _setter_noop) 285 #-------------------------------------------------------- 286 # variant handlers 287 #--------------------------------------------------------
288 - def _get_variant_progress_notes(self, data=None):
289 return self._get_variant_soap(data=data)
290 #--------------------------------------------------------
291 - def _get_variant_soap(self, data=None):
292 if data is None: 293 cats = list(data) 294 template = u'%s' 295 else: 296 parts = data.split('//', 2) 297 if len(parts) == 1: 298 cats = list(parts) 299 template = u'%s' 300 else: 301 cats = list(parts[0]) 302 template = parts[1] 303 304 narr = gmNarrativeWidgets.select_narrative_from_episodes(soap_cats = cats) 305 306 if len(narr) == 0: 307 return u'' 308 309 narr = [ template % n['narrative'] for n in narr ] 310 311 return u'\n'.join(narr)
312 #--------------------------------------------------------
313 - def _get_variant_name(self, data=None):
314 if data is None: 315 return [_('template is missing')] 316 317 name = self.pat.get_active_name() 318 319 parts = { 320 'title': gmTools.coalesce(name['title'], u''), 321 'firstnames': name['firstnames'], 322 'lastnames': name['lastnames'], 323 'preferred': gmTools.coalesce ( 324 initial = name['preferred'], 325 instead = u' ', 326 template_initial = u' "%s" ' 327 ) 328 } 329 330 return data % parts
331 #--------------------------------------------------------
332 - def _get_variant_date_of_birth(self, data='%x'):
333 return self.pat.get_formatted_dob(format = str(data), encoding = gmI18N.get_encoding())
334 #-------------------------------------------------------- 335 # FIXME: extend to all supported genders
336 - def _get_variant_gender_mapper(self, data='male//female//other'):
337 values = data.split('//', 2) 338 339 if len(values) == 2: 340 male_value, female_value = values 341 other_value = u'<unkown gender>' 342 elif len(values) == 3: 343 male_value, female_value, other_value = values 344 else: 345 return _('invalid gender mapping layout: [%s]') % data 346 347 if self.pat['gender'] == u'm': 348 return male_value 349 350 if self.pat['gender'] == u'f': 351 return female_value 352 353 return other_value
354 #--------------------------------------------------------
355 - def _get_variant_adr_street(self, data=u'?'):
356 # if data == u'?': 357 # types = xxxxxxxxxxx 358 adrs = self.pat.get_addresses(address_type=data) 359 if len(adrs) == 0: 360 return _('no street for address type [%s]') % data 361 return adrs[0]['street']
362 #--------------------------------------------------------
363 - def _get_variant_adr_number(self, data=u'?'):
364 adrs = self.pat.get_addresses(address_type=data) 365 if len(adrs) == 0: 366 return _('no number for address type [%s]') % data 367 return adrs[0]['number']
368 #--------------------------------------------------------
369 - def _get_variant_adr_location(self, data=u'?'):
370 adrs = self.pat.get_addresses(address_type=data) 371 if len(adrs) == 0: 372 return _('no location for address type [%s]') % data 373 return adrs[0]['urb']
374 #--------------------------------------------------------
375 - def _get_variant_adr_postcode(self, data=u'?'):
376 adrs = self.pat.get_addresses(address_type=data) 377 if len(adrs) == 0: 378 return _('no postcode for address type [%s]') % data 379 return adrs[0]['postcode']
380 #--------------------------------------------------------
381 - def _get_variant_allergy_list(self, data=None):
382 if data is None: 383 return [_('template is missing')] 384 385 template, separator = data.split('//', 2) 386 387 emr = self.pat.get_emr() 388 return separator.join([ template % a for a in emr.get_allergies() ])
389 #--------------------------------------------------------
390 - def _get_variant_allergies(self, data=None):
391 392 if data is None: 393 return [_('template is missing')] 394 395 emr = self.pat.get_emr() 396 return u'\n'.join([ data % a for a in emr.get_allergies() ])
397 #--------------------------------------------------------
398 - def _get_variant_current_meds(self, data=None):
399 400 if data is None: 401 return [_('template is missing')] 402 403 emr = self.pat.get_emr() 404 current_meds = emr.get_current_substance_intake ( 405 include_inactive = False, 406 include_unapproved = False, 407 order_by = u'brand, substance' 408 ) 409 410 # FIXME: we should be dealing with translating None to u'' here 411 412 return u'\n'.join([ data % m for m in current_meds ])
413 #--------------------------------------------------------
414 - def _get_variant_current_meds_table(self, data=None):
415 416 options = data.split('//') 417 418 if u'latex' in options: 419 return gmMedication.format_substance_intake ( 420 emr = self.pat.get_emr(), 421 output_format = u'latex', 422 table_type = u'by-brand' 423 ) 424 425 _log.error('no known current medications table formatting style in [%]', data) 426 return _('unknown current medication table formatting style')
427 #--------------------------------------------------------
428 - def _get_variant_lab_table(self, data=None):
429 430 options = data.split('//') 431 432 emr = self.pat.get_emr() 433 434 if u'latex' in options: 435 return gmPathLab.format_test_results ( 436 results = emr.get_test_results_by_date(), 437 output_format = u'latex' 438 ) 439 440 _log.error('no known test results table formatting style in [%s]', data) 441 return _('unknown test results table formatting style [%s]') % data
442 #--------------------------------------------------------
443 - def _get_variant_problems(self, data=None):
444 445 if data is None: 446 return [_('template is missing')] 447 448 probs = self.pat.get_emr().get_problems() 449 450 return u'\n'.join([ data % p for p in probs ])
451 #--------------------------------------------------------
452 - def _get_variant_today(self, data='%x'):
454 #--------------------------------------------------------
455 - def _get_variant_tex_escape(self, data=None):
456 return gmTools.tex_escape_string(text = data)
457 #-------------------------------------------------------- 458 # internal helpers 459 #-------------------------------------------------------- 460 461 #=====================================================================
462 -class cMacroPrimitives:
463 """Functions a macro can legally use. 464 465 An instance of this class is passed to the GNUmed scripting 466 listener. Hence, all actions a macro can legally take must 467 be defined in this class. Thus we achieve some screening for 468 security and also thread safety handling. 469 """ 470 #-----------------------------------------------------------------
471 - def __init__(self, personality = None):
472 if personality is None: 473 raise gmExceptions.ConstructorError, 'must specify personality' 474 self.__personality = personality 475 self.__attached = 0 476 self._get_source_personality = None 477 self.__user_done = False 478 self.__user_answer = 'no answer yet' 479 self.__pat = gmPerson.gmCurrentPatient() 480 481 self.__auth_cookie = str(random.random()) 482 self.__pat_lock_cookie = str(random.random()) 483 self.__lock_after_load_cookie = str(random.random()) 484 485 _log.info('slave mode personality is [%s]', personality)
486 #----------------------------------------------------------------- 487 # public API 488 #-----------------------------------------------------------------
489 - def attach(self, personality = None):
490 if self.__attached: 491 _log.error('attach with [%s] rejected, already serving a client', personality) 492 return (0, _('attach rejected, already serving a client')) 493 if personality != self.__personality: 494 _log.error('rejecting attach to personality [%s], only servicing [%s]' % (personality, self.__personality)) 495 return (0, _('attach to personality [%s] rejected') % personality) 496 self.__attached = 1 497 self.__auth_cookie = str(random.random()) 498 return (1, self.__auth_cookie)
499 #-----------------------------------------------------------------
500 - def detach(self, auth_cookie=None):
501 if not self.__attached: 502 return 1 503 if auth_cookie != self.__auth_cookie: 504 _log.error('rejecting detach() with cookie [%s]' % auth_cookie) 505 return 0 506 self.__attached = 0 507 return 1
508 #-----------------------------------------------------------------
509 - def force_detach(self):
510 if not self.__attached: 511 return 1 512 self.__user_done = False 513 # FIXME: use self.__sync_cookie for syncing with user interaction 514 wx.CallAfter(self._force_detach) 515 return 1
516 #-----------------------------------------------------------------
517 - def version(self):
518 ver = _cfg.get(option = u'client_version') 519 return "GNUmed %s, %s $Revision: 1.51 $" % (ver, self.__class__.__name__)
520 #-----------------------------------------------------------------
521 - def shutdown_gnumed(self, auth_cookie=None, forced=False):
522 """Shuts down this client instance.""" 523 if not self.__attached: 524 return 0 525 if auth_cookie != self.__auth_cookie: 526 _log.error('non-authenticated shutdown_gnumed()') 527 return 0 528 wx.CallAfter(self._shutdown_gnumed, forced) 529 return 1
530 #-----------------------------------------------------------------
531 - def raise_gnumed(self, auth_cookie = None):
532 """Raise ourselves to the top of the desktop.""" 533 if not self.__attached: 534 return 0 535 if auth_cookie != self.__auth_cookie: 536 _log.error('non-authenticated raise_gnumed()') 537 return 0 538 return "cMacroPrimitives.raise_gnumed() not implemented"
539 #-----------------------------------------------------------------
540 - def get_loaded_plugins(self, auth_cookie = None):
541 if not self.__attached: 542 return 0 543 if auth_cookie != self.__auth_cookie: 544 _log.error('non-authenticated get_loaded_plugins()') 545 return 0 546 gb = gmGuiBroker.GuiBroker() 547 return gb['horstspace.notebook.gui'].keys()
548 #-----------------------------------------------------------------
549 - def raise_notebook_plugin(self, auth_cookie = None, a_plugin = None):
550 """Raise a notebook plugin within GNUmed.""" 551 if not self.__attached: 552 return 0 553 if auth_cookie != self.__auth_cookie: 554 _log.error('non-authenticated raise_notebook_plugin()') 555 return 0 556 # FIXME: use semaphore 557 wx.CallAfter(gmPlugin.raise_notebook_plugin, a_plugin) 558 return 1
559 #-----------------------------------------------------------------
560 - def load_patient_from_external_source(self, auth_cookie = None):
561 """Load external patient, perhaps create it. 562 563 Callers must use get_user_answer() to get status information. 564 It is unsafe to proceed without knowing the completion state as 565 the controlled client may be waiting for user input from a 566 patient selection list. 567 """ 568 if not self.__attached: 569 return (0, _('request rejected, you are not attach()ed')) 570 if auth_cookie != self.__auth_cookie: 571 _log.error('non-authenticated load_patient_from_external_source()') 572 return (0, _('rejected load_patient_from_external_source(), not authenticated')) 573 if self.__pat.locked: 574 _log.error('patient is locked, cannot load from external source') 575 return (0, _('current patient is locked')) 576 self.__user_done = False 577 wx.CallAfter(self._load_patient_from_external_source) 578 self.__lock_after_load_cookie = str(random.random()) 579 return (1, self.__lock_after_load_cookie)
580 #-----------------------------------------------------------------
581 - def lock_loaded_patient(self, auth_cookie = None, lock_after_load_cookie = None):
582 if not self.__attached: 583 return (0, _('request rejected, you are not attach()ed')) 584 if auth_cookie != self.__auth_cookie: 585 _log.error('non-authenticated lock_load_patient()') 586 return (0, _('rejected lock_load_patient(), not authenticated')) 587 # FIXME: ask user what to do about wrong cookie 588 if lock_after_load_cookie != self.__lock_after_load_cookie: 589 _log.warning('patient lock-after-load request rejected due to wrong cookie [%s]' % lock_after_load_cookie) 590 return (0, 'patient lock-after-load request rejected, wrong cookie provided') 591 self.__pat.locked = True 592 self.__pat_lock_cookie = str(random.random()) 593 return (1, self.__pat_lock_cookie)
594 #-----------------------------------------------------------------
595 - def lock_into_patient(self, auth_cookie = None, search_params = None):
596 if not self.__attached: 597 return (0, _('request rejected, you are not attach()ed')) 598 if auth_cookie != self.__auth_cookie: 599 _log.error('non-authenticated lock_into_patient()') 600 return (0, _('rejected lock_into_patient(), not authenticated')) 601 if self.__pat.locked: 602 _log.error('patient is already locked') 603 return (0, _('already locked into a patient')) 604 searcher = gmPerson.cPatientSearcher_SQL() 605 if type(search_params) == types.DictType: 606 idents = searcher.get_identities(search_dict=search_params) 607 print "must use dto, not search_dict" 608 print xxxxxxxxxxxxxxxxx 609 else: 610 idents = searcher.get_identities(search_term=search_params) 611 if idents is None: 612 return (0, _('error searching for patient with [%s]/%s') % (search_term, search_dict)) 613 if len(idents) == 0: 614 return (0, _('no patient found for [%s]/%s') % (search_term, search_dict)) 615 # FIXME: let user select patient 616 if len(idents) > 1: 617 return (0, _('several matching patients found for [%s]/%s') % (search_term, search_dict)) 618 if not gmPatSearchWidgets.set_active_patient(patient = idents[0]): 619 return (0, _('cannot activate patient [%s] (%s/%s)') % (str(idents[0]), search_term, search_dict)) 620 self.__pat.locked = True 621 self.__pat_lock_cookie = str(random.random()) 622 return (1, self.__pat_lock_cookie)
623 #-----------------------------------------------------------------
624 - def unlock_patient(self, auth_cookie = None, unlock_cookie = None):
625 if not self.__attached: 626 return (0, _('request rejected, you are not attach()ed')) 627 if auth_cookie != self.__auth_cookie: 628 _log.error('non-authenticated unlock_patient()') 629 return (0, _('rejected unlock_patient, not authenticated')) 630 # we ain't locked anyways, so succeed 631 if not self.__pat.locked: 632 return (1, '') 633 # FIXME: ask user what to do about wrong cookie 634 if unlock_cookie != self.__pat_lock_cookie: 635 _log.warning('patient unlock request rejected due to wrong cookie [%s]' % unlock_cookie) 636 return (0, 'patient unlock request rejected, wrong cookie provided') 637 self.__pat.locked = False 638 return (1, '')
639 #-----------------------------------------------------------------
640 - def assume_staff_identity(self, auth_cookie = None, staff_name = "Dr.Jekyll", staff_creds = None):
641 if not self.__attached: 642 return 0 643 if auth_cookie != self.__auth_cookie: 644 _log.error('non-authenticated select_identity()') 645 return 0 646 return "cMacroPrimitives.assume_staff_identity() not implemented"
647 #-----------------------------------------------------------------
648 - def get_user_answer(self):
649 if not self.__user_done: 650 return (0, 'still waiting') 651 self.__user_done = False 652 return (1, self.__user_answer)
653 #----------------------------------------------------------------- 654 # internal API 655 #-----------------------------------------------------------------
656 - def _force_detach(self):
657 msg = _( 658 'Someone tries to forcibly break the existing\n' 659 'controlling connection. This may or may not\n' 660 'have legitimate reasons.\n\n' 661 'Do you want to allow breaking the connection ?' 662 ) 663 can_break_conn = gmGuiHelpers.gm_show_question ( 664 aMessage = msg, 665 aTitle = _('forced detach attempt') 666 ) 667 if can_break_conn: 668 self.__user_answer = 1 669 else: 670 self.__user_answer = 0 671 self.__user_done = True 672 if can_break_conn: 673 self.__pat.locked = False 674 self.__attached = 0 675 return 1
676 #-----------------------------------------------------------------
677 - def _shutdown_gnumed(self, forced=False):
678 top_win = wx.GetApp().GetTopWindow() 679 if forced: 680 top_win.Destroy() 681 else: 682 top_win.Close()
683 #-----------------------------------------------------------------
685 patient = gmPatSearchWidgets.get_person_from_external_sources(search_immediately = True, activate_immediately = True) 686 if patient is not None: 687 self.__user_answer = 1 688 else: 689 self.__user_answer = 0 690 self.__user_done = True 691 return 1
692 #===================================================================== 693 # main 694 #===================================================================== 695 if __name__ == '__main__': 696 697 if len(sys.argv) < 2: 698 sys.exit() 699 700 if sys.argv[1] != 'test': 701 sys.exit() 702 703 gmI18N.activate_locale() 704 gmI18N.install_domain() 705 706 #--------------------------------------------------------
707 - def test_placeholders():
708 handler = gmPlaceholderHandler() 709 handler.debug = True 710 711 for placeholder in ['a', 'b']: 712 print handler[placeholder] 713 714 pat = gmPerson.ask_for_patient() 715 if pat is None: 716 return 717 718 gmPatSearchWidgets.set_active_patient(patient = pat) 719 720 print 'DOB (YYYY-MM-DD):', handler['date_of_birth::%Y-%m-%d'] 721 722 app = wx.PyWidgetTester(size = (200, 50)) 723 for placeholder in known_placeholders: 724 print placeholder, "=", handler[placeholder] 725 726 ph = 'progress_notes::ap' 727 print '%s: %s' % (ph, handler[ph])
728 #--------------------------------------------------------
729 - def test_new_variant_placeholders():
730 731 tests = [ 732 # should work: 733 '$<lastname>$', 734 '$<lastname::::3>$', 735 '$<name::%(title)s %(firstnames)s%(preferred)s%(lastnames)s>$', 736 737 # should fail: 738 'lastname', 739 '$<lastname', 740 '$<lastname::', 741 '$<lastname::>$', 742 '$<lastname::abc>$', 743 '$<lastname::abc::>$', 744 '$<lastname::abc::3>$', 745 '$<lastname::abc::xyz>$', 746 '$<lastname::::>$', 747 '$<lastname::::xyz>$', 748 749 '$<date_of_birth::%Y-%m-%d>$', 750 '$<date_of_birth::%Y-%m-%d::3>$', 751 '$<date_of_birth::%Y-%m-%d::>$', 752 753 # should work: 754 '$<adr_location::home::35>$', 755 '$<gender_mapper::male//female//other::5>$', 756 '$<current_meds::==> %(brand)s %(preparation)s (%(substance)s) <==\n::50>$', 757 '$<allergy_list::%(descriptor)s, >$', 758 '$<current_meds_table::latex//by-brand>$' 759 760 # 'firstname', 761 # 'title', 762 # 'date_of_birth', 763 # 'progress_notes', 764 # 'soap', 765 # 'soap_s', 766 # 'soap_o', 767 # 'soap_a', 768 # 'soap_p', 769 770 # 'soap', 771 # 'progress_notes', 772 # 'date_of_birth' 773 ] 774 775 pat = gmPerson.ask_for_patient() 776 if pat is None: 777 return 778 779 gmPatSearchWidgets.set_active_patient(patient = pat) 780 781 handler = gmPlaceholderHandler() 782 handler.debug = True 783 784 for placeholder in tests: 785 print placeholder, "=>", handler[placeholder] 786 print "--------------" 787 raw_input()
788 789 # print 'DOB (YYYY-MM-DD):', handler['date_of_birth::%Y-%m-%d'] 790 791 # app = wx.PyWidgetTester(size = (200, 50)) 792 # for placeholder in known_placeholders: 793 # print placeholder, "=", handler[placeholder] 794 795 # ph = 'progress_notes::ap' 796 # print '%s: %s' % (ph, handler[ph]) 797 798 #--------------------------------------------------------
799 - def test_scripting():
800 from Gnumed.pycommon import gmScriptingListener 801 import xmlrpclib 802 listener = gmScriptingListener.cScriptingListener(macro_executor = cMacroPrimitives(personality='unit test'), port=9999) 803 804 s = xmlrpclib.ServerProxy('http://localhost:9999') 805 print "should fail:", s.attach() 806 print "should fail:", s.attach('wrong cookie') 807 print "should work:", s.version() 808 print "should fail:", s.raise_gnumed() 809 print "should fail:", s.raise_notebook_plugin('test plugin') 810 print "should fail:", s.lock_into_patient('kirk, james') 811 print "should fail:", s.unlock_patient() 812 status, conn_auth = s.attach('unit test') 813 print "should work:", status, conn_auth 814 print "should work:", s.version() 815 print "should work:", s.raise_gnumed(conn_auth) 816 status, pat_auth = s.lock_into_patient(conn_auth, 'kirk, james') 817 print "should work:", status, pat_auth 818 print "should fail:", s.unlock_patient(conn_auth, 'bogus patient unlock cookie') 819 print "should work", s.unlock_patient(conn_auth, pat_auth) 820 data = {'firstname': 'jame', 'lastnames': 'Kirk', 'gender': 'm'} 821 status, pat_auth = s.lock_into_patient(conn_auth, data) 822 print "should work:", status, pat_auth 823 print "should work", s.unlock_patient(conn_auth, pat_auth) 824 print s.detach('bogus detach cookie') 825 print s.detach(conn_auth) 826 del s 827 828 listener.shutdown()
829 #--------------------------------------------------------
830 - def test_placeholder_regex():
831 832 import re as regex 833 834 tests = [ 835 ' $<lastname>$ ', 836 ' $<lastname::::3>$ ', 837 838 # should fail: 839 '$<date_of_birth::%Y-%m-%d>$', 840 '$<date_of_birth::%Y-%m-%d::3>$', 841 '$<date_of_birth::%Y-%m-%d::>$', 842 843 '$<adr_location::home::35>$', 844 '$<gender_mapper::male//female//other::5>$', 845 '$<current_meds::==> %(brand)s %(preparation)s (%(substance)s) <==\\n::50>$', 846 '$<allergy_list::%(descriptor)s, >$', 847 848 '\\noindent Patient: $<lastname>$, $<firstname>$', 849 '$<allergies::%(descriptor)s & %(l10n_type)s & {\\footnotesize %(reaction)s} \tabularnewline \hline >$', 850 '$<current_meds:: \item[%(substance)s] {\\footnotesize (%(brand)s)} %(preparation)s %(strength)s: %(schedule)s >$' 851 ] 852 853 tests = [ 854 855 'junk $<lastname::::3>$ junk', 856 'junk $<lastname::abc::3>$ junk', 857 'junk $<lastname::abc>$ junk', 858 'junk $<lastname>$ junk', 859 860 'junk $<lastname>$ junk $<firstname>$ junk', 861 'junk $<lastname::abc>$ junk $<fiststname::abc>$ junk', 862 'junk $<lastname::abc::3>$ junk $<firstname::abc::3>$ junk', 863 'junk $<lastname::::3>$ junk $<firstname::::3>$ junk' 864 865 ] 866 867 print "testing placeholder regex:", default_placeholder_regex 868 print "" 869 870 for t in tests: 871 print 'line: "%s"' % t 872 print "placeholders:" 873 for p in regex.findall(default_placeholder_regex, t, regex.IGNORECASE): 874 print ' => "%s"' % p 875 print " "
876 #-------------------------------------------------------- 877 878 #test_placeholders() 879 test_new_variant_placeholders() 880 #test_scripting() 881 #test_placeholder_regex() 882 883 #===================================================================== 884