Package Gnumed :: Package business :: Module gmPathLab
[frames] | no frames]

Source Code for Module Gnumed.business.gmPathLab

   1  """GNUmed measurements related business objects.""" 
   2  #============================================================ 
   3  __version__ = "$Revision: 1.81 $" 
   4  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>" 
   5  __license__ = "GPL" 
   6   
   7   
   8  import types, sys, logging, codecs, decimal 
   9   
  10  if __name__ == '__main__': 
  11          sys.path.insert(0, '../../') 
  12   
  13  from Gnumed.pycommon import gmDateTime 
  14  if __name__ == '__main__': 
  15          from Gnumed.pycommon import gmLog2 
  16          from Gnumed.pycommon import gmI18N 
  17          gmDateTime.init() 
  18  from Gnumed.pycommon import gmExceptions 
  19  from Gnumed.pycommon import gmBusinessDBObject 
  20  from Gnumed.pycommon import gmPG2 
  21  from Gnumed.pycommon import gmTools 
  22  from Gnumed.pycommon import gmDispatcher 
  23  from Gnumed.pycommon import gmHooks 
  24  from Gnumed.business import gmOrganization 
  25   
  26   
  27  _log = logging.getLogger('gm.lab') 
  28  _log.info(__version__) 
  29   
  30  # FIXME: use UCUM from Regenstrief Institute 
  31   
  32  #============================================================ 
