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

Source Code for Module Gnumed.business.gmDocuments

   1  """This module encapsulates a document stored in a GNUmed database.""" 
   2  #============================================================ 
   3  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>" 
   4  __license__ = "GPL v2 or later" 
   5   
   6  import sys, os, shutil, os.path, types, time, logging 
   7   
   8   
   9  if __name__ == '__main__': 
  10          sys.path.insert(0, '../../') 
  11  from Gnumed.pycommon import gmExceptions 
  12  from Gnumed.pycommon import gmBusinessDBObject 
  13  from Gnumed.pycommon import gmPG2 
  14  from Gnumed.pycommon import gmTools 
  15  from Gnumed.pycommon import gmMimeLib 
  16  from Gnumed.pycommon import gmDateTime 
  17  from Gnumed.pycommon import gmWorkerThread 
  18   
  19  from Gnumed.business import gmOrganization 
  20   
  21   
  22  _log = logging.getLogger('gm.docs') 
  23   
  24  MUGSHOT=26 
  25  DOCUMENT_TYPE_VISUAL_PROGRESS_NOTE = 'visual progress note' 
  26  DOCUMENT_TYPE_PRESCRIPTION = 'prescription' 
  27   
  28  #============================================================ 
29 -class cDocumentFolder:
30 """Represents a folder with medical documents for a single patient.""" 31
32 - def __init__(self, aPKey = None):
33 """Fails if 34 35 - patient referenced by aPKey does not exist 36 """ 37 self.pk_patient = aPKey # == identity.pk == primary key 38 if not self._pkey_exists(): 39 raise gmExceptions.ConstructorError("No patient with PK [%s] in database." % aPKey) 40 41 # register backend notification interests 42 # (keep this last so we won't hang on threads when 43 # failing this constructor for other reasons ...) 44 # if not self._register_interests(): 45 # raise gmExceptions.ConstructorError, "cannot register signal interests" 46 47 _log.debug('instantiated document folder for patient [%s]' % self.pk_patient)
48 #--------------------------------------------------------
49 - def cleanup(self):
50 pass
51 #-------------------------------------------------------- 52 # internal helper 53 #--------------------------------------------------------
54 - def _pkey_exists(self):
55 """Does this primary key exist ? 56 57 - true/false/None 58 """ 59 # patient in demographic database ? 60 rows, idx = gmPG2.run_ro_queries(queries = [ 61 {'cmd': "select exists(select pk from dem.identity where pk = %s)", 'args': [self.pk_patient]} 62 ]) 63 if not rows[0][0]: 64 _log.error("patient [%s] not in demographic database" % self.pk_patient) 65 return None 66 return True
67 #-------------------------------------------------------- 68 # API 69 #--------------------------------------------------------
71 cmd = """ 72 SELECT pk_doc 73 FROM blobs.v_doc_med 74 WHERE 75 pk_patient = %(pat)s 76 AND 77 type = %(typ)s 78 AND 79 ext_ref = %(ref)s 80 ORDER BY 81 clin_when DESC 82 LIMIT 1 83 """ 84 args = { 85 'pat': self.pk_patient, 86 'typ': DOCUMENT_TYPE_PRESCRIPTION, 87 'ref': 'FreeDiams' 88 } 89 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 90 if len(rows) == 0: 91 _log.info('no FreeDiams prescription available for patient [%s]' % self.pk_patient) 92 return None 93 prescription = cDocument(aPK_obj = rows[0][0]) 94 return prescription
95 96 #--------------------------------------------------------
97 - def get_latest_mugshot(self):
98 cmd = "SELECT pk_obj FROM blobs.v_latest_mugshot WHERE pk_patient = %s" 99 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_patient]}]) 100 if len(rows) == 0: 101 _log.info('no mugshots available for patient [%s]' % self.pk_patient) 102 return None 103 return cDocumentPart(aPK_obj = rows[0][0])
104 105 latest_mugshot = property(get_latest_mugshot, lambda x:x) 106 107 #--------------------------------------------------------
108 - def get_mugshot_list(self, latest_only=True):
109 if latest_only: 110 cmd = "select pk_doc, pk_obj from blobs.v_latest_mugshot where pk_patient=%s" 111 else: 112 cmd = """ 113 select 114 vdm.pk_doc as pk_doc, 115 dobj.pk as pk_obj 116 from 117 blobs.v_doc_med vdm 118 blobs.doc_obj dobj 119 where 120 vdm.pk_type = (select pk from blobs.doc_type where name = 'patient photograph') 121 and vdm.pk_patient = %s 122 and dobj.fk_doc = vdm.pk_doc 123 """ 124 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_patient]}]) 125 return rows
126 127 #--------------------------------------------------------
128 - def get_doc_list(self, doc_type=None):
129 """return flat list of document IDs""" 130 131 args = { 132 'ID': self.pk_patient, 133 'TYP': doc_type 134 } 135 136 cmd = """ 137 select vdm.pk_doc 138 from blobs.v_doc_med vdm 139 where 140 vdm.pk_patient = %%(ID)s 141 %s 142 order by vdm.clin_when""" 143 144 if doc_type is None: 145 cmd = cmd % '' 146 else: 147 try: 148 int(doc_type) 149 cmd = cmd % 'and vdm.pk_type = %(TYP)s' 150 except (TypeError, ValueError): 151 cmd = cmd % 'and vdm.pk_type = (select pk from blobs.doc_type where name = %(TYP)s)' 152 153 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 154 doc_ids = [] 155 for row in rows: 156 doc_ids.append(row[0]) 157 return doc_ids
158 159 #--------------------------------------------------------
160 - def get_visual_progress_notes(self, episodes=None, encounter=None):
161 return self.get_documents ( 162 doc_type = DOCUMENT_TYPE_VISUAL_PROGRESS_NOTE, 163 pk_episodes = episodes, 164 encounter = encounter 165 )
166 167 #--------------------------------------------------------
168 - def get_unsigned_documents(self):
169 args = {'pat': self.pk_patient} 170 cmd = _SQL_get_document_fields % """ 171 pk_doc IN ( 172 SELECT DISTINCT ON (b_vo.pk_doc) b_vo.pk_doc 173 FROM blobs.v_obj4doc_no_data b_vo 174 WHERE 175 pk_patient = %(pat)s 176 AND 177 reviewed IS FALSE 178 ) 179 ORDER BY clin_when DESC""" 180 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 181 return [ cDocument(row = {'pk_field': 'pk_doc', 'idx': idx, 'data': r}) for r in rows ]
182 183 #--------------------------------------------------------
184 - def get_documents(self, doc_type=None, pk_episodes=None, encounter=None, order_by=None, exclude_unsigned=False, pk_types=None):
185 """Return list of documents.""" 186 187 args = { 188 'pat': self.pk_patient, 189 'type': doc_type, 190 'enc': encounter 191 } 192 where_parts = ['pk_patient = %(pat)s'] 193 194 if doc_type is not None: 195 try: 196 int(doc_type) 197 where_parts.append('pk_type = %(type)s') 198 except (TypeError, ValueError): 199 where_parts.append('pk_type = (SELECT pk FROM blobs.doc_type WHERE name = %(type)s)') 200 201 if pk_types is not None: 202 where_parts.append('pk_type IN %(pk_types)s') 203 args['pk_types'] = tuple(pk_types) 204 205 if (pk_episodes is not None) and (len(pk_episodes) > 0): 206 where_parts.append('pk_episode IN %(epis)s') 207 args['epis'] = tuple(pk_episodes) 208 209 if encounter is not None: 210 where_parts.append('pk_encounter = %(enc)s') 211 212 if exclude_unsigned: 213 where_parts.append('pk_doc IN (SELECT b_vo.pk_doc FROM blobs.v_obj4doc_no_data b_vo WHERE b_vo.pk_patient = %(pat)s AND b_vo.reviewed IS TRUE)') 214 215 if order_by is None: 216 order_by = 'ORDER BY clin_when' 217 218 cmd = "%s\n%s" % (_SQL_get_document_fields % ' AND '.join(where_parts), order_by) 219 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 220 221 return [ cDocument(row = {'pk_field': 'pk_doc', 'idx': idx, 'data': r}) for r in rows ]
222 223 documents = property(get_documents, lambda x:x) 224 225 #--------------------------------------------------------
226 - def add_document(self, document_type=None, encounter=None, episode=None, link_obj=None):
227 return create_document(link_obj = link_obj, document_type = document_type, encounter = encounter, episode = episode)
228 229 #--------------------------------------------------------
230 - def add_prescription(self, encounter=None, episode=None, link_obj=None):
231 return self.add_document ( 232 link_obj = link_obj, 233 document_type = create_document_type ( 234 document_type = DOCUMENT_TYPE_PRESCRIPTION 235 )['pk_doc_type'], 236 encounter = encounter, 237 episode = episode 238 )
239 240 #--------------------------------------------------------
242 cmd = gmOrganization._SQL_get_org_unit % ( 243 'pk_org_unit IN (SELECT DISTINCT ON (pk_org_unit) pk_org_unit FROM blobs.v_doc_med WHERE pk_patient = %(pat)s)' 244 ) 245 args = {'pat': self.pk_patient} 246 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 247 return [ gmOrganization.cOrgUnit(row = {'data': r, 'idx': idx, 'pk_field': 'pk_org_unit'}) for r in rows ]
248 249 all_document_org_units = property(_get_all_document_org_units, lambda x:x)
250 251 #============================================================ 252 _SQL_get_document_part_fields = "select * from blobs.v_obj4doc_no_data where %s" 253
254 -class cDocumentPart(gmBusinessDBObject.cBusinessDBObject):
255 """Represents one part of a medical document.""" 256 257 _cmd_fetch_payload = _SQL_get_document_part_fields % "pk_obj = %s" 258 _cmds_store_payload = [ 259 """UPDATE blobs.doc_obj SET 260 seq_idx = %(seq_idx)s, 261 comment = gm.nullify_empty_string(%(obj_comment)s), 262 filename = gm.nullify_empty_string(%(filename)s), 263 fk_intended_reviewer = %(pk_intended_reviewer)s 264 WHERE 265 pk = %(pk_obj)s 266 AND 267 xmin = %(xmin_doc_obj)s 268 RETURNING 269 xmin AS xmin_doc_obj""" 270 ] 271 _updatable_fields = [ 272 'seq_idx', 273 'obj_comment', 274 'pk_intended_reviewer', 275 'filename' 276 ] 277 #-------------------------------------------------------- 278 # retrieve data 279 #--------------------------------------------------------
280 - def save_to_file(self, aChunkSize=0, filename=None, target_mime=None, target_extension=None, ignore_conversion_problems=False, directory=None, adjust_extension=False, conn=None):
281 282 if filename is None: 283 filename = self.get_useful_filename(make_unique = True, directory = directory) 284 285 filename = self.__download_to_file(filename = filename) 286 if filename is None: 287 return None 288 289 if target_mime is None: 290 if filename.endswith('.dat'): 291 if adjust_extension: 292 return gmMimeLib.adjust_extension_by_mimetype(filename) 293 return filename 294 295 if target_extension is None: 296 target_extension = gmMimeLib.guess_ext_by_mimetype(mimetype = target_mime) 297 298 target_path, name = os.path.split(filename) 299 name, tmp = os.path.splitext(name) 300 target_fname = gmTools.get_unique_filename ( 301 prefix = '%s-conv-' % name, 302 suffix = target_extension 303 ) 304 _log.debug('attempting conversion: [%s] -> [<%s>:%s]', filename, target_mime, target_fname) 305 converted_fname = gmMimeLib.convert_file ( 306 filename = filename, 307 target_mime = target_mime, 308 target_filename = target_fname 309 ) 310 if converted_fname is not None: 311 return converted_fname 312 313 _log.warning('conversion failed') 314 if not ignore_conversion_problems: 315 return None 316 317 if filename.endswith('.dat'): 318 if adjust_extension: 319 filename = gmMimeLib.adjust_extension_by_mimetype(filename) 320 _log.warning('programmed to ignore conversion problems, hoping receiver can handle [%s]', filename) 321 return filename
322 323 #--------------------------------------------------------
324 - def get_reviews(self):
325 cmd = """ 326 SELECT 327 reviewer, 328 reviewed_when, 329 is_technically_abnormal, 330 clinically_relevant, 331 is_review_by_responsible_reviewer, 332 is_your_review, 333 coalesce(comment, '') 334 FROM blobs.v_reviewed_doc_objects 335 WHERE pk_doc_obj = %s 336 ORDER BY 337 is_your_review desc, 338 is_review_by_responsible_reviewer desc, 339 reviewed_when desc 340 """ 341 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 342 return rows
343 344 #--------------------------------------------------------
345 - def __get_containing_document(self):
346 return cDocument(aPK_obj = self._payload[self._idx['pk_doc']])
347 348 containing_document = property(__get_containing_document) 349 350 #-------------------------------------------------------- 351 # store data 352 #--------------------------------------------------------
353 - def update_data_from_file(self, fname=None, link_obj=None):
354 # sanity check 355 if not (os.access(fname, os.R_OK) and os.path.isfile(fname)): 356 _log.error('[%s] is not a readable file' % fname) 357 return False 358 359 if not gmPG2.file2bytea ( 360 conn = link_obj, 361 query = "UPDATE blobs.doc_obj SET data = %(data)s::bytea WHERE pk = %(pk)s RETURNING md5(data) AS md5", 362 filename = fname, 363 args = {'pk': self.pk_obj}, 364 file_md5 = gmTools.file2md5(filename = fname, return_hex = True) 365 ): 366 return False 367 368 # must update XMIN now ... 369 self.refetch_payload(link_obj = link_obj) 370 return True
371 372 #--------------------------------------------------------
373 - def set_reviewed(self, technically_abnormal=None, clinically_relevant=None):
374 # row already there ? 375 cmd = """ 376 select pk 377 from blobs.reviewed_doc_objs 378 where 379 fk_reviewed_row = %s and 380 fk_reviewer = (select pk from dem.staff where db_user = current_user)""" 381 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 382 383 # INSERT needed 384 if len(rows) == 0: 385 cols = [ 386 "fk_reviewer", 387 "fk_reviewed_row", 388 "is_technically_abnormal", 389 "clinically_relevant" 390 ] 391 vals = [ 392 '%(fk_row)s', 393 '%(abnormal)s', 394 '%(relevant)s' 395 ] 396 args = { 397 'fk_row': self.pk_obj, 398 'abnormal': technically_abnormal, 399 'relevant': clinically_relevant 400 } 401 cmd = """ 402 insert into blobs.reviewed_doc_objs ( 403 %s 404 ) values ( 405 (select pk from dem.staff where db_user=current_user), 406 %s 407 )""" % (', '.join(cols), ', '.join(vals)) 408 409 # UPDATE needed 410 if len(rows) == 1: 411 pk_review = rows[0][0] 412 args = { 413 'abnormal': technically_abnormal, 414 'relevant': clinically_relevant, 415 'pk_review': pk_review 416 } 417 cmd = """ 418 UPDATE blobs.reviewed_doc_objs SET 419 is_technically_abnormal = %(abnormal)s, 420 clinically_relevant = %(relevant)s 421 WHERE 422 pk = %(pk_review)s 423 """ 424 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 425 426 return True
427 428 #--------------------------------------------------------
429 - def set_as_active_photograph(self):
430 if self._payload[self._idx['type']] != 'patient photograph': 431 return False 432 # set seq_idx to current max + 1 433 cmd = 'SELECT coalesce(max(seq_idx)+1, 1) FROM blobs.doc_obj WHERE fk_doc = %(doc_id)s' 434 rows, idx = gmPG2.run_ro_queries ( 435 queries = [{ 436 'cmd': cmd, 437 'args': {'doc_id': self._payload[self._idx['pk_doc']]} 438 }] 439 ) 440 self._payload[self._idx['seq_idx']] = rows[0][0] 441 self._is_modified = True 442 self.save_payload()
443 444 #--------------------------------------------------------
445 - def reattach(self, pk_doc=None):
446 if pk_doc == self._payload[self._idx['pk_doc']]: 447 return True 448 449 cmd = """ 450 UPDATE blobs.doc_obj SET 451 fk_doc = %(pk_doc_target)s, 452 -- coalesce needed for no-parts target docs 453 seq_idx = (SELECT coalesce(max(seq_idx) + 1, 1) FROM blobs.doc_obj WHERE fk_doc = %(pk_doc_target)s) 454 WHERE 455 EXISTS(SELECT 1 FROM blobs.doc_med WHERE pk = %(pk_doc_target)s) 456 AND 457 pk = %(pk_obj)s 458 AND 459 xmin = %(xmin_doc_obj)s 460 RETURNING fk_doc 461 """ 462 args = { 463 'pk_doc_target': pk_doc, 464 'pk_obj': self.pk_obj, 465 'xmin_doc_obj': self._payload[self._idx['xmin_doc_obj']] 466 } 467 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 468 if len(rows) == 0: 469 return False 470 # The following should never hold true because the target 471 # fk_doc is returned from the query and it is checked for 472 # equality before the UPDATE already. Assuming the update 473 # failed to update a row because the target fk_doc did 474 # not exist we would not get *any* rows in return - for 475 # which condition we also already checked 476 if rows[0]['fk_doc'] == self._payload[self._idx['pk_doc']]: 477 return False 478 479 self.refetch_payload() 480 return True
481 482 #--------------------------------------------------------
483 - def display_via_mime(self, chunksize=0, block=None):
484 485 fname = self.save_to_file(aChunkSize = chunksize) 486 if fname is None: 487 return False, '' 488 489 success, msg = gmMimeLib.call_viewer_on_file(fname, block = block) 490 if not success: 491 return False, msg 492 493 return True, ''
494 495 #--------------------------------------------------------
496 - def format_single_line(self):
497 f_ext = '' 498 if self._payload[self._idx['filename']] is not None: 499 f_ext = os.path.splitext(self._payload[self._idx['filename']])[1].strip('.').strip() 500 if f_ext != '': 501 f_ext = ' .' + f_ext.upper() 502 txt = _('part %s, %s%s%s of document %s from %s%s') % ( 503 self._payload[self._idx['seq_idx']], 504 gmTools.size2str(self._payload[self._idx['size']]), 505 f_ext, 506 gmTools.coalesce(self._payload[self._idx['obj_comment']], '', ' ("%s")'), 507 self._payload[self._idx['l10n_type']], 508 gmDateTime.pydt_strftime(self._payload[self._idx['date_generated']], '%Y %b %d'), 509 gmTools.coalesce(self._payload[self._idx['doc_comment']], '', ' ("%s")') 510 ) 511 return txt
512 513 #--------------------------------------------------------
514 - def format(self, single_line=False):
515 if single_line: 516 return self.format_single_line() 517 518 txt = _('%s document part [#%s]\n') % ( 519 gmTools.bool2str ( 520 boolean = self._payload[self._idx['reviewed']], 521 true_str = _('Reviewed'), 522 false_str = _('Unreviewed') 523 ), 524 self._payload[self._idx['pk_obj']] 525 ) 526 f_ext = '' 527 if self._payload[self._idx['filename']] is not None: 528 f_ext = os.path.splitext(self._payload[self._idx['filename']])[1].strip('.').strip() 529 if f_ext != '': 530 f_ext = '.' + f_ext.upper() + ' ' 531 txt += _(' Part %s: %s %s(%s Bytes)\n') % ( 532 self._payload[self._idx['seq_idx']], 533 gmTools.size2str(self._payload[self._idx['size']]), 534 f_ext, 535 self._payload[self._idx['size']] 536 ) 537 if self._payload[self._idx['filename']] is not None: 538 path, fname = os.path.split(self._payload[self._idx['filename']]) 539 if not path.endswith(os.path.sep): 540 if path != '': 541 path += os.path.sep 542 if path != '': 543 path = ' (%s)' % path 544 txt += _(' Filename: %s%s\n') % (fname, path) 545 if self._payload[self._idx['obj_comment']] is not None: 546 txt += '\n%s\n' % self._payload[self._idx['obj_comment']] 547 return txt
548 549 #--------------------------------------------------------
550 - def format_metainfo(self, callback=None):
551 """If <callback> is not None it will receive a tuple (status, description, pk_obj).""" 552 if callback is None: 553 return self.__run_metainfo_formatter() 554 555 gmWorkerThread.execute_in_worker_thread ( 556 payload_function = self.__run_metainfo_formatter, 557 completion_callback = callback, 558 worker_name = 'doc_part-metainfo_formatter-' 559 )
560 561 #--------------------------------------------------------
562 - def get_useful_filename(self, patient=None, make_unique=False, directory=None, include_gnumed_tag=True, date_before_type=False, name_first=True):
563 patient_part = '' 564 if patient is not None: 565 if name_first: 566 patient_part = '%s-' % patient.subdir_name 567 else: 568 patient_part = '-%s' % patient.subdir_name 569 570 # preserve original filename extension if available 571 suffix = '.dat' 572 if self._payload[self._idx['filename']] is not None: 573 tmp, suffix = os.path.splitext ( 574 gmTools.fname_sanitize(self._payload[self._idx['filename']]).lower() 575 ) 576 if suffix == '': 577 suffix = '.dat' 578 579 if include_gnumed_tag: 580 fname_template = 'gm_doc-part_%s-%%s' % self._payload[self._idx['seq_idx']] 581 else: 582 fname_template = '%%s-part_%s' % self._payload[self._idx['seq_idx']] 583 584 if date_before_type: 585 date_type_part = '%s-%s' % ( 586 gmDateTime.pydt_strftime(self._payload[self._idx['date_generated']], '%Y-%m-%d', 'utf-8', gmDateTime.acc_days), 587 self._payload[self._idx['l10n_type']].replace(' ', '_').replace('-', '_'), 588 ) 589 else: 590 date_type_part = '%s-%s' % ( 591 self._payload[self._idx['l10n_type']].replace(' ', '_').replace('-', '_'), 592 gmDateTime.pydt_strftime(self._payload[self._idx['date_generated']], '%Y-%m-%d', 'utf-8', gmDateTime.acc_days) 593 ) 594 595 if name_first: 596 date_type_name_part = patient_part + date_type_part 597 else: 598 date_type_name_part = date_type_part + patient_part 599 600 fname = fname_template % date_type_name_part 601 602 if make_unique: 603 fname = gmTools.get_unique_filename ( 604 prefix = '%s-' % gmTools.fname_sanitize(fname), 605 suffix = suffix, 606 tmp_dir = directory 607 ) 608 else: 609 fname = gmTools.fname_sanitize(os.path.join(gmTools.coalesce(directory, gmTools.gmPaths().tmp_dir), fname + suffix)) 610 611 return fname
612 613 useful_filename = property(get_useful_filename) 614 615 #-------------------------------------------------------- 616 # internal helpers 617 #--------------------------------------------------------
618 - def __download_to_file(self, filename=None, aChunkSize=0, conn=None):
619 if self._payload[self._idx['size']] == 0: 620 _log.debug('part size 0, nothing to download') 621 return None 622 623 if filename is None: 624 filename = gmTools.get_unique_filename() 625 success = gmPG2.bytea2file ( 626 data_query = { 627 'cmd': 'SELECT substring(data from %(start)s for %(size)s) FROM blobs.doc_obj WHERE pk=%(pk)s', 628 'args': {'pk': self.pk_obj} 629 }, 630 filename = filename, 631 chunk_size = aChunkSize, 632 data_size = self._payload[self._idx['size']], 633 conn = conn 634 ) 635 if not success: 636 return None 637 638 return filename
639 640 #--------------------------------------------------------
641 - def __run_metainfo_formatter(self):
642 filename = self.__download_to_file() 643 if filename is None: 644 _log.error('problem downloading part') 645 return (False, _('problem downloading document part')) 646 647 status, desc = gmMimeLib.describe_file(filename) 648 return (status, desc, self.pk_obj)
649 650 #------------------------------------------------------------
651 -def delete_document_part(part_pk=None, encounter_pk=None):
652 cmd = """ 653 SELECT blobs.delete_document_part(%(pk)s, %(enc)s) 654 WHERE NOT EXISTS 655 (SELECT 1 FROM clin.export_item where fk_doc_obj = %(pk)s) 656 """ 657 args = {'pk': part_pk, 'enc': encounter_pk} 658 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 659 return
660 661 #============================================================ 662 _SQL_get_document_fields = "SELECT * FROM blobs.v_doc_med b_vdm WHERE %s" 663
664 -class cDocument(gmBusinessDBObject.cBusinessDBObject):
665 """Represents one medical document.""" 666 667 _cmd_fetch_payload = _SQL_get_document_fields % "pk_doc = %s" 668 _cmds_store_payload = [ 669 """UPDATE blobs.doc_med SET 670 fk_type = %(pk_type)s, 671 fk_episode = %(pk_episode)s, 672 fk_encounter = %(pk_encounter)s, 673 fk_org_unit = %(pk_org_unit)s, 674 unit_is_receiver = %(unit_is_receiver)s, 675 clin_when = %(clin_when)s, 676 comment = gm.nullify_empty_string(%(comment)s), 677 ext_ref = gm.nullify_empty_string(%(ext_ref)s), 678 fk_hospital_stay = %(pk_hospital_stay)s 679 WHERE 680 pk = %(pk_doc)s and 681 xmin = %(xmin_doc_med)s 682 RETURNING 683 xmin AS xmin_doc_med""" 684 ] 685 _updatable_fields = [ 686 'pk_type', 687 'comment', 688 'clin_when', 689 'ext_ref', 690 'pk_episode', 691 'pk_encounter', # mainly useful when moving visual progress notes to their respective encounters 692 'pk_org_unit', 693 'unit_is_receiver', 694 'pk_hospital_stay' 695 ] 696 697 #--------------------------------------------------------
698 - def refetch_payload(self, ignore_changes=False, link_obj=None):
699 try: del self.__has_unreviewed_parts 700 except AttributeError: pass 701 702 return super(cDocument, self).refetch_payload(ignore_changes = ignore_changes, link_obj = link_obj)
703 704 #--------------------------------------------------------
705 - def get_descriptions(self, max_lng=250):
706 """Get document descriptions. 707 708 - will return a list of rows 709 """ 710 if max_lng is None: 711 cmd = "SELECT pk, text FROM blobs.doc_desc WHERE fk_doc = %s" 712 else: 713 cmd = "SELECT pk, substring(text from 1 for %s) FROM blobs.doc_desc WHERE fk_doc=%%s" % max_lng 714 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 715 return rows
716 717 #--------------------------------------------------------
718 - def add_description(self, description=None):
719 cmd = "insert into blobs.doc_desc (fk_doc, text) values (%s, %s)" 720 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj, description]}]) 721 return True
722 723 #--------------------------------------------------------
724 - def update_description(self, pk=None, description=None):
725 cmd = "update blobs.doc_desc set text = %(desc)s where fk_doc = %(doc)s and pk = %(pk_desc)s" 726 gmPG2.run_rw_queries(queries = [ 727 {'cmd': cmd, 'args': {'doc': self.pk_obj, 'pk_desc': pk, 'desc': description}} 728 ]) 729 return True
730 731 #--------------------------------------------------------
732 - def delete_description(self, pk=None):
733 cmd = "delete from blobs.doc_desc where fk_doc = %(doc)s and pk = %(desc)s" 734 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'doc': self.pk_obj, 'desc': pk}}]) 735 return True
736 737 #--------------------------------------------------------
738 - def _get_parts(self):
739 cmd = _SQL_get_document_part_fields % "pk_doc = %s ORDER BY seq_idx" 740 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}], get_col_idx = True) 741 return [ cDocumentPart(row = {'pk_field': 'pk_obj', 'idx': idx, 'data': r}) for r in rows ]
742 743 parts = property(_get_parts, lambda x:x) 744 745 #--------------------------------------------------------
746 - def add_part(self, file=None, link_obj=None):
747 """Add a part to the document.""" 748 # create dummy part 749 cmd = """ 750 INSERT INTO blobs.doc_obj ( 751 fk_doc, data, seq_idx 752 ) VALUES ( 753 %(doc_id)s, 754 ''::bytea, 755 (SELECT coalesce(max(seq_idx)+1, 1) FROM blobs.doc_obj WHERE fk_doc = %(doc_id)s) 756 ) RETURNING pk""" 757 rows, idx = gmPG2.run_rw_queries ( 758 link_obj = link_obj, 759 queries = [{'cmd': cmd, 'args': {'doc_id': self.pk_obj}}], 760 return_data = True 761 ) 762 # init document part instance 763 pk_part = rows[0][0] 764 new_part = cDocumentPart(aPK_obj = pk_part, link_obj = link_obj) 765 if not new_part.update_data_from_file(link_obj = link_obj, fname = file): 766 _log.error('cannot import binary data from [%s] into document part' % file) 767 gmPG2.run_rw_queries ( 768 link_obj = link_obj, 769 queries = [{'cmd': "DELETE FROM blobs.doc_obj WHERE pk = %s", 'args': [pk_part]}] 770 ) 771 return None 772 new_part['filename'] = file 773 new_part.save_payload(conn = link_obj) 774 775 return new_part
776 777 #--------------------------------------------------------
778 - def add_parts_from_files(self, files=None, reviewer=None):
779 780 new_parts = [] 781 782 for filename in files: 783 new_part = self.add_part(file = filename) 784 if new_part is None: 785 msg = 'cannot instantiate document part object from [%s]' % filename 786 _log.error(msg) 787 return (False, msg, filename) 788 new_parts.append(new_part) 789 790 if reviewer is not None: 791 new_part['pk_intended_reviewer'] = reviewer # None == Null 792 success, data = new_part.save_payload() 793 if not success: 794 msg = 'cannot set reviewer to [%s] on [%s]' % (reviewer, filename) 795 _log.error(msg) 796 _log.error(str(data)) 797 return (False, msg, filename) 798 799 return (True, '', new_parts)
800 801 #--------------------------------------------------------
802 - def save_parts_to_files(self, export_dir=None, chunksize=0, conn=None):
803 fnames = [] 804 for part in self.parts: 805 fname = part.save_to_file(aChunkSize = chunksize, directory = export_dir, conn = conn) 806 if fname is None: 807 _log.error('cannot export document part [%s]', part) 808 continue 809 fnames.append(fname) 810 return fnames
811 812 #--------------------------------------------------------
813 - def _get_has_unreviewed_parts(self):
814 try: 815 return self.__has_unreviewed_parts 816 except AttributeError: 817 pass 818 819 cmd = "SELECT EXISTS(SELECT 1 FROM blobs.v_obj4doc_no_data WHERE pk_doc = %(pk)s AND reviewed IS FALSE)" 820 args = {'pk': self.pk_obj} 821 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 822 self.__has_unreviewed_parts = rows[0][0] 823 824 return self.__has_unreviewed_parts
825 826 has_unreviewed_parts = property(_get_has_unreviewed_parts, lambda x:x) 827 828 #--------------------------------------------------------
829 - def set_reviewed(self, technically_abnormal=None, clinically_relevant=None):
830 # FIXME: this is probably inefficient 831 for part in self.parts: 832 if not part.set_reviewed(technically_abnormal, clinically_relevant): 833 return False 834 return True
835 836 #--------------------------------------------------------
837 - def set_primary_reviewer(self, reviewer=None):
838 for part in self.parts: 839 part['pk_intended_reviewer'] = reviewer 840 success, data = part.save_payload() 841 if not success: 842 _log.error('cannot set reviewer to [%s]' % reviewer) 843 _log.error(str(data)) 844 return False 845 return True
846 847 #--------------------------------------------------------
848 - def format_single_line(self):
849 850 part_count = len(self._payload[self._idx['seq_idx_list']]) 851 if part_count == 0: 852 parts = _('no parts') 853 elif part_count == 1: 854 parts = _('1 part') 855 else: 856 parts = _('%s parts') % part_count 857 858 detail = '' 859 if self._payload[self._idx['ext_ref']] is not None: 860 detail = self._payload[self._idx['ext_ref']] 861 if self._payload[self._idx['unit']] is not None: 862 template = _('%s of %s') 863 if detail == '': 864 detail = _('%s of %s') % ( 865 self._payload[self._idx['unit']], 866 self._payload[self._idx['organization']] 867 ) 868 else: 869 detail += (' @ ' + template % ( 870 self._payload[self._idx['unit']], 871 self._payload[self._idx['organization']] 872 )) 873 if detail != '': 874 detail = ' (%s)' % detail 875 876 return '%s %s (%s):%s%s' % ( 877 gmDateTime.pydt_strftime(self._payload[self._idx['clin_when']], '%Y %b %d', accuracy = gmDateTime.acc_days), 878 self._payload[self._idx['l10n_type']], 879 parts, 880 gmTools.coalesce(self._payload[self._idx['comment']], '', ' "%s"'), 881 detail 882 )
883 884 #--------------------------------------------------------
885 - def format(self, single_line=False):
886 if single_line: 887 return self.format_single_line() 888 889 part_count = len(self._payload[self._idx['seq_idx_list']]) 890 if part_count == 0: 891 parts = _('no parts') 892 elif part_count == 1: 893 parts = _('1 part') 894 else: 895 parts = _('%s parts') % part_count 896 org = '' 897 if self._payload[self._idx['unit']] is not None: 898 if self._payload[self._idx['unit_is_receiver']]: 899 org = _(' Receiver: %s @ %s\n') % ( 900 self._payload[self._idx['unit']], 901 self._payload[self._idx['organization']] 902 ) 903 else: 904 org = _(' Sender: %s @ %s\n') % ( 905 self._payload[self._idx['unit']], 906 self._payload[self._idx['organization']] 907 ) 908 stay = '' 909 if self._payload[self._idx['pk_hospital_stay']] is not None: 910 stay = _('Hospital stay') + ': %s\n' % self.hospital_stay.format ( 911 left_margin = 0, 912 include_procedures = False, 913 include_docs = False, 914 include_episode = False 915 ) 916 917 txt = _( 918 '%s (%s) #%s\n' 919 ' Created: %s\n' 920 ' Episode: %s\n' 921 '%s' 922 '%s' 923 '%s' 924 '%s' 925 '%s' 926 ) % ( 927 self._payload[self._idx['l10n_type']], 928 parts, 929 self._payload[self._idx['pk_doc']], 930 gmDateTime.pydt_strftime(self._payload[self._idx['clin_when']], format = '%Y %b %d', accuracy = gmDateTime.acc_days), 931 self._payload[self._idx['episode']], 932 gmTools.coalesce(self._payload[self._idx['health_issue']], '', _(' Health issue: %s\n')), 933 gmTools.coalesce(self._payload[self._idx['ext_ref']], '', _(' External reference: %s\n')), 934 org, 935 stay, 936 gmTools.coalesce(self._payload[self._idx['comment']], '', ' %s') 937 ) 938 939 return txt
940 941 #--------------------------------------------------------
942 - def _get_hospital_stay(self):
943 if self._payload[self._idx['pk_hospital_stay']] is None: 944 return None 945 from Gnumed.business import gmEMRStructItems 946 return gmEMRStructItems.cHospitalStay(self._payload[self._idx['pk_hospital_stay']])
947 948 hospital_stay = property(_get_hospital_stay, lambda x:x) 949 950 #--------------------------------------------------------
951 - def _get_org_unit(self):
952 if self._payload[self._idx['pk_org_unit']] is None: 953 return None 954 return gmOrganization.cOrgUnit(self._payload[self._idx['pk_org_unit']])
955 956 org_unit = property(_get_org_unit, lambda x:x) 957 958 #--------------------------------------------------------
959 - def _get_procedures(self):
960 from Gnumed.business.gmEMRStructItems import get_procedures4document 961 return get_procedures4document(pk_document = self.pk_obj)
962 963 procedures = property(_get_procedures, lambda x:x) 964 965 #--------------------------------------------------------
966 - def _get_bills(self):
967 from Gnumed.business.gmBilling import get_bills4document 968 return get_bills4document(pk_document = self.pk_obj)
969 970 bills = property(_get_bills, lambda x:x)
971 972 #------------------------------------------------------------
973 -def create_document(document_type=None, encounter=None, episode=None, link_obj=None):
974 """Returns new document instance or raises an exception.""" 975 try: 976 int(document_type) 977 cmd = """INSERT INTO blobs.doc_med (fk_type, fk_encounter, fk_episode) VALUES (%(type)s, %(enc)s, %(epi)s) RETURNING pk""" 978 except ValueError: 979 create_document_type(document_type = document_type) 980 cmd = """ 981 INSERT INTO blobs.doc_med ( 982 fk_type, 983 fk_encounter, 984 fk_episode 985 ) VALUES ( 986 coalesce ( 987 (SELECT pk from blobs.doc_type bdt where bdt.name = %(type)s), 988 (SELECT pk from blobs.doc_type bdt where _(bdt.name) = %(type)s) 989 ), 990 %(enc)s, 991 %(epi)s 992 ) RETURNING pk""" 993 args = {'type': document_type, 'enc': encounter, 'epi': episode} 994 rows, idx = gmPG2.run_rw_queries(link_obj = link_obj, queries = [{'cmd': cmd, 'args': args}], return_data = True) 995 doc = cDocument(aPK_obj = rows[0][0], link_obj = link_obj) 996 return doc
997 998 #------------------------------------------------------------
999 -def search_for_documents(patient_id=None, type_id=None, external_reference=None, pk_episode=None, pk_types=None):
1000 """Searches for documents with the given patient and type ID.""" 1001 1002 if (patient_id is None) and (pk_episode is None): 1003 raise ValueError('need patient_id or pk_episode to search for document') 1004 1005 where_parts = [] 1006 args = { 1007 'pat_id': patient_id, 1008 'type_id': type_id, 1009 'ref': external_reference, 1010 'pk_epi': pk_episode 1011 } 1012 1013 if patient_id is not None: 1014 where_parts.append('pk_patient = %(pat_id)s') 1015 1016 if type_id is not None: 1017 where_parts.append('pk_type = %(type_id)s') 1018 1019 if external_reference is not None: 1020 where_parts.append('ext_ref = %(ref)s') 1021 1022 if pk_episode is not None: 1023 where_parts.append('pk_episode = %(pk_epi)s') 1024 1025 if pk_types is not None: 1026 where_parts.append('pk_type IN %(pk_types)s') 1027 args['pk_types'] = tuple(pk_types) 1028 1029 cmd = _SQL_get_document_fields % ' AND '.join(where_parts) 1030 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 1031 return [ cDocument(row = {'data': r, 'idx': idx, 'pk_field': 'pk_doc'}) for r in rows ]
1032 1033 #------------------------------------------------------------
1034 -def delete_document(document_id=None, encounter_id=None):
1035 # cascades to doc_obj and doc_desc but not bill.bill 1036 cmd = "SELECT blobs.delete_document(%(pk)s, %(enc)s)" 1037 args = {'pk': document_id, 'enc': encounter_id} 1038 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 1039 if not rows[0][0]: 1040 _log.error('cannot delete document [%s]', document_id) 1041 return False 1042 return True
1043 1044 #------------------------------------------------------------
1045 -def reclassify_documents_by_type(original_type=None, target_type=None):
1046 1047 _log.debug('reclassifying documents by type') 1048 _log.debug('original: %s', original_type) 1049 _log.debug('target: %s', target_type) 1050 1051 if target_type['pk_doc_type'] == original_type['pk_doc_type']: 1052 return True 1053 1054 cmd = """ 1055 update blobs.doc_med set 1056 fk_type = %(new_type)s 1057 where 1058 fk_type = %(old_type)s 1059 """ 1060 args = {'new_type': target_type['pk_doc_type'], 'old_type': original_type['pk_doc_type']} 1061 1062 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 1063 1064 return True
1065 1066 #============================================================
1067 -class cDocumentType(gmBusinessDBObject.cBusinessDBObject):
1068 """Represents a document type.""" 1069 _cmd_fetch_payload = """select * from blobs.v_doc_type where pk_doc_type=%s""" 1070 _cmds_store_payload = [ 1071 """update blobs.doc_type set 1072 name = %(type)s 1073 where 1074 pk=%(pk_obj)s and 1075 xmin=%(xmin_doc_type)s""", 1076 """select xmin_doc_type from blobs.v_doc_type where pk_doc_type = %(pk_obj)s""" 1077 ] 1078 _updatable_fields = ['type'] 1079 #--------------------------------------------------------
1080 - def set_translation(self, translation=None):
1081 1082 if translation.strip() == '': 1083 return False 1084 1085 if translation.strip() == self._payload[self._idx['l10n_type']].strip(): 1086 return True 1087 1088 rows, idx = gmPG2.run_rw_queries ( 1089 queries = [ 1090 {'cmd': 'select i18n.i18n(%s)', 'args': [self._payload[self._idx['type']]]}, 1091 {'cmd': 'select i18n.upd_tx((select i18n.get_curr_lang()), %(orig)s, %(tx)s)', 1092 'args': { 1093 'orig': self._payload[self._idx['type']], 1094 'tx': translation 1095 } 1096 } 1097 ], 1098 return_data = True 1099 ) 1100 if not rows[0][0]: 1101 _log.error('cannot set translation to [%s]' % translation) 1102 return False 1103 1104 return self.refetch_payload()
1105 1106 #------------------------------------------------------------
1107 -def get_document_types():
1108 rows, idx = gmPG2.run_ro_queries ( 1109 queries = [{'cmd': "SELECT * FROM blobs.v_doc_type"}], 1110 get_col_idx = True 1111 ) 1112 doc_types = [] 1113 for row in rows: 1114 row_def = {'pk_field': 'pk_doc_type', 'idx': idx, 'data': row} 1115 doc_types.append(cDocumentType(row = row_def)) 1116 return doc_types
1117 1118 #------------------------------------------------------------
1119 -def get_document_type_pk(document_type=None):
1120 args = {'typ': document_type.strip()} 1121 1122 cmd = 'SELECT pk FROM blobs.doc_type WHERE name = %(typ)s' 1123 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1124 if len(rows) == 0: 1125 cmd = 'SELECT pk FROM blobs.doc_type WHERE _(name) = %(typ)s' 1126 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1127 1128 if len(rows) == 0: 1129 return None 1130 1131 return rows[0]['pk']
1132 1133 #------------------------------------------------------------
1134 -def map_types2pk(document_types=None):
1135 args = {'types': tuple(document_types)} 1136 cmd = 'SELECT pk_doc_type, coalesce(l10n_type, type) as desc FROM blobs.v_doc_type WHERE l10n_type IN %(types)s OR type IN %(types)s' 1137 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1138 return rows
1139 1140 #------------------------------------------------------------
1141 -def create_document_type(document_type=None):
1142 # check for potential dupes: 1143 cmd = 'SELECT pk FROM blobs.doc_type WHERE name = %s' 1144 rows, idx = gmPG2.run_ro_queries ( 1145 queries = [{'cmd': cmd, 'args': [document_type]}] 1146 ) 1147 if len(rows) == 0: 1148 _log.debug('creating document type [%s]', document_type) 1149 cmd1 = "INSERT INTO blobs.doc_type (name) VALUES (%s) RETURNING pk" 1150 rows, idx = gmPG2.run_rw_queries ( 1151 queries = [{'cmd': cmd1, 'args': [document_type]}], 1152 return_data = True 1153 ) 1154 return cDocumentType(aPK_obj = rows[0][0])
1155 1156 #------------------------------------------------------------
1157 -def delete_document_type(document_type=None):
1158 if document_type['is_in_use']: 1159 return False 1160 gmPG2.run_rw_queries ( 1161 queries = [{ 1162 'cmd': 'delete from blobs.doc_type where pk=%s', 1163 'args': [document_type['pk_doc_type']] 1164 }] 1165 ) 1166 return True
1167 1168 #------------------------------------------------------------
1169 -def get_ext_ref():
1170 """This needs *considerably* more smarts.""" 1171 dirname = gmTools.get_unique_filename ( 1172 prefix = '', 1173 suffix = time.strftime(".%Y%m%d-%H%M%S", time.localtime()) 1174 ) 1175 # extract name for dir 1176 path, doc_ID = os.path.split(dirname) 1177 return doc_ID
1178 1179 #============================================================ 1180 # main 1181 #------------------------------------------------------------ 1182 if __name__ == '__main__': 1183 1184 if len(sys.argv) < 2: 1185 sys.exit() 1186 1187 if sys.argv[1] != 'test': 1188 sys.exit() 1189 1190 #--------------------------------------------------------
1191 - def test_doc_types():
1192 1193 print("----------------------") 1194 print("listing document types") 1195 print("----------------------") 1196 1197 for dt in get_document_types(): 1198 print(dt) 1199 1200 print("------------------------------") 1201 print("testing document type handling") 1202 print("------------------------------") 1203 1204 dt = create_document_type(document_type = 'dummy doc type for unit test 1') 1205 print("created:", dt) 1206 1207 dt['type'] = 'dummy doc type for unit test 2' 1208 dt.save_payload() 1209 print("changed base name:", dt) 1210 1211 dt.set_translation(translation = 'Dummy-Dokumenten-Typ fuer Unit-Test') 1212 print("translated:", dt) 1213 1214 print("deleted:", delete_document_type(document_type = dt)) 1215 1216 return
1217 #--------------------------------------------------------
1218 - def test_adding_doc_part():
1219 1220 print("-----------------------") 1221 print("testing document import") 1222 print("-----------------------") 1223 1224 docs = search_for_documents(patient_id=12) 1225 doc = docs[0] 1226 print("adding to doc:", doc) 1227 1228 fname = sys.argv[1] 1229 print("adding from file:", fname) 1230 part = doc.add_part(file=fname) 1231 print("new part:", part) 1232 1233 return
1234 #--------------------------------------------------------
1235 - def test_get_documents():
1236 1237 doc_folder = cDocumentFolder(aPKey=12) 1238 1239 #photo = doc_folder.get_latest_mugshot() 1240 #print type(photo), photo 1241 1242 docs = doc_folder.get_documents() 1243 for doc in docs: 1244 #print type(doc), doc 1245 #print doc.parts 1246 #print doc.format_single_line() 1247 print('--------------------------') 1248 print(doc.format(single_line = True)) 1249 print(doc.format())
1250 1251 #--------------------------------------------------------
1252 - def test_get_useful_filename():
1253 pk = 12 1254 from Gnumed.business.gmPerson import cPatient 1255 pat = cPatient(pk) 1256 doc_folder = cDocumentFolder(aPKey = pk) 1257 for doc in doc_folder.documents: 1258 for part in doc.parts: 1259 print(part.get_useful_filename ( 1260 patient = pat, 1261 make_unique = True, 1262 directory = None, 1263 include_gnumed_tag = False, 1264 date_before_type = True, 1265 name_first = False 1266 ))
1267 1268 #--------------------------------------------------------
1269 - def test_part_metainfo_formatter():
1270 1271 #-------------------------------- 1272 def desc_printer(worker_result): 1273 status, desc = worker_result 1274 print('printer callback:') 1275 print(status) 1276 print(desc) 1277 print('<hit key> for next') 1278 return
1279 #-------------------------------- 1280 1281 pk = 12 1282 from Gnumed.business.gmPerson import cPatient 1283 pat = cPatient(pk) 1284 doc_folder = cDocumentFolder(aPKey = pk) 1285 for doc in doc_folder.documents: 1286 for part in doc.parts: 1287 part.format_metainfo(callback = desc_printer) 1288 input('waiting ...') 1289 # success, desc = part.format_metainfo() 1290 # print(success) 1291 # print(desc) 1292 # input('next') 1293 1294 # print(part.get_useful_filename ( 1295 # patient = pat, 1296 # make_unique = True, 1297 # directory = None, 1298 # include_gnumed_tag = False, 1299 # date_before_type = True, 1300 # name_first = False 1301 # )) 1302 1303 #-------------------------------------------------------- 1304 from Gnumed.pycommon import gmI18N 1305 gmI18N.activate_locale() 1306 gmI18N.install_domain() 1307 1308 #test_doc_types() 1309 #test_adding_doc_part() 1310 #test_get_documents() 1311 #test_get_useful_filename() 1312 test_part_metainfo_formatter() 1313 1314 # print get_ext_ref() 1315