Package Gnumed :: Package exporters :: Module gmTimelineExporter
[frames] | no frames]

Source Code for Module Gnumed.exporters.gmTimelineExporter

  1  # -*- coding: utf8 -*- 
  2  """Timeline exporter. 
  3   
  4  Copyright: authors 
  5  """ 
  6  #============================================================ 
  7  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>" 
  8  __license__ = 'GPL v2 or later (details at http://www.gnu.org)' 
  9   
 10  import sys 
 11  import logging 
 12  import io 
 13  import os 
 14   
 15   
 16  if __name__ == '__main__': 
 17          sys.path.insert(0, '../../') 
 18          from Gnumed.pycommon import gmI18N 
 19  from Gnumed.pycommon import gmTools 
 20  from Gnumed.pycommon import gmDateTime 
 21   
 22   
 23  _log = logging.getLogger('gm.tl') 
 24   
 25  #============================================================ 
 26  ERA_NAME_CARE_PERIOD = _('Care Period') 
 27   
 28  #============================================================ 
 29   
 30  # <icon>base-64 encoded PNG image data</icon> 
 31   
 32  #============================================================ 
 33  xml_start = """<?xml version="1.0" encoding="utf-8"?> 
 34  <timeline> 
 35          <version>1.20.0</version> 
 36          <timetype>gregoriantime</timetype> 
 37          <!-- ======================================== Eras ======================================== --> 
 38          <eras> 
 39                  <era> 
 40                          <name>%s</name> 
 41                          <start>%s</start> 
 42                          <end>%s</end> 
 43                          <color>205,238,241</color> 
 44                          <ends_today>%s</ends_today> 
 45                  </era> 
 46                  <era> 
 47                          <name>%s</name> 
 48                          <start>%s</start> 
 49                          <end>%s</end> 
 50                          <color>161,210,226</color> 
 51                          <ends_today>%s</ends_today> 
 52                  </era> 
 53          </eras> 
 54          <!-- ======================================== Categories ======================================== --> 
 55          <categories> 
 56                  <!-- health issues --> 
 57                  <category> 
 58                          <name>%s</name> 
 59                          <color>255,0,0</color> 
 60                          <font_color>0,0,0</font_color> 
 61                  </category> 
 62                  <!-- episodes --> 
 63                  <category> 
 64                          <name>%s</name> 
 65                          <color>0,255,0</color> 
 66                          <font_color>0,0,0</font_color> 
 67                  </category> 
 68                  <!-- encounters --> 
 69                  <category> 
 70                          <name>%s</name> 
 71                          <color>30,144,255</color> 
 72                          <font_color>0,0,0</font_color> 
 73                  </category> 
 74                  <!-- hospital stays --> 
 75                  <category> 
 76                          <name>%s</name> 
 77                          <color>255,255,0</color> 
 78                          <font_color>0,0,0</font_color> 
 79                  </category> 
 80                  <!-- procedures --> 
 81                  <category> 
 82                          <name>%s</name> 
 83                          <color>160,32,140</color> 
 84                          <font_color>0,0,0</font_color> 
 85                  </category> 
 86                  <!-- documents --> 
 87                  <category> 
 88                          <name>%s</name> 
 89                          <color>255,165,0</color> 
 90                          <font_color>0,0,0</font_color> 
 91                  </category> 
 92                  <!-- vaccinations --> 
 93                  <category> 
 94                          <name>%s</name> 
 95                          <color>144,238,144</color> 
 96                          <font_color>0,0,0</font_color> 
 97                  </category> 
 98                  <!-- substance intake --> 
 99                  <category> 
100                          <name>%s</name> 
101                          <color>165,42,42</color> 
102                          <font_color>0,0,0</font_color> 
103                  </category> 
104                  <!-- life events --> 
105                  <category> 
106                          <name>%s</name> 
107                          <color>30,144,255</color> 
108                          <font_color>0,0,0</font_color> 
109                  </category> 
110          </categories> 
111          <!-- ======================================== Events ======================================== --> 
112          <events>""" 
113   
114  xml_end = """ 
115          </events> 
116          <view> 
117                  <displayed_period> 
118                          <start>%s</start> 
119                          <end>%s</end> 
120                  </displayed_period> 
121          <hidden_categories> 
122          </hidden_categories> 
123          </view> 
124  </timeline>""" 
125   
126  #============================================================ 
127 -def format_pydt(pydt, format = '%Y-%m-%d %H:%M:%S'):
128 return gmDateTime.pydt_strftime(pydt, format = format, accuracy = gmDateTime.acc_seconds)
129 130 #------------------------------------------------------------ 131 # health issues 132 #------------------------------------------------------------ 133 __xml_issue_template = """ 134 <event> 135 <start>%(start)s</start> 136 <end>%(end)s</end> 137 <text>%(container_id)s%(label)s</text> 138 <fuzzy>%(fuzzy)s</fuzzy> 139 <locked>True</locked> 140 <ends_today>%(ends2day)s</ends_today> 141 <category>%(category)s</category> 142 <description>%(desc)s</description> 143 </event>""" 144
145 -def __format_health_issue_as_timeline_xml(issue, patient, emr):
146 # container IDs are supposed to be numeric 147 # 85bd7a14a1e74aab8db072ff8f417afb@H30.rldata.local 148 data = {'category': _('Health issues')} 149 possible_start = issue.possible_start_date 150 safe_start = issue.safe_start_date 151 end = issue.clinical_end_date 152 ends_today = 'False' 153 if end is None: 154 # open episode or active 155 ends_today = 'True' 156 end = now 157 # somewhat hacky and not really correct: 158 start2use = safe_start 159 if safe_start > end: 160 if possible_start < end: 161 start2use = possible_start 162 else: 163 start2use = end 164 data['desc'] = gmTools.xml_escape_string(issue.format ( 165 patient = patient, 166 with_summary = True, 167 with_codes = True, 168 with_episodes = True, 169 with_encounters = False, 170 with_medications = False, 171 with_hospital_stays = False, 172 with_procedures = False, 173 with_family_history = False, 174 with_documents = False, 175 with_tests = False, 176 with_vaccinations = False 177 ).strip().strip('\n').strip()) 178 label = gmTools.shorten_words_in_line(text = issue['description'], max_length = 25, min_word_length = 5) 179 xml = '' 180 # if possible_start < safe_start: 181 # data['start'] = format_pydt(possible_start) 182 # data['end'] = format_pydt(safe_start) 183 # data['ends2day'] = 'False' 184 # data['fuzzy'] = 'True' 185 # data['container_id'] = '' 186 # data['label'] = '?%s?' % gmTools.xml_escape_string(label) 187 # xml += __xml_issue_template % data 188 data['start'] = format_pydt(start2use) 189 data['end'] = format_pydt(end) 190 data['ends2day'] = ends_today 191 data['fuzzy'] = 'False' 192 data['container_id'] = '[%s]' % issue['pk_health_issue'] 193 data['label'] = gmTools.xml_escape_string(label) 194 xml += __xml_issue_template % data 195 return xml
196 197 #------------------------------------------------------------ 198 # episodes 199 #------------------------------------------------------------ 200 __xml_episode_template = """ 201 <event> 202 <start>%(start)s</start> 203 <end>%(end)s</end> 204 <text>%(container_id)s%(label)s</text> 205 <progress>%(progress)s</progress> 206 <fuzzy>False</fuzzy> 207 <locked>True</locked> 208 <ends_today>%(ends2day)s</ends_today> 209 <category>%(category)s</category> 210 <description>%(desc)s</description> 211 </event>""" 212
213 -def __format_episode_as_timeline_xml(episode, patient):
214 data = { 215 'category': _('Episodes'), 216 'start': format_pydt(episode.best_guess_clinical_start_date), 217 'container_id': gmTools.coalesce ( 218 value2test = episode['pk_health_issue'], 219 return_instead = '', 220 template4value = '(%s)' 221 ), 222 'label': gmTools.xml_escape_string ( 223 gmTools.shorten_words_in_line(text = episode['description'], max_length = 20, min_word_length = 5) 224 ), 225 'ends2day': gmTools.bool2subst(episode['episode_open'], 'True', 'False'), 226 'progress': gmTools.bool2subst(episode['episode_open'], '0', '100'), 227 'desc': gmTools.xml_escape_string(episode.format ( 228 patient = patient, 229 with_summary = True, 230 with_codes = True, 231 with_encounters = True, 232 with_documents = False, 233 with_hospital_stays = False, 234 with_procedures = False, 235 with_family_history = False, 236 with_tests = False, 237 with_vaccinations = False, 238 with_health_issue = True 239 ).strip().strip('\n').strip()) 240 } 241 end = episode.best_guess_clinical_end_date 242 if end is None: 243 data['end'] = format_pydt(now) 244 else: 245 data['end'] = format_pydt(end) 246 return __xml_episode_template % data
247 248 #------------------------------------------------------------ 249 # encounters 250 #------------------------------------------------------------ 251 __xml_encounter_template = """ 252 <event> 253 <start>%s</start> 254 <end>%s</end> 255 <text>%s</text> 256 <progress>0</progress> 257 <fuzzy>False</fuzzy> 258 <locked>True</locked> 259 <ends_today>False</ends_today> 260 <category>%s</category> 261 <description>%s</description> 262 <milestone>%s</milestone> 263 </event>""" 264
265 -def __format_encounter_as_timeline_xml(encounter, patient):
266 return __xml_encounter_template % ( 267 format_pydt(encounter['started']), 268 format_pydt(encounter['last_affirmed']), 269 #u'(%s)' % encounter['pk_episode'], 270 gmTools.xml_escape_string(format_pydt(encounter['started'], format = '%b %d')), 271 _('Encounters'), # category 272 gmTools.xml_escape_string(encounter.format ( 273 patient = patient, 274 with_soap = True, 275 with_docs = False, 276 with_tests = False, 277 fancy_header = False, 278 with_vaccinations = False, 279 with_co_encountlet_hints = False, 280 with_rfe_aoe = True, 281 with_family_history = False 282 ).strip().strip('\n').strip()), 283 'False' 284 )
285 286 #------------------------------------------------------------ 287 # hospital stays 288 #------------------------------------------------------------ 289 __xml_hospital_stay_template = """ 290 <event> 291 <start>%s</start> 292 <end>%s</end> 293 <text>%s</text> 294 <fuzzy>False</fuzzy> 295 <locked>True</locked> 296 <ends_today>False</ends_today> 297 <category>%s</category> 298 <description>%s</description> 299 </event>""" 300
301 -def __format_hospital_stay_as_timeline_xml(stay):
302 end = stay['discharge'] 303 if end is None: 304 end = now 305 return __xml_hospital_stay_template % ( 306 format_pydt(stay['admission']), 307 format_pydt(end), 308 gmTools.xml_escape_string(stay['hospital']), 309 _('Hospital stays'), # category 310 gmTools.xml_escape_string(stay.format().strip().strip('\n').strip()) 311 )
312 313 #------------------------------------------------------------ 314 # procedures 315 #------------------------------------------------------------ 316 __xml_procedure_template = """ 317 <event> 318 <start>%s</start> 319 <end>%s</end> 320 <text>%s</text> 321 <fuzzy>False</fuzzy> 322 <locked>True</locked> 323 <ends_today>False</ends_today> 324 <category>%s</category> 325 <description>%s</description> 326 </event>""" 327
328 -def __format_procedure_as_timeline_xml(proc):
329 if proc['is_ongoing']: 330 end = now 331 else: 332 if proc['clin_end'] is None: 333 end = proc['clin_when'] 334 else: 335 end = proc['clin_end'] 336 desc = gmTools.shorten_words_in_line(text = proc['performed_procedure'], max_length = 20, min_word_length = 5) 337 return __xml_procedure_template % ( 338 format_pydt(proc['clin_when']), 339 format_pydt(end), 340 gmTools.xml_escape_string(desc), 341 _('Procedures'), 342 gmTools.xml_escape_string(proc.format ( 343 include_episode = True, 344 include_codes = True 345 ).strip().strip('\n').strip()) 346 )
347 348 #------------------------------------------------------------ 349 # documents 350 #------------------------------------------------------------ 351 __xml_document_template = """ 352 <event> 353 <start>%s</start> 354 <end>%s</end> 355 <text>%s</text> 356 <fuzzy>False</fuzzy> 357 <locked>True</locked> 358 <ends_today>False</ends_today> 359 <category>%s</category> 360 <description>%s</description> 361 </event>""" 362
363 -def __format_document_as_timeline_xml(doc):
364 desc = gmTools.shorten_words_in_line(text = doc['l10n_type'], max_length = 20, min_word_length = 5) 365 return __xml_document_template % ( 366 format_pydt(doc['clin_when']), 367 format_pydt(doc['clin_when']), 368 gmTools.xml_escape_string(desc), 369 _('Documents'), 370 gmTools.xml_escape_string(doc.format().strip().strip('\n').strip()) 371 )
372 373 #------------------------------------------------------------ 374 # vaccinations 375 #------------------------------------------------------------ 376 __xml_vaccination_template = """ 377 <event> 378 <start>%s</start> 379 <end>%s</end> 380 <text>%s</text> 381 <fuzzy>False</fuzzy> 382 <locked>True</locked> 383 <ends_today>False</ends_today> 384 <category>%s</category> 385 <description>%s</description> 386 </event>""" 387
388 -def __format_vaccination_as_timeline_xml(vacc):
389 return __xml_vaccination_template % ( 390 format_pydt(vacc['date_given']), 391 format_pydt(vacc['date_given']), 392 gmTools.xml_escape_string(vacc['vaccine']), 393 _('Vaccinations'), 394 gmTools.xml_escape_string('\n'.join(vacc.format ( 395 with_indications = True, 396 with_comment = True, 397 with_reaction = True, 398 date_format = '%Y %b %d' 399 )).strip().strip('\n').strip()) 400 )
401 402 #------------------------------------------------------------ 403 # substance intake 404 #------------------------------------------------------------ 405 __xml_intake_template = """ 406 <event> 407 <start>%s</start> 408 <end>%s</end> 409 <text>%s</text> 410 <fuzzy>False</fuzzy> 411 <locked>True</locked> 412 <ends_today>False</ends_today> 413 <category>%s</category> 414 <description>%s</description> 415 </event>""" 416
417 -def __format_intake_as_timeline_xml(intake):
418 if intake['discontinued'] is None: 419 if intake['duration'] is None: 420 if intake['seems_inactive']: 421 end = intake['started'] 422 else: 423 end = now 424 else: 425 end = intake['started'] + intake['duration'] 426 else: 427 end = intake['discontinued'] 428 429 return __xml_intake_template % ( 430 format_pydt(intake['started']), 431 format_pydt(end), 432 gmTools.xml_escape_string(intake['substance']), 433 _('Substances'), 434 gmTools.xml_escape_string(intake.format ( 435 single_line = False, 436 show_all_product_components = False 437 ).strip().strip('\n').strip()) 438 )
439 440 #------------------------------------------------------------ 441 # main library entry point 442 #------------------------------------------------------------
443 -def create_timeline_file(patient=None, filename=None, include_documents=False, include_vaccinations=False, include_encounters=False):
444 445 emr = patient.emr 446 global now 447 now = gmDateTime.pydt_now_here() 448 449 if filename is None: 450 timeline_fname = gmTools.get_unique_filename(prefix = 'gm-', suffix = '.timeline') # .timeline required ... 451 else: 452 timeline_fname = filename 453 _log.debug('exporting EMR as timeline into [%s]', timeline_fname) 454 timeline = io.open(timeline_fname, mode = 'wt', encoding = 'utf8', errors = 'xmlcharrefreplace') 455 456 if patient['dob'] is None: 457 lifespan_start = format_pydt(now.replace(year = now.year - 100)) 458 else: 459 lifespan_start = format_pydt(patient['dob']) 460 461 if patient['deceased'] is None: 462 life_ends2day = 'True' 463 lifespan_end = format_pydt(now) 464 else: 465 life_ends2day = 'False' 466 lifespan_end = format_pydt(patient['deceased']) 467 468 earliest_care_date = emr.earliest_care_date 469 most_recent_care_date = emr.most_recent_care_date 470 if most_recent_care_date is None: 471 most_recent_care_date = lifespan_end 472 care_ends2day = life_ends2day 473 else: 474 most_recent_care_date = format_pydt(most_recent_care_date) 475 care_ends2day = 'False' 476 477 timeline.write(xml_start % ( 478 # era: life span of patient 479 _('Lifespan'), 480 lifespan_start, 481 lifespan_end, 482 life_ends2day, 483 ERA_NAME_CARE_PERIOD, 484 format_pydt(earliest_care_date), 485 most_recent_care_date, 486 care_ends2day, 487 # categories 488 _('Health issues'), 489 _('Episodes'), 490 _('Encounters'), 491 _('Hospital stays'), 492 _('Procedures'), 493 _('Documents'), 494 _('Vaccinations'), 495 _('Substances'), 496 _('Life events') 497 )) 498 # birth 499 if patient['dob'] is None: 500 start = now.replace(year = now.year - 100) 501 timeline.write(__xml_encounter_template % ( 502 format_pydt(start), 503 format_pydt(start), 504 '?', 505 _('Life events'), 506 _('Date of birth unknown'), 507 'True' 508 )) 509 else: 510 start = patient['dob'] 511 timeline.write(__xml_encounter_template % ( 512 format_pydt(patient['dob']), 513 format_pydt(patient['dob']), 514 '*', 515 _('Life events'), 516 _('Birth: %s') % patient.get_formatted_dob(format = '%Y %b %d %H:%M', honor_estimation = True), 517 'True' 518 )) 519 520 # start of care 521 timeline.write(__xml_encounter_template % ( 522 format_pydt(earliest_care_date), 523 format_pydt(earliest_care_date), 524 gmTools.u_heavy_greek_cross, 525 _('Life events'), 526 _('Start of Care: %s\n(the earliest recorded event of care in this praxis)') % format_pydt(earliest_care_date, format = '%Y %b %d'), 527 'True' 528 )) 529 530 # containers must be defined before their 531 # subevents, so put health issues first 532 timeline.write('\n <!-- ========================================\n Health issues\n======================================== -->') 533 for issue in emr.health_issues: 534 timeline.write(__format_health_issue_as_timeline_xml(issue, patient, emr)) 535 536 timeline.write('\n <!-- ========================================\n Episodes\n======================================== -->') 537 for epi in emr.get_episodes(order_by = 'pk_health_issue'): 538 timeline.write(__format_episode_as_timeline_xml(epi, patient)) 539 540 if include_encounters: 541 timeline.write(u'\n<!--\n========================================\n Encounters\n======================================== -->') 542 for enc in emr.get_encounters(skip_empty = True): 543 timeline.write(__format_encounter_as_timeline_xml(enc, patient)) 544 545 timeline.write('\n<!--\n========================================\n Hospital stays\n======================================== -->') 546 for stay in emr.hospital_stays: 547 timeline.write(__format_hospital_stay_as_timeline_xml(stay)) 548 549 timeline.write('\n<!--\n========================================\n Procedures\n======================================== -->') 550 for proc in emr.performed_procedures: 551 timeline.write(__format_procedure_as_timeline_xml(proc)) 552 553 if include_vaccinations: 554 timeline.write(u'\n<!--\n========================================\n Vaccinations\n======================================== -->') 555 for vacc in emr.vaccinations: 556 timeline.write(__format_vaccination_as_timeline_xml(vacc)) 557 558 timeline.write('\n<!--\n========================================\n Substance intakes\n======================================== -->') 559 for intake in emr.get_current_medications(include_inactive = True, include_unapproved = False): 560 timeline.write(__format_intake_as_timeline_xml(intake)) 561 562 if include_documents: 563 timeline.write(u'\n<!--\n========================================\n Documents\n======================================== -->') 564 for doc in patient.document_folder.documents: 565 timeline.write(__format_document_as_timeline_xml(doc)) 566 567 # allergies ? 568 # - unclear where and how to place 569 # test results ? 570 # - too many events, at most "day sample drawn" 571 572 # death 573 if patient['deceased'] is None: 574 end = now 575 else: 576 end = patient['deceased'] 577 death_ago = gmDateTime.format_apparent_age_medically ( 578 age = gmDateTime.calculate_apparent_age(start = end, end = now) 579 ) 580 timeline.write(__xml_encounter_template % ( 581 format_pydt(end), 582 format_pydt(end), 583 gmTools.u_dagger, 584 _('Life events'), 585 _('Death: %s\n(%s ago at age %s)') % ( 586 format_pydt(end, format = '%Y %b %d %H:%M'), 587 death_ago, 588 patient.get_medical_age() 589 ), 590 'True' 591 )) 592 593 # display range 594 if end.month == 2: 595 if end.day == 29: 596 # leap years aren't consecutive 597 end = end.replace(day = 28) 598 target_year = end.year + 1 599 end = end.replace(year = target_year) 600 timeline.write(xml_end % ( 601 format_pydt(start), 602 format_pydt(end) 603 )) 604 605 timeline.close() 606 return timeline_fname
607 608 #------------------------------------------------------------ 609 __fake_timeline_start = """<?xml version="1.0" encoding="utf-8"?> 610 <timeline> 611 <version>0.20.0</version> 612 <categories> 613 <!-- life events --> 614 <category> 615 <name>%s</name> 616 <color>30,144,255</color> 617 <font_color>0,0,0</font_color> 618 </category> 619 </categories> 620 <events>""" % _('Life events') 621 622 __fake_timeline_body_template = """ 623 <event> 624 <start>%s</start> 625 <end>%s</end> 626 <text>%s</text> 627 <fuzzy>False</fuzzy> 628 <locked>True</locked> 629 <ends_today>False</ends_today> 630 <!-- category></category --> 631 <description>%s 632 </description> 633 </event>""" 634
635 -def create_fake_timeline_file(patient=None, filename=None):
636 """Used to create an 'empty' timeline file for display. 637 638 - needed because .clear_timeline() doesn't really work 639 """ 640 emr = patient.emr 641 global now 642 now = gmDateTime.pydt_now_here() 643 644 if filename is None: 645 timeline_fname = gmTools.get_unique_filename(prefix = 'gm-', suffix = '.timeline') 646 else: 647 timeline_fname = filename 648 649 _log.debug('creating dummy timeline in [%s]', timeline_fname) 650 timeline = io.open(timeline_fname, mode = 'wt', encoding = 'utf8', errors = 'xmlcharrefreplace') 651 652 timeline.write(__fake_timeline_start) 653 654 # birth 655 if patient['dob'] is None: 656 start = now.replace(year = now.year - 100) 657 timeline.write(__xml_encounter_template % ( 658 format_pydt(start), 659 format_pydt(start), 660 _('Birth') + ': ?', 661 _('Life events'), 662 _('Date of birth unknown'), 663 'False' 664 )) 665 else: 666 start = patient['dob'] 667 timeline.write(__xml_encounter_template % ( 668 format_pydt(patient['dob']), 669 format_pydt(patient['dob']), 670 _('Birth') + gmTools.bool2subst(patient['dob_is_estimated'], ' (%s)' % gmTools.u_almost_equal_to, ''), 671 _('Life events'), 672 '', 673 'False' 674 )) 675 676 # death 677 if patient['deceased'] is None: 678 end = now 679 else: 680 end = patient['deceased'] 681 timeline.write(__xml_encounter_template % ( 682 format_pydt(end), 683 format_pydt(end), 684 #u'', 685 _('Death'), 686 _('Life events'), 687 '', 688 'False' 689 )) 690 691 # fake issue 692 timeline.write(__fake_timeline_body_template % ( 693 format_pydt(start), 694 format_pydt(end), 695 _('Cannot display timeline.'), 696 _('Cannot display timeline.') 697 )) 698 699 # display range 700 if end.month == 2: 701 if end.day == 29: 702 # leap years aren't consecutive 703 end = end.replace(day = 28) 704 target_year = end.year + 1 705 end = end.replace(year = target_year) 706 timeline.write(xml_end % ( 707 format_pydt(start), 708 format_pydt(end) 709 )) 710 711 timeline.close() 712 return timeline_fname
713 714 #============================================================ 715 # main 716 #------------------------------------------------------------ 717 if __name__ == '__main__': 718 719 if len(sys.argv) < 2: 720 sys.exit() 721 722 if sys.argv[1] != "test": 723 sys.exit() 724 725 gmI18N.activate_locale() 726 gmI18N.install_domain('gnumed') 727 728 from Gnumed.business import gmPraxis 729 praxis = gmPraxis.gmCurrentPraxisBranch(branch = gmPraxis.get_praxis_branches()[0]) 730 731 from Gnumed.business import gmPerson 732 # 14 / 20 / 138 / 58 / 20 / 5 733 pat = gmPerson.gmCurrentPatient(gmPerson.cPatient(aPK_obj = 14)) 734 fname = '~/gnumed/gm2tl-%s.timeline' % pat.subdir_name 735 736 print (create_timeline_file ( 737 patient = pat, 738 filename = os.path.expanduser(fname), 739 include_documents = True, 740 include_vaccinations = True, 741 include_encounters = True 742 )) 743