33 -def _on_test_result_modified():
34 """Always relates to the active patient.""" 35 gmHooks.run_hook_script(hook = u'after_test_result_modified')
36 37 gmDispatcher.connect(_on_test_result_modified, u'test_result_mod_db') 38 39 #============================================================
40 -class cTestOrg(gmBusinessDBObject.cBusinessDBObject):
41 """Represents one test org/lab.""" 42 _cmd_fetch_payload = u"""SELECT * FROM clin.v_test_orgs WHERE pk_test_org = %s""" 43 _cmds_store_payload = [ 44 u"""UPDATE clin.test_org SET 45 fk_org_unit = %(pk_org_unit)s, 46 contact = gm.nullify_empty_string(%(test_org_contact)s), 47 comment = gm.nullify_empty_string(%(comment)s) 48 WHERE 49 pk = %(pk_test_org)s 50 AND 51 xmin = %(xmin_test_org)s 52 RETURNING 53 xmin AS xmin_test_org 54 """ 55 ] 56 _updatable_fields = [ 57 u'pk_org_unit', 58 u'test_org_contact', 59 u'comment' 60 ]
61 #------------------------------------------------------------
62 -def create_test_org(name=None, comment=None, pk_org_unit=None):
63 64 if name is None: 65 name = _('inhouse lab') 66 comment = _('auto-generated') 67 68 # get org unit 69 if pk_org_unit is None: 70 org = gmOrganization.org_exists(organization = name) 71 if org is None: 72 org = gmOrganization.create_org ( 73 organization = name, 74 category = u'Laboratory' 75 ) 76 org_unit = gmOrganization.create_org_unit ( 77 pk_organization = org['pk_org'], 78 unit = name 79 ) 80 pk_org_unit = org_unit['pk_org_unit'] 81 82 # test org exists ? 83 args = {'pk_unit': pk_org_unit} 84 cmd = u'SELECT pk_test_org FROM clin.v_test_orgs WHERE pk_org_unit = %(pk_unit)s' 85 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 86 87 if len(rows) == 0: 88 cmd = u'INSERT INTO clin.test_org (fk_org_unit) VALUES (%(pk_unit)s) RETURNING pk' 89 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 90 91 test_org = cTestOrg(aPK_obj = rows[0][0]) 92 if comment is not None: 93 comment = comment.strip() 94 test_org['comment'] = comment 95 test_org.save() 96 97 return test_org
98 #------------------------------------------------------------
99 -def delete_test_org(test_org=None):
100 args = {'pk': test_org} 101 cmd = u""" 102 DELETE FROM clin.test_org 103 WHERE 104 pk = %(pk)s 105 AND 106 NOT EXISTS (SELECT 1 FROM clin.lab_request WHERE fk_test_org = %(pk)s LIMIT 1) 107 AND 108 NOT EXISTS (SELECT 1 FROM clin.test_type WHERE fk_test_org = %(pk)s LIMIT 1) 109 """ 110 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
111 #------------------------------------------------------------
112 -def get_test_orgs(order_by=u'unit'):
113 cmd = u'SELECT * FROM clin.v_test_orgs ORDER BY %s' % order_by 114 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 115 return [ cTestOrg(row = {'pk_field': 'pk_test_org', 'data': r, 'idx': idx}) for r in rows ]
116 #============================================================
117 -class cMetaTestType(gmBusinessDBObject.cBusinessDBObject):
118 """Represents one meta test type under which actual test types can be aggregated.""" 119 120 _cmd_fetch_payload = u"""select * from clin.meta_test_type where pk = %s""" 121 122 _cmds_store_payload = [] 123 124 _updatable_fields = []
125 #------------------------------------------------------------
126 -def delete_meta_type(meta_type=None):
127 cmd = u'delete from clin.meta_test_type where pk = %(pk)s' 128 args = {'pk': meta_type} 129 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
130 #------------------------------------------------------------
131 -def get_meta_test_types():
132 cmd = u'select * from clin.meta_test_type' 133 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 134 return [ cMetaTestType(row = {'pk_field': 'pk', 'data': r, 'idx': idx}) for r in rows ]
135 #============================================================
136 -class cUnifiedTestType(gmBusinessDBObject.cBusinessDBObject):
137 """Represents one unified test type.""" 138 139 # FIXME: if we ever want to write we need to include XMIN in the view 140 _cmd_fetch_payload = u"""select * from clin.v_unified_test_types where pk_test_type = %s""" 141 142 _cmds_store_payload = [] 143 144 _updatable_fields = [] 145 #--------------------------------------------------------
146 - def get_most_recent_result(self, pk_patient=None):
147 cmd = u""" 148 SELECT pk_test_result, clin_when 149 FROM clin.v_test_results 150 WHERE 151 pk_patient = %(pat)s 152 AND 153 pk_meta_test_type = %(pkmtt)s 154 ORDER BY clin_when DESC 155 LIMIT 1 156 """ 157 args = {'pat': pk_patient, 'pkmtt': self._payload[self._idx['pk_meta_test_type']]} 158 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 159 if len(rows) == 0: 160 return None 161 return cTestResult(aPK_obj = rows[0]['pk_test_result'])
162 #============================================================
163 -class cMeasurementType(gmBusinessDBObject.cBusinessDBObject):
164 """Represents one test result type.""" 165 166 _cmd_fetch_payload = u"""select * from clin.v_test_types where pk_test_type = %s""" 167 168 _cmds_store_payload = [ 169 u"""update clin.test_type set 170 abbrev = %(abbrev)s, 171 name = %(name)s, 172 loinc = gm.nullify_empty_string(%(loinc)s), 173 code = gm.nullify_empty_string(%(code)s), 174 coding_system = gm.nullify_empty_string(%(coding_system)s), 175 comment = gm.nullify_empty_string(%(comment_type)s), 176 conversion_unit = gm.nullify_empty_string(%(conversion_unit)s), 177 fk_test_org = %(pk_test_org)s 178 where pk = %(pk_test_type)s""", 179 u"""select xmin_test_type from clin.v_test_types where pk_test_type = %(pk_test_type)s""" 180 ] 181 182 _updatable_fields = [ 183 'abbrev', 184 'name', 185 'loinc', 186 'code', 187 'coding_system', 188 'comment_type', 189 'conversion_unit', 190 'pk_test_org' 191 ] 192 #-------------------------------------------------------- 193 # def __setitem__(self, attribute, value): 194 # 195 # # find fk_test_org from name 196 # if (attribute == 'fk_test_org') and (value is not None): 197 # try: 198 # int(value) 199 # except: 200 # cmd = u"select pk from clin.test_org where internal _name = %(val)s" 201 # rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'val': value}}]) 202 # if len(rows) == 0: 203 # raise ValueError('[%s]: no test org for [%s], cannot set <%s>' % (self.__class__.__name__, value, attribute)) 204 # value = rows[0][0] 205 # 206 # gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value) 207 #--------------------------------------------------------
208 - def _get_in_use(self):
209 cmd = u'select exists(select 1 from clin.test_result where fk_type = %(pk_type)s)' 210 args = {'pk_type': self._payload[self._idx['pk_test_type']]} 211 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 212 return rows[0][0]
213 214 in_use = property(_get_in_use, lambda x:x)
215 #------------------------------------------------------------
216 -def get_measurement_types(order_by=None):
217 cmd = u'select * from clin.v_test_types %s' % gmTools.coalesce(order_by, u'', u'order by %s') 218 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 219 return [ cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': r, 'idx': idx}) for r in rows ]
220 #------------------------------------------------------------
221 -def find_measurement_type(lab=None, abbrev=None, name=None):
222 223 if (abbrev is None) and (name is None): 224 raise ValueError('must have <abbrev> and/or <name> set') 225 226 where_snippets = [] 227 228 if lab is None: 229 where_snippets.append('pk_test_org IS NULL') 230 else: 231 try: 232 int(lab) 233 where_snippets.append('pk_test_org = %(lab)s') 234 except (TypeError, ValueError): 235 where_snippets.append('pk_test_org = (SELECT pk_test_org FROM clin.v_test_orgs WHERE unit = %(lab)s)') 236 237 if abbrev is not None: 238 where_snippets.append('abbrev = %(abbrev)s') 239 240 if name is not None: 241 where_snippets.append('name = %(name)s') 242 243 where_clause = u' and '.join(where_snippets) 244 cmd = u"select * from clin.v_test_types where %s" % where_clause 245 args = {'lab': lab, 'abbrev': abbrev, 'name': name} 246 247 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 248 249 if len(rows) == 0: 250 return None 251 252 tt = cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': rows[0], 'idx': idx}) 253 return tt
254 #------------------------------------------------------------
255 -def delete_measurement_type(measurement_type=None):
256 cmd = u'delete from clin.test_type where pk = %(pk)s' 257 args = {'pk': measurement_type} 258 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
259 #------------------------------------------------------------
260 -def create_measurement_type(lab=None, abbrev=None, unit=None, name=None):
261 """Create or get test type.""" 262 263 ttype = find_measurement_type(lab = lab, abbrev = abbrev, name = name) 264 # found ? 265 if ttype is not None: 266 return ttype 267 268 _log.debug('creating test type [%s:%s:%s:%s]', lab, abbrev, name, unit) 269 270 # not found, so create it 271 if unit is None: 272 _log.error('need <unit> to create test type: %s:%s:%s:%s' % (lab, abbrev, name, unit)) 273 raise ValueError('need <unit> to create test type') 274 275 # make query 276 cols = [] 277 val_snippets = [] 278 vals = {} 279 280 # lab 281 if lab is None: 282 lab = create_test_org()['pk_test_org'] 283 284 cols.append('fk_test_org') 285 try: 286 vals['lab'] = int(lab) 287 val_snippets.append('%(lab)s') 288 except: 289 vals['lab'] = lab 290 val_snippets.append('(SELECT pk_test_org FROM clin.v_test_orgs WHERE unit = %(lab)s)') 291 292 # code 293 cols.append('abbrev') 294 val_snippets.append('%(abbrev)s') 295 vals['abbrev'] = abbrev 296 297 # unit 298 cols.append('conversion_unit') 299 val_snippets.append('%(unit)s') 300 vals['unit'] = unit 301 302 # name 303 if name is not None: 304 cols.append('name') 305 val_snippets.append('%(name)s') 306 vals['name'] = name 307 308 col_clause = u', '.join(cols) 309 val_clause = u', '.join(val_snippets) 310 queries = [ 311 {'cmd': u'insert into clin.test_type (%s) values (%s)' % (col_clause, val_clause), 'args': vals}, 312 {'cmd': u"select * from clin.v_test_types where pk_test_type = currval(pg_get_serial_sequence('clin.test_type', 'pk'))"} 313 ] 314 rows, idx = gmPG2.run_rw_queries(queries = queries, get_col_idx = True, return_data = True) 315 ttype = cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': rows[0], 'idx': idx}) 316 317 return ttype
318 #============================================================
319 -class cTestResult(gmBusinessDBObject.cBusinessDBObject):
320 """Represents one test result.""" 321 322 _cmd_fetch_payload = u"select * from clin.v_test_results where pk_test_result = %s" 323 324 _cmds_store_payload = [ 325 u"""update clin.test_result set 326 clin_when = %(clin_when)s, 327 narrative = nullif(trim(%(comment)s), ''), 328 val_num = %(val_num)s, 329 val_alpha = nullif(trim(%(val_alpha)s), ''), 330 val_unit = nullif(trim(%(val_unit)s), ''), 331 val_normal_min = %(val_normal_min)s, 332 val_normal_max = %(val_normal_max)s, 333 val_normal_range = nullif(trim(%(val_normal_range)s), ''), 334 val_target_min = %(val_target_min)s, 335 val_target_max = %(val_target_max)s, 336 val_target_range = nullif(trim(%(val_target_range)s), ''), 337 abnormality_indicator = nullif(trim(%(abnormality_indicator)s), ''), 338 norm_ref_group = nullif(trim(%(norm_ref_group)s), ''), 339 note_test_org = nullif(trim(%(note_test_org)s), ''), 340 material = nullif(trim(%(material)s), ''), 341 material_detail = nullif(trim(%(material_detail)s), ''), 342 fk_intended_reviewer = %(pk_intended_reviewer)s, 343 fk_encounter = %(pk_encounter)s, 344 fk_episode = %(pk_episode)s, 345 fk_type = %(pk_test_type)s, 346 fk_request = %(pk_request)s 347 where 348 pk = %(pk_test_result)s and 349 xmin = %(xmin_test_result)s""", 350 u"""select xmin_test_result from clin.v_test_results where pk_test_result = %(pk_test_result)s""" 351 ] 352 353 _updatable_fields = [ 354 'clin_when', 355 'comment', 356 'val_num', 357 'val_alpha', 358 'val_unit', 359 'val_normal_min', 360 'val_normal_max', 361 'val_normal_range', 362 'val_target_min', 363 'val_target_max', 364 'val_target_range', 365 'abnormality_indicator', 366 'norm_ref_group', 367 'note_test_org', 368 'material', 369 'material_detail', 370 'pk_intended_reviewer', 371 'pk_encounter', 372 'pk_episode', 373 'pk_test_type', 374 'pk_request' 375 ] 376 #--------------------------------------------------------
377 - def format(self, with_review=True, with_comments=True, date_format='%Y-%m-%d %H:%M'):
378 379 lines = [] 380 381 lines.append(u' %s %s (%s): %s %s%s' % ( 382 self._payload[self._idx['clin_when']].strftime(date_format), 383 self._payload[self._idx['unified_abbrev']], 384 self._payload[self._idx['unified_name']], 385 self._payload[self._idx['unified_val']], 386 self._payload[self._idx['val_unit']], 387 gmTools.coalesce(self._payload[self._idx['abnormality_indicator']], u'', u' (%s)') 388 )) 389 390 if with_comments: 391 if gmTools.coalesce(self._payload[self._idx['comment']], u'').strip() != u'': 392 lines.append(_(' Doc: %s') % self._payload[self._idx['comment']].strip()) 393 if gmTools.coalesce(self._payload[self._idx['note_test_org']], u'').strip() != u'': 394 lines.append(_(' MTA: %s') % self._payload[self._idx['note_test_org']].strip()) 395 396 if with_review: 397 if self._payload[self._idx['reviewed']]: 398 if self._payload[self._idx['is_clinically_relevant']]: 399 lines.append(u' %s %s: %s' % ( 400 self._payload[self._idx['last_reviewer']], 401 self._payload[self._idx['last_reviewed']].strftime('%Y-%m-%d %H:%M'), 402 gmTools.bool2subst ( 403 self._payload[self._idx['is_technically_abnormal']], 404 _('abnormal and relevant'), 405 _('normal but relevant') 406 ) 407 )) 408 else: 409 lines.append(_(' unreviewed')) 410 411 return lines
412 #--------------------------------------------------------
413 - def _get_reference_ranges(self):
414 415 cmd = u""" 416 select 417 distinct on (norm_ref_group_str, val_unit, val_normal_min, val_normal_max, val_normal_range, val_target_min, val_target_max, val_target_range) 418 pk_patient, 419 val_unit, 420 val_normal_min, val_normal_max, val_normal_range, 421 val_target_min, val_target_max, val_target_range, 422 norm_ref_group, 423 coalesce(norm_ref_group, '') as norm_ref_group_str 424 from 425 clin.v_test_results 426 where 427 pk_test_type = %(pk_type)s 428 """ 429 args = {'pk_type': self._payload[self._idx['pk_test_type']]} 430 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 431 return rows
432
433 - def _set_reference_ranges(self, val):
434 raise AttributeError('[%s]: reference ranges not settable') % self.__class__.__name__
435 436 reference_ranges = property(_get_reference_ranges, _set_reference_ranges) 437 #--------------------------------------------------------
438 - def set_review(self, technically_abnormal=None, clinically_relevant=None, comment=None, make_me_responsible=False):
439 440 # FIXME: this is not concurrency safe 441 if self._payload[self._idx['reviewed']]: 442 self.__change_existing_review ( 443 technically_abnormal = technically_abnormal, 444 clinically_relevant = clinically_relevant, 445 comment = comment 446 ) 447 else: 448 # do not sign off unreviewed results if 449 # NOTHING AT ALL is known about them 450 if technically_abnormal is None: 451 if clinically_relevant is None: 452 comment = gmTools.none_if(comment, u'', strip_string = True) 453 if comment is None: 454 if make_me_responsible is False: 455 return True 456 self.__set_new_review ( 457 technically_abnormal = technically_abnormal, 458 clinically_relevant = clinically_relevant, 459 comment = comment 460 ) 461 462 if make_me_responsible is True: 463 cmd = u"SELECT pk FROM dem.staff WHERE db_user = current_user" 464 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}]) 465 self['pk_intended_reviewer'] = rows[0][0] 466 self.save_payload() 467 return 468 469 self.refetch_payload()
470 #-------------------------------------------------------- 471 # internal API 472 #--------------------------------------------------------
473 - def __set_new_review(self, technically_abnormal=None, clinically_relevant=None, comment=None):
474 """Add a review to a row. 475 476 - if technically abnormal is not provided/None it will be set 477 to True if the lab's indicator has a meaningful value 478 - if clinically relevant is not provided/None it is set to 479 whatever technically abnormal is 480 """ 481 if technically_abnormal is None: 482 technically_abnormal = False 483 if self._payload[self._idx['abnormality_indicator']] is not None: 484 if self._payload[self._idx['abnormality_indicator']].strip() != u'': 485 technically_abnormal = True 486 487 if clinically_relevant is None: 488 clinically_relevant = technically_abnormal 489 490 cmd = u""" 491 INSERT INTO clin.reviewed_test_results ( 492 fk_reviewed_row, 493 is_technically_abnormal, 494 clinically_relevant, 495 comment 496 ) VALUES ( 497 %(pk)s, 498 %(abnormal)s, 499 %(relevant)s, 500 gm.nullify_empty_string(%(cmt)s) 501 )""" 502 args = { 503 'pk': self._payload[self._idx['pk_test_result']], 504 'abnormal': technically_abnormal, 505 'relevant': clinically_relevant, 506 'cmt': comment 507 } 508 509 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
510 #--------------------------------------------------------
511 - def __change_existing_review(self, technically_abnormal=None, clinically_relevant=None, comment=None):
512 """Change a review on a row. 513 514 - if technically abnormal/clinically relevant are 515 None they are not set 516 """ 517 args = { 518 'pk_row': self._payload[self._idx['pk_test_result']], 519 'abnormal': technically_abnormal, 520 'relevant': clinically_relevant, 521 'cmt': comment 522 } 523 524 set_parts = [ 525 u'fk_reviewer = (SELECT pk FROM dem.staff WHERE db_user = current_user)', 526 u'comment = gm.nullify_empty_string(%(cmt)s)' 527 ] 528 529 if technically_abnormal is not None: 530 set_parts.append(u'is_technically_abnormal = %(abnormal)s') 531 532 if clinically_relevant is not None: 533 set_parts.append(u'clinically_relevant = %(relevant)s') 534 535 cmd = u""" 536 UPDATE clin.reviewed_test_results SET 537 %s 538 WHERE 539 fk_reviewed_row = %%(pk_row)s 540 """ % u',\n '.join(set_parts) 541 542 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
543 #------------------------------------------------------------
544 -def delete_test_result(result=None):
545 546 try: 547 pk = int(result) 548 except (TypeError, AttributeError): 549 pk = result['pk_test_result'] 550 551 cmd = u'delete from clin.test_result where pk = %(pk)s' 552 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk}}])
553 #------------------------------------------------------------
554 -def create_test_result(encounter=None, episode=None, type=None, intended_reviewer=None, val_num=None, val_alpha=None, unit=None):
555 556 cmd1 = u""" 557 insert into clin.test_result ( 558 fk_encounter, 559 fk_episode, 560 fk_type, 561 fk_intended_reviewer, 562 val_num, 563 val_alpha, 564 val_unit 565 ) values ( 566 %(enc)s, 567 %(epi)s, 568 %(type)s, 569 %(rev)s, 570 %(v_num)s, 571 %(v_alpha)s, 572 %(unit)s 573 )""" 574 575 cmd2 = u""" 576 select * 577 from 578 clin.v_test_results 579 where 580 pk_test_result = currval(pg_get_serial_sequence('clin.test_result', 'pk'))""" 581 582 args = { 583 u'enc': encounter, 584 u'epi': episode, 585 u'type': type, 586 u'rev': intended_reviewer, 587 u'v_num': val_num, 588 u'v_alpha': val_alpha, 589 u'unit': unit 590 } 591 592 rows, idx = gmPG2.run_rw_queries ( 593 queries = [ 594 {'cmd': cmd1, 'args': args}, 595 {'cmd': cmd2} 596 ], 597 return_data = True, 598 get_col_idx = True 599 ) 600 601 tr = cTestResult(row = { 602 'pk_field': 'pk_test_result', 603 'idx': idx, 604 'data': rows[0] 605 }) 606 607 return tr
608 #------------------------------------------------------------
609 -def format_test_results(results=None, output_format=u'latex'):
610 611 _log.debug(u'formatting test results into [%s]', output_format) 612 613 if output_format == u'latex': 614 return __format_test_results_latex(results = results) 615 616 msg = _('unknown test results output format [%s]') % output_format 617 _log.error(msg) 618 return msg
619 #------------------------------------------------------------
620 -def __tests2latex_minipage(results=None, width=u'1.5cm', show_time=False, show_range=True):
621 622 if len(results) == 0: 623 return u'\\begin{minipage}{%s} \\end{minipage}' % width 624 625 lines = [] 626 for t in results: 627 628 tmp = u'' 629 630 if show_time: 631 tmp += u'{\\tiny (%s)} ' % t['clin_when'].strftime('%H:%M') 632 633 tmp += u'%.8s' % t['unified_val'] 634 635 lines.append(tmp) 636 tmp = u'' 637 638 if show_range: 639 has_range = ( 640 t['unified_target_range'] is not None 641 or 642 t['unified_target_min'] is not None 643 or 644 t['unified_target_max'] is not None 645 ) 646 if has_range: 647 if t['unified_target_range'] is not None: 648 tmp += u'{\\tiny %s}' % t['unified_target_range'] 649 else: 650 tmp += u'{\\tiny %s}' % ( 651 gmTools.coalesce(t['unified_target_min'], u'- ', u'%s - '), 652 gmTools.coalesce(t['unified_target_max'], u'', u'%s') 653 ) 654 lines.append(tmp) 655 656 return u'\\begin{minipage}{%s} \\begin{flushright} %s \\end{flushright} \\end{minipage}' % (width, u' \\\\ '.join(lines))
657 #------------------------------------------------------------
658 -def __tests2latex_cell(results=None, show_time=False, show_range=True):
659 660 if len(results) == 0: 661 return u'' 662 663 lines = [] 664 for t in results: 665 666 tmp = u'' 667 668 if show_time: 669 tmp += u'\\tiny %s ' % t['clin_when'].strftime('%H:%M') 670 671 tmp += u'\\normalsize %.8s' % t['unified_val'] 672 673 lines.append(tmp) 674 tmp = u'\\tiny %s' % gmTools.coalesce(t['val_unit'], u'', u'%s ') 675 676 if not show_range: 677 lines.append(tmp) 678 continue 679 680 has_range = ( 681 t['unified_target_range'] is not None 682 or 683 t['unified_target_min'] is not None 684 or 685 t['unified_target_max'] is not None 686 ) 687 688 if not has_range: 689 lines.append(tmp) 690 continue 691 692 if t['unified_target_range'] is not None: 693 tmp += u'[%s]' % t['unified_target_range'] 694 else: 695 tmp += u'[%s%s]' % ( 696 gmTools.coalesce(t['unified_target_min'], u'--', u'%s--'), 697 gmTools.coalesce(t['unified_target_max'], u'', u'%s') 698 ) 699 lines.append(tmp) 700 701 return u' \\\\ '.join(lines)
702 #------------------------------------------------------------
703 -def __format_test_results_latex(results=None):
704 705 if len(results) == 0: 706 return u'\\noindent %s' % _('No test results to format.') 707 708 # discover the columns and rows 709 dates = {} 710 tests = {} 711 grid = {} 712 for result in results: 713 # row_label = u'%s \\ \\tiny (%s)}' % (result['unified_abbrev'], result['unified_name']) 714 row_label = result['unified_abbrev'] 715 tests[row_label] = None 716 col_label = u'{\\scriptsize %s}' % result['clin_when'].strftime('%Y-%m-%d') 717 dates[col_label] = None 718 try: 719 grid[row_label] 720 except KeyError: 721 grid[row_label] = {} 722 try: 723 grid[row_label][col_label].append(result) 724 except KeyError: 725 grid[row_label][col_label] = [result] 726 727 col_labels = sorted(dates.keys(), reverse = True) 728 del dates 729 row_labels = sorted(tests.keys()) 730 del tests 731 732 col_def = len(col_labels) * u'>{\\raggedleft}p{1.7cm}|' 733 734 # format them 735 tex = u"""\\noindent %s 736 737 \\noindent \\begin{tabular}{|l|%s} 738 \\hline 739 & %s \\tabularnewline 740 \\hline 741 742 %%s \\tabularnewline 743 744 \\hline 745 746 \\end{tabular}""" % ( 747 _('Test results'), 748 col_def, 749 u' & '.join(col_labels) 750 ) 751 752 rows = [] 753 754 # loop over rows 755 for rl in row_labels: 756 cells = [rl] 757 # loop over cols per row 758 for cl in col_labels: 759 try: 760 # get tests for this (row/col) position 761 tests = grid[rl][cl] 762 except KeyError: 763 # none there, so insert empty cell 764 cells.append(u' ') 765 continue 766 767 cells.append ( 768 __tests2latex_cell ( 769 results = tests, 770 show_time = (len(tests) > 1), 771 show_range = True 772 ) 773 ) 774 775 rows.append(u' & '.join(cells)) 776 777 return tex % u' \\tabularnewline\n \\hline\n'.join(rows)
778 779 #============================================================
780 -def export_results_for_gnuplot(results=None, filename=None):
781 782 if filename is None: 783 filename = gmTools.get_unique_filename(prefix = u'gm2gpl-', suffix = '.dat') 784 785 # sort results into series by test type 786 series = {} 787 for r in results: 788 try: 789 series[r['unified_name']].append(r) 790 except KeyError: 791 series[r['unified_name']] = [r] 792 793 gp_data = codecs.open(filename, 'wb', 'utf8') 794 795 gp_data.write(u'# %s\n' % _('GNUmed test results export for Gnuplot plotting')) 796 gp_data.write(u'# -------------------------------------------------------------\n') 797 gp_data.write(u'# first line of index: test type abbreviation & name\n') 798 gp_data.write(u'#\n') 799 gp_data.write(u'# clin_when at full precision\n') 800 gp_data.write(u'# value\n') 801 gp_data.write(u'# unit\n') 802 gp_data.write(u'# unified (target or normal) range: lower bound\n') 803 gp_data.write(u'# unified (target or normal) range: upper bound\n') 804 gp_data.write(u'# normal range: lower bound\n') 805 gp_data.write(u'# normal range: upper bound\n') 806 gp_data.write(u'# target range: lower bound\n') 807 gp_data.write(u'# target range: upper bound\n') 808 gp_data.write(u'# clin_when formatted into string as x-axis tic label\n') 809 gp_data.write(u'# -------------------------------------------------------------\n') 810 811 for test_type in series.keys(): 812 if len(series[test_type]) == 0: 813 continue 814 815 r = series[test_type][0] 816 title = u'%s (%s)' % ( 817 r['unified_abbrev'], 818 r['unified_name'] 819 ) 820 gp_data.write(u'\n\n"%s" "%s"\n' % (title, title)) 821 822 prev_date = None 823 prev_year = None 824 for r in series[test_type]: 825 curr_date = r['clin_when'].strftime('%Y-%m-%d') 826 if curr_date == prev_date: 827 gp_data.write(u'\n# %s\n' % _('blank line inserted to allow for discontinued line drawing for same-day values')) 828 if r['clin_when'].year == prev_year: 829 when_template = '%b %d %H:%M' 830 else: 831 when_template = '%b %d %H:%M (%Y)' 832 prev_year = r['clin_when'].year 833 gp_data.write (u'%s %s "%s" %s %s %s %s %s %s "%s"\n' % ( 834 r['clin_when'].strftime('%Y-%m-%d_%H:%M'), 835 r['unified_val'], 836 gmTools.coalesce(r['val_unit'], u'"<?>"'), 837 gmTools.coalesce(r['unified_target_min'], u'"<?>"'), 838 gmTools.coalesce(r['unified_target_max'], u'"<?>"'), 839 gmTools.coalesce(r['val_normal_min'], u'"<?>"'), 840 gmTools.coalesce(r['val_normal_max'], u'"<?>"'), 841 gmTools.coalesce(r['val_target_min'], u'"<?>"'), 842 gmTools.coalesce(r['val_target_max'], u'"<?>"'), 843 gmDateTime.pydt_strftime ( 844 r['clin_when'], 845 format = when_template, 846 accuracy = gmDateTime.acc_minutes 847 ) 848 )) 849 prev_date = curr_date 850 851 gp_data.close() 852 853 return filename
854 #============================================================
855 -class cLabResult(gmBusinessDBObject.cBusinessDBObject):
856 """Represents one lab result.""" 857 858 _cmd_fetch_payload = """ 859 select *, xmin_test_result from v_results4lab_req 860 where pk_result=%s""" 861 _cmds_lock_rows_for_update = [ 862 """select 1 from test_result where pk=%(pk_result)s and xmin=%(xmin_test_result)s for update""" 863 ] 864 _cmds_store_payload = [ 865 """update test_result set 866 clin_when = %(val_when)s, 867 narrative = %(progress_note_result)s, 868 fk_type = %(pk_test_type)s, 869 val_num = %(val_num)s::numeric, 870 val_alpha = %(val_alpha)s, 871 val_unit = %(val_unit)s, 872 val_normal_min = %(val_normal_min)s, 873 val_normal_max = %(val_normal_max)s, 874 val_normal_range = %(val_normal_range)s, 875 val_target_min = %(val_target_min)s, 876 val_target_max = %(val_target_max)s, 877 val_target_range = %(val_target_range)s, 878 abnormality_indicator = %(abnormal)s, 879 norm_ref_group = %(ref_group)s, 880 note_provider = %(note_provider)s, 881 material = %(material)s, 882 material_detail = %(material_detail)s 883 where pk = %(pk_result)s""", 884 """select xmin_test_result from v_results4lab_req where pk_result=%(pk_result)s""" 885 ] 886 887 _updatable_fields = [ 888 'val_when', 889 'progress_note_result', 890 'val_num', 891 'val_alpha', 892 'val_unit', 893 'val_normal_min', 894 'val_normal_max', 895 'val_normal_range', 896 'val_target_min', 897 'val_target_max', 898 'val_target_range', 899 'abnormal', 900 'ref_group', 901 'note_provider', 902 'material', 903 'material_detail' 904 ] 905 #--------------------------------------------------------
906 - def __init__(self, aPK_obj=None, row=None):
907 """Instantiate. 908 909 aPK_obj as dict: 910 - patient_id 911 - when_field (see view definition) 912 - when 913 - test_type 914 - val_num 915 - val_alpha 916 - unit 917 """ 918 # instantiate from row data ? 919 if aPK_obj is None: 920 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=row) 921 return 922 pk = aPK_obj 923 # find PK from row data ? 924 if type(aPK_obj) == types.DictType: 925 # sanity checks 926 if None in [aPK_obj['patient_id'], aPK_obj['when'], aPK_obj['when_field'], aPK_obj['test_type'], aPK_obj['unit']]: 927 raise gmExceptions.ConstructorError, 'parameter error: %s' % aPK_obj 928 if (aPK_obj['val_num'] is None) and (aPK_obj['val_alpha'] is None): 929 raise gmExceptions.ConstructorError, 'parameter error: val_num and val_alpha cannot both be None' 930 # get PK 931 where_snippets = [ 932 'pk_patient=%(patient_id)s', 933 'pk_test_type=%(test_type)s', 934 '%s=%%(when)s' % aPK_obj['when_field'], 935 'val_unit=%(unit)s' 936 ] 937 if aPK_obj['val_num'] is not None: 938 where_snippets.append('val_num=%(val_num)s::numeric') 939 if aPK_obj['val_alpha'] is not None: 940 where_snippets.append('val_alpha=%(val_alpha)s') 941 942 where_clause = ' and '.join(where_snippets) 943 cmd = "select pk_result from v_results4lab_req where %s" % where_clause 944 data = gmPG.run_ro_query('historica', cmd, None, aPK_obj) 945 if data is None: 946 raise gmExceptions.ConstructorError, 'error getting lab result for: %s' % aPK_obj 947 if len(data) == 0: 948 raise gmExceptions.NoSuchClinItemError, 'no lab result for: %s' % aPK_obj 949 pk = data[0][0] 950 # instantiate class 951 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
952 #--------------------------------------------------------
953 - def get_patient(self):
954 cmd = """ 955 select 956 %s, 957 vbp.title, 958 vbp.firstnames, 959 vbp.lastnames, 960 vbp.dob 961 from v_basic_person vbp 962 where vbp.pk_identity=%%s""" % self._payload[self._idx['pk_patient']] 963 pat = gmPG.run_ro_query('historica', cmd, None, self._payload[self._idx['pk_patient']]) 964 return pat[0]
965 #============================================================
966 -class cLabRequest(gmBusinessDBObject.cBusinessDBObject):
967 """Represents one lab request.""" 968 969 _cmd_fetch_payload = """ 970 select *, xmin_lab_request from v_lab_requests 971 where pk_request=%s""" 972 _cmds_lock_rows_for_update = [ 973 """select 1 from lab_request where pk=%(pk_request)s and xmin=%(xmin_lab_request)s for update""" 974 ] 975 _cmds_store_payload = [ 976 """update lab_request set 977 request_id=%(request_id)s, 978 lab_request_id=%(lab_request_id)s, 979 clin_when=%(sampled_when)s, 980 lab_rxd_when=%(lab_rxd_when)s, 981 results_reported_when=%(results_reported_when)s, 982 request_status=%(request_status)s, 983 is_pending=%(is_pending)s::bool, 984 narrative=%(progress_note)s 985 where pk=%(pk_request)s""", 986 """select xmin_lab_request from v_lab_requests where pk_request=%(pk_request)s""" 987 ] 988 _updatable_fields = [ 989 'request_id', 990 'lab_request_id', 991 'sampled_when', 992 'lab_rxd_when', 993 'results_reported_when', 994 'request_status', 995 'is_pending', 996 'progress_note' 997 ] 998 #--------------------------------------------------------
999 - def __init__(self, aPK_obj=None, row=None):
1000 """Instantiate lab request. 1001 1002 The aPK_obj can be either a dict with the keys "req_id" 1003 and "lab" or a simple primary key. 1004 """ 1005 # instantiate from row data ? 1006 if aPK_obj is None: 1007 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=row) 1008 return 1009 pk = aPK_obj 1010 # instantiate from "req_id" and "lab" ? 1011 if type(aPK_obj) == types.DictType: 1012 # sanity check 1013 try: 1014 aPK_obj['req_id'] 1015 aPK_obj['lab'] 1016 except: 1017 _log.exception('[%s:??]: faulty <aPK_obj> structure: [%s]' % (self.__class__.__name__, aPK_obj), sys.exc_info()) 1018 raise gmExceptions.ConstructorError, '[%s:??]: cannot derive PK from [%s]' % (self.__class__.__name__, aPK_obj) 1019 # generate query 1020 where_snippets = [] 1021 vals = {} 1022 where_snippets.append('request_id=%(req_id)s') 1023 if type(aPK_obj['lab']) == types.IntType: 1024 where_snippets.append('pk_test_org=%(lab)s') 1025 else: 1026 where_snippets.append('lab_name=%(lab)s') 1027 where_clause = ' and '.join(where_snippets) 1028 cmd = "select pk_request from v_lab_requests where %s" % where_clause 1029 # get pk 1030 data = gmPG.run_ro_query('historica', cmd, None, aPK_obj) 1031 if data is None: 1032 raise gmExceptions.ConstructorError, '[%s:??]: error getting lab request for [%s]' % (self.__class__.__name__, aPK_obj) 1033 if len(data) == 0: 1034 raise gmExceptions.NoSuchClinItemError, '[%s:??]: no lab request for [%s]' % (self.__class__.__name__, aPK_obj) 1035 pk = data[0][0] 1036 # instantiate class 1037 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1038 #--------------------------------------------------------
1039 - def get_patient(self):
1040 cmd = """ 1041 select vpi.pk_patient, vbp.title, vbp.firstnames, vbp.lastnames, vbp.dob 1042 from v_pat_items vpi, v_basic_person vbp 1043 where 1044 vpi.pk_item=%s 1045 and 1046 vbp.pk_identity=vpi.pk_patient""" 1047 pat = gmPG.run_ro_query('historica', cmd, None, self._payload[self._idx['pk_item']]) 1048 if pat is None: 1049 _log.error('cannot get patient for lab request [%s]' % self._payload[self._idx['pk_item']]) 1050 return None 1051 if len(pat) == 0: 1052 _log.error('no patient associated with lab request [%s]' % self._payload[self._idx['pk_item']]) 1053 return None 1054 return pat[0]
1055 #============================================================ 1056 # convenience functions 1057 #------------------------------------------------------------
1058 -def create_lab_request(lab=None, req_id=None, pat_id=None, encounter_id=None, episode_id=None):
1059 """Create or get lab request. 1060 1061 returns tuple (status, value): 1062 (True, lab request instance) 1063 (False, error message) 1064 (None, housekeeping_todo primary key) 1065 """ 1066 req = None 1067 aPK_obj = { 1068 'lab': lab, 1069 'req_id': req_id 1070 } 1071 try: 1072 req = cLabRequest (aPK_obj) 1073 except gmExceptions.NoSuchClinItemError, msg: 1074 _log.info('%s: will try to create lab request' % str(msg)) 1075 except gmExceptions.ConstructorError, msg: 1076 _log.exception(str(msg), sys.exc_info(), verbose=0) 1077 return (False, msg) 1078 # found 1079 if req is not None: 1080 db_pat = req.get_patient() 1081 if db_pat is None: 1082 _log.error('cannot cross-check patient on lab request') 1083 return (None, '') 1084 # yes but ambigous 1085 if pat_id != db_pat[0]: 1086 _log.error('lab request found for [%s:%s] but patient mismatch: expected [%s], in DB [%s]' % (lab, req_id, pat_id, db_pat)) 1087 me = '$RCSfile: gmPathLab.py,v $ $Revision: 1.81 $' 1088 to = 'user' 1089 prob = _('The lab request already exists but belongs to a different patient.') 1090 sol = _('Verify which patient this lab request really belongs to.') 1091 ctxt = _('lab [%s], request ID [%s], expected link with patient [%s], currently linked to patient [%s]') % (lab, req_id, pat_id, db_pat) 1092 cat = 'lab' 1093 status, data = gmPG.add_housekeeping_todo(me, to, prob, sol, ctxt, cat) 1094 return (None, data) 1095 return (True, req) 1096 # not found 1097 queries = [] 1098 if type(lab) is types.IntType: 1099 cmd = "insert into lab_request (fk_encounter, fk_episode, fk_test_org, request_id) values (%s, %s, %s, %s)" 1100 else: 1101 cmd = "insert into lab_request (fk_encounter, fk_episode, fk_test_org, request_id) values (%s, %s, (select pk from test_org where internal_OBSOLETE_name=%s), %s)" 1102 queries.append((cmd, [encounter_id, episode_id, str(lab), req_id])) 1103 cmd = "select currval('lab_request_pk_seq')" 1104 queries.append((cmd, [])) 1105 # insert new 1106 result, err = gmPG.run_commit('historica', queries, True) 1107 if result is None: 1108 return (False, err) 1109 try: 1110 req = cLabRequest(aPK_obj=result[0][0]) 1111 except gmExceptions.ConstructorError, msg: 1112 _log.exception(str(msg), sys.exc_info(), verbose=0) 1113 return (False, msg) 1114 return (True, req)
1115 #------------------------------------------------------------
1116 -def create_lab_result(patient_id=None, when_field=None, when=None, test_type=None, val_num=None, val_alpha=None, unit=None, encounter_id=None, request=None):
1117 tres = None 1118 data = { 1119 'patient_id': patient_id, 1120 'when_field': when_field, 1121 'when': when, 1122 'test_type': test_type, 1123 'val_num': val_num, 1124 'val_alpha': val_alpha, 1125 'unit': unit 1126 } 1127 try: 1128 tres = cLabResult(aPK_obj=data) 1129 # exists already, so fail 1130 _log.error('will not overwrite existing test result') 1131 _log.debug(str(tres)) 1132 return (None, tres) 1133 except gmExceptions.NoSuchClinItemError: 1134 _log.debug('test result not found - as expected, will create it') 1135 except gmExceptions.ConstructorError, msg: 1136 _log.exception(str(msg), sys.exc_info(), verbose=0) 1137 return (False, msg) 1138 if request is None: 1139 return (False, _('need lab request when inserting lab result')) 1140 # not found 1141 if encounter_id is None: 1142 encounter_id = request['pk_encounter'] 1143 queries = [] 1144 cmd = "insert into test_result (fk_encounter, fk_episode, fk_type, val_num, val_alpha, val_unit) values (%s, %s, %s, %s, %s, %s)" 1145 queries.append((cmd, [encounter_id, request['pk_episode'], test_type, val_num, val_alpha, unit])) 1146 cmd = "insert into lnk_result2lab_req (fk_result, fk_request) values ((select currval('test_result_pk_seq')), %s)" 1147 queries.append((cmd, [request['pk_request']])) 1148 cmd = "select currval('test_result_pk_seq')" 1149 queries.append((cmd, [])) 1150 # insert new 1151 result, err = gmPG.run_commit('historica', queries, True) 1152 if result is None: 1153 return (False, err) 1154 try: 1155 tres = cLabResult(aPK_obj=result[0][0]) 1156 except gmExceptions.ConstructorError, msg: 1157 _log.exception(str(msg), sys.exc_info(), verbose=0) 1158 return (False, msg) 1159 return (True, tres)
1160 #------------------------------------------------------------
1161 -def get_unreviewed_results(limit=50):
1162 # sanity check 1163 if limit < 1: 1164 limit = 1 1165 # retrieve one more row than needed so we know there's more available ;-) 1166 lim = limit + 1 1167 cmd = """ 1168 select pk_result 1169 from v_results4lab_req 1170 where reviewed is false 1171 order by pk_patient 1172 limit %s""" % lim 1173 rows = gmPG.run_ro_query('historica', cmd) 1174 if rows is None: 1175 _log.error('error retrieving unreviewed lab results') 1176 return (None, _('error retrieving unreviewed lab results')) 1177 if len(rows) == 0: 1178 return (False, []) 1179 # more than LIMIT rows ? 1180 if len(rows) == lim: 1181 more_avail = True 1182 # but deliver only LIMIT rows so that our assumption holds true... 1183 del rows[limit] 1184 else: 1185 more_avail = False 1186 results = [] 1187 for row in rows: 1188 try: 1189 results.append(cLabResult(aPK_obj=row[0])) 1190 except gmExceptions.ConstructorError: 1191 _log.exception('skipping unreviewed lab result [%s]' % row[0], sys.exc_info(), verbose=0) 1192 return (more_avail, results)
1193 #------------------------------------------------------------
1194 -def get_pending_requests(limit=250):
1195 lim = limit + 1 1196 cmd = "select pk from lab_request where is_pending is true limit %s" % lim 1197 rows = gmPG.run_ro_query('historica', cmd) 1198 if rows is None: 1199 _log.error('error retrieving pending lab requests') 1200 return (None, None) 1201 if len(rows) == 0: 1202 return (False, []) 1203 results = [] 1204 # more than LIMIT rows ? 1205 if len(rows) == lim: 1206 too_many = True 1207 # but deliver only LIMIT rows so that our assumption holds true... 1208 del rows[limit] 1209 else: 1210 too_many = False 1211 requests = [] 1212 for row in rows: 1213 try: 1214 requests.append(cLabRequest(aPK_obj=row[0])) 1215 except gmExceptions.ConstructorError: 1216 _log.exception('skipping pending lab request [%s]' % row[0], sys.exc_info(), verbose=0) 1217 return (too_many, requests)
1218 #------------------------------------------------------------
1219 -def get_next_request_ID(lab=None, incrementor_func=None):
1220 """Get logically next request ID for given lab. 1221 1222 - incrementor_func: 1223 - if not supplied the next ID is guessed 1224 - if supplied it is applied to the most recently used ID 1225 """ 1226 if type(lab) == types.IntType: 1227 lab_snippet = 'vlr.fk_test_org=%s' 1228 else: 1229 lab_snippet = 'vlr.lab_name=%s' 1230 lab = str(lab) 1231 cmd = """ 1232 select request_id 1233 from lab_request lr0 1234 where lr0.clin_when = ( 1235 select max(vlr.sampled_when) 1236 from v_lab_requests vlr 1237 where %s 1238 )""" % lab_snippet 1239 rows = gmPG.run_ro_query('historica', cmd, None, lab) 1240 if rows is None: 1241 _log.warning('error getting most recently used request ID for lab [%s]' % lab) 1242 return '' 1243 if len(rows) == 0: 1244 return '' 1245 most_recent = rows[0][0] 1246 # apply supplied incrementor 1247 if incrementor_func is not None: 1248 try: 1249 next = incrementor_func(most_recent) 1250 except TypeError: 1251 _log.error('cannot call incrementor function [%s]' % str(incrementor_func)) 1252 return most_recent 1253 return next 1254 # try to be smart ourselves 1255 for pos in range(len(most_recent)): 1256 header = most_recent[:pos] 1257 trailer = most_recent[pos:] 1258 try: 1259 return '%s%s' % (header, str(int(trailer) + 1)) 1260 except ValueError: 1261 header = most_recent[:-1] 1262 trailer = most_recent[-1:] 1263 return '%s%s' % (header, chr(ord(trailer) + 1))
1264 #============================================================
1265 -def calculate_bmi(mass=None, height=None, age=None):
1266 """Calculate BMI. 1267 1268 mass: kg 1269 height: cm 1270 age: not yet used 1271 1272 returns: 1273 (True/False, data) 1274 True: data = (bmi, lower_normal, upper_normal) 1275 False: data = error message 1276 """ 1277 converted, mass = gmTools.input2decimal(mass) 1278 if not converted: 1279 return False, u'mass: cannot convert <%s> to Decimal' % mass 1280 1281 converted, height = gmTools.input2decimal(height) 1282 if not converted: 1283 return False, u'height: cannot convert <%s> to Decimal' % height 1284 1285 approx_surface = (height / decimal.Decimal(100))**2 1286 bmi = mass / approx_surface 1287 1288 print mass, height, '->', approx_surface, '->', bmi 1289 1290 lower_normal_mass = 20.0 * approx_surface 1291 upper_normal_mass = 25.0 * approx_surface 1292 1293 return True, (bmi, lower_normal_mass, upper_normal_mass)
1294 #============================================================ 1295 # main - unit testing 1296 #------------------------------------------------------------ 1297 if __name__ == '__main__': 1298 1299 if len(sys.argv) < 2: 1300 sys.exit() 1301 1302 if sys.argv[1] != 'test': 1303 sys.exit() 1304 1305 import time 1306 1307 gmI18N.activate_locale() 1308 gmI18N.install_domain() 1309 1310 #------------------------------------------
1311 - def test_create_test_result():
1312 tr = create_test_result ( 1313 encounter = 1, 1314 episode = 1, 1315 type = 1, 1316 intended_reviewer = 1, 1317 val_num = '12', 1318 val_alpha=None, 1319 unit = 'mg/dl' 1320 ) 1321 print tr 1322 return tr
1323 #------------------------------------------
1324 - def test_delete_test_result():
1325 tr = test_create_test_result() 1326 delete_test_result(tr)
1327 #------------------------------------------
1328 - def test_result():
1329 r = cTestResult(aPK_obj=1) 1330 print r 1331 print r.reference_ranges
1332 #------------------------------------------
1333 - def test_lab_result():
1334 print "test_result()" 1335 # lab_result = cLabResult(aPK_obj=4) 1336 data = { 1337 'patient_id': 12, 1338 'when_field': 'val_when', 1339 'when': '2000-09-17 18:23:00+02', 1340 'test_type': 9, 1341 'val_num': 17.3, 1342 'val_alpha': None, 1343 'unit': 'mg/l' 1344 } 1345 lab_result = cLabResult(aPK_obj=data) 1346 print lab_result 1347 fields = lab_result.get_fields() 1348 for field in fields: 1349 print field, ':', lab_result[field] 1350 print "updatable:", lab_result.get_updatable_fields() 1351 print time.time() 1352 print lab_result.get_patient() 1353 print time.time()
1354 #------------------------------------------
1355 - def test_request():
1356 print "test_request()" 1357 try: 1358 # lab_req = cLabRequest(aPK_obj=1) 1359 # lab_req = cLabRequest(req_id='EML#SC937-0176-CEC#11', lab=2) 1360 data = { 1361 'req_id': 'EML#SC937-0176-CEC#11', 1362 'lab': 'Enterprise Main Lab' 1363 } 1364 lab_req = cLabRequest(aPK_obj=data) 1365 except gmExceptions.ConstructorError, msg: 1366 print "no such lab request:", msg 1367 return 1368 print lab_req 1369 fields = lab_req.get_fields() 1370 for field in fields: 1371 print field, ':', lab_req[field] 1372 print "updatable:", lab_req.get_updatable_fields() 1373 print time.time() 1374 print lab_req.get_patient() 1375 print time.time()
1376 #--------------------------------------------------------
1377 - def test_unreviewed():
1378 data = get_unreviewed_results() 1379 for result in data: 1380 print result
1381 #--------------------------------------------------------
1382 - def test_pending():
1383 data = get_pending_requests() 1384 for result in data: 1385 print result
1386 #--------------------------------------------------------
1387 - def test_create_measurement_type():
1388 print create_measurement_type ( 1389 lab = None, 1390 abbrev = u'tBZ2', 1391 unit = u'mg%', 1392 name = 'BZ (test 2)' 1393 )
1394 #--------------------------------------------------------
1395 - def test_meta_test_type():
1396 mtt = cMetaTestType(aPK_obj = 1) 1397 print mtt 1398 print get_meta_test_types()
1399 #--------------------------------------------------------
1400 - def test_test_type():
1401 tt = cMeasurementType(aPK_obj = 1) 1402 print tt 1403 print get_measurement_types()
1404 #--------------------------------------------------------
1405 - def test_format_test_results():
1406 results = [ 1407 cTestResult(aPK_obj=1), 1408 cTestResult(aPK_obj=2), 1409 cTestResult(aPK_obj=3) 1410 # cTestResult(aPK_obj=4) 1411 ] 1412 print format_test_results(results = results)
1413 #--------------------------------------------------------
1414 - def test_calculate_bmi():
1415 done, data = calculate_bmi(mass = sys.argv[2], height = sys.argv[3]) 1416 bmi, low, high = data 1417 1418 print "BMI:", bmi 1419 print "low:", low, "kg" 1420 print "hi :", high, "kg"
1421 1422 #-------------------------------------------------------- 1423 1424 #test_result() 1425 #test_create_test_result() 1426 #test_delete_test_result() 1427 #test_create_measurement_type() 1428 #test_lab_result() 1429 #test_request() 1430 #test_create_result() 1431 #test_unreviewed() 1432 #test_pending() 1433 #test_meta_test_type() 1434 #test_test_type() 1435 #test_format_test_results() 1436 test_calculate_bmi() 1437 1438 #============================================================ 1439