def compare_versions(left_version, right_version): """ 0: left == right -1: left < right 1: left > right """ _log.debug('comparing [%s] with [%s]', left_version, right_version) if left_version == right_version: _log.debug('same version') return 0 if right_version in ['head', 'dev', 'devel']: _log.debug('development code') return -1 if left_version in ['head', 'dev', 'devel']: _log.debug('development code') return 1 left_parts = left_version.split('.') right_parts = right_version.split('.') tmp, left_major = gmTools.input2decimal('%s.%s' % (left_parts[0], left_parts[1])) tmp, right_major = gmTools.input2decimal('%s.%s' % (right_parts[0], right_parts[1])) if left_major < right_major: _log.debug('left version [%s] < right version [%s]: major part', left_version, right_version) return -1 if left_major > right_major: _log.debug('left version [%s] > right version [%s]: major part', left_version, right_version) return 1 tmp, left_part3 = gmTools.input2decimal(left_parts[2].replace('rc', '0.')) tmp, right_part3 = gmTools.input2decimal(right_parts[2].replace( 'rc', '0.')) if left_part3 < right_part3: _log.debug('left version [%s] < right version [%s]: minor part', left_version, right_version) return -1 if left_part3 > right_part3: _log.debug('left version [%s] > right version [%s]: minor part', left_version, right_version) return 1 return 0
def compare_versions(left_version, right_version): """ 0: left == right -1: left < right 1: left > right """ if left_version == right_version: _log.debug('same version: [%s] = [%s]', left_version, right_version) return 0 left_parts = left_version.split('.') right_parts = right_version.split('.') tmp, left_major = gmTools.input2decimal(u'%s.%s' % (left_parts[0], left_parts[1])) tmp, right_major = gmTools.input2decimal(u'%s.%s' % (right_parts[0], right_parts[1])) if left_major < right_major: _log.debug('left version [%s] < right version [%s]: major part', left_version, right_version) return -1 if left_major > right_major: _log.debug('left version [%s] > right version [%s]: major part', left_version, right_version) return 1 tmp, left_part3 = gmTools.input2decimal(left_parts[2].replace('rc', '0.')) tmp, right_part3 = gmTools.input2decimal(right_parts[2].replace( 'rc', '0.')) if left_part3 < right_part3: _log.debug('left version [%s] < right version [%s]: minor part', left_version, right_version) return -1 if left_part3 > right_part3: _log.debug('left version [%s] > right version [%s]: minor part', left_version, right_version) return 1 return 0
def compare_versions(left_version, right_version): """ 0: left == right -1: left < right 1: left > right """ if left_version == right_version: _log.debug('same version: [%s] = [%s]', left_version, right_version) return 0 left_parts = left_version.split('.') right_parts = right_version.split('.') tmp, left_major = gmTools.input2decimal(u'%s.%s' % (left_parts[0], left_parts[1])) tmp, right_major = gmTools.input2decimal(u'%s.%s' % (right_parts[0], right_parts[1])) if left_major < right_major: _log.debug('left version [%s] < right version [%s]: major part', left_version, right_version) return -1 if left_major > right_major: _log.debug('left version [%s] > right version [%s]: major part', left_version, right_version) return 1 tmp, left_part3 = gmTools.input2decimal(left_parts[2].replace('rc', '0.')) tmp, right_part3 = gmTools.input2decimal(right_parts[2].replace('rc', '0.')) if left_part3 < right_part3: _log.debug('left version [%s] < right version [%s]: minor part', left_version, right_version) return -1 if left_part3 > right_part3: _log.debug('left version [%s] > right version [%s]: minor part', left_version, right_version) return 1 return 0
def __import_single_PID_hl7_file(filename, emr=None): """Assumes single-PID/single-MSH HL7 file.""" _log.debug('importing single-PID single-MSH HL7 data from [%s]', filename) # read the file MSH_file = io.open(filename, mode = 'rt', encoding = 'utf8') HL7 = pyhl7.parse(MSH_file.read(1024 * 1024 * 5)) # 5 MB max MSH_file.close() # sanity checks if len(HL7.segments('MSH')) != 1: _log.error('more than one MSH segment') return False if len(HL7.segments('PID')) != 1: _log.error('more than one PID segment') return False # ensure lab is in database hl7_lab = HL7.extract_field('MSH', field_num = MSH_field__sending_lab) gm_lab = __find_or_create_lab(hl7_lab) # ensure test types exist conn = gmPG2.get_connection(readonly = False) __ensure_hl7_test_types_exist_in_gnumed(link_obj = conn, hl7_data = HL7, pk_test_org = gm_lab['pk_test_org']) # find patient if emr is None: #PID = HL7.segment('PID') pats = __PID2dto(HL7 = HL7) if len(pats) == 0: conn.rollback() return False if len(pats) > 1: conn.rollback() return False emr = pats[0].emr # import values: loop over segments when_list = {} current_result = None previous_segment = None had_errors = False msh_seen = False pid_seen = False last_obr = None obr = {} for seg_idx in range(len(HL7)): seg = HL7[seg_idx] seg_type = seg[0][0] _log.debug('processing line #%s = segment of type <%s>', seg_idx, seg_type) if seg_type == u'MSH': msh_seen = True if seg_type == u'PID': if not msh_seen: conn.rollback() _log.error('PID segment before MSH segment') return False pid_seen = True if seg_type in [u'MSH', u'PID']: _log.info('segment already handled') previous_segment = seg_type obr = {} current_result = None continue if seg_type in [u'ORC']: _log.info('currently ignoring %s segments', seg_type) previous_segment = seg_type obr = {} current_result = None continue if seg_type == u'OBR': previous_segment = seg_type last_obr = seg current_result = None obr['abbrev'] = (u'%s' % seg[OBR_field__service_name][0]).strip() try: obr['name'] = (u'%s' % seg[OBR_field__service_name][1]).strip() except IndexError: obr['name'] = obr['abbrev'] for field_name in [OBR_field__ts_ended, OBR_field__ts_started, OBR_field__ts_specimen_received, OBR_field__ts_requested]: obr['clin_when'] = seg[field_name][0].strip() if obr['clin_when'] != u'': break continue if seg_type == u'OBX': current_result = None # determine value val_alpha = seg[OBX_field__value][0].strip() is_num, val_num = gmTools.input2decimal(initial = val_alpha) if is_num: val_alpha = None else: val_num = None val_alpha = val_alpha.replace('\.br\\', u'\n') # determine test type unit = seg[OBX_field__unit][0].strip() if unit == u'': if is_num: unit = u'1/1' else: unit = None test_type = __find_or_create_test_type ( loinc = u'%s' % seg[OBX_field__type][0][OBX_component__loinc-1], name = u'%s' % seg[OBX_field__type][0][OBX_component__name-1], pk_lab = gm_lab['pk_test_org'], unit = unit ) # eventually, episode should be read from lab_request epi = emr.add_episode ( link_obj = conn, episode_name = u'administrative', is_open = False, allow_dupes = False ) current_result = emr.add_test_result ( link_obj = conn, episode = epi['pk_episode'], type = test_type['pk_test_type'], intended_reviewer = gmStaff.gmCurrentProvider()['pk_staff'], val_num = val_num, val_alpha = val_alpha, unit = unit ) # handle range information et al ref_range = seg[OBX_field__range][0].strip() if ref_range != u'': current_result.reference_range = ref_range flag = seg[OBX_field__abnormal_flag][0].strip() if flag != u'': current_result['abnormality_indicator'] = flag current_result['status'] = seg[OBX_field__status][0].strip() current_result['val_grouping'] = seg[OBX_field__subid][0].strip() current_result['source_data'] = u'' if last_obr is not None: current_result['source_data'] += unicode(last_obr) current_result['source_data'] += u'\n' current_result['source_data'] += unicode(seg) clin_when = seg[OBX_field__timestamp][0].strip() if clin_when == u'': _log.warning('no <Observation timestamp> in OBX, trying OBR timestamp') clin_when = obr['clin_when'] try: clin_when = __hl7dt2pydt(clin_when) except ValueError: _log.exception('clin_when from OBX or OBR not useable, assuming <today>') if clin_when is not None: current_result['clin_when'] = clin_when current_result.save(conn = conn) when_list[gmDateTime.pydt_strftime(current_result['clin_when'], '%Y %b %d')] = 1 previous_segment = seg_type continue if seg_type == u'NTE': note = seg[NET_field__note][0].strip().replace('\.br\\', u'\n') if note == u'': _log.debug('empty NTE segment') previous_segment = seg_type # maybe not ? (HL7 providers happen to use empty NTE segments to "structure" raw HL7 |-) continue # if this is an NTE following an OBR (IOW an order-related # comment): make this a test result all of its own :-) if previous_segment == u'OBR': _log.debug('NTE following OBR: general note, using OBR timestamp [%s]', obr['clin_when']) current_result = None name = obr['name'] if name == u'': name = _('Comment') # FIXME: please suggest a LOINC for "order comment" test_type = __find_or_create_test_type(name = name, pk_lab = gm_lab['pk_test_org'], abbrev = obr['abbrev']) # eventually, episode should be read from lab_request epi = emr.add_episode ( link_obj = conn, episode_name = u'administrative', is_open = False, allow_dupes = False ) nte_result = emr.add_test_result ( link_obj = conn, episode = epi['pk_episode'], type = test_type['pk_test_type'], intended_reviewer = gmStaff.gmCurrentProvider()['pk_staff'], val_alpha = note ) #nte_result['val_grouping'] = seg[OBX_field__subid][0].strip() nte_result['source_data'] = unicode(seg) try: nte_result['clin_when'] = __hl7dt2pydt(obr['clin_when']) except ValueError: _log.exception('no .clin_when from OBR for NTE pseudo-OBX available') nte_result.save(conn = conn) continue if (previous_segment == u'OBX') and (current_result is not None): current_result['source_data'] += u'\n' current_result['source_data'] += unicode(seg) current_result['note_test_org'] = gmTools.coalesce ( current_result['note_test_org'], note, u'%%s\n%s' % note ) current_result.save(conn = conn) previous_segment = seg_type continue _log.error(u'unexpected NTE segment') had_errors = True break _log.error('unknown segment, aborting') _log.debug('line: %s', seg) had_errors = True break if had_errors: conn.rollback() return False conn.commit() # record import in chart try: no_results = len(HL7.segments('OBX')) except KeyError: no_results = u'?' soap = _( 'Imported HL7 file [%s]:\n' ' lab "%s" (%s@%s), %s results (%s)' ) % ( filename, hl7_lab, gm_lab['unit'], gm_lab['organization'], no_results, u' / '.join(when_list.keys()) ) epi = emr.add_episode ( episode_name = u'administrative', is_open = False, allow_dupes = False ) emr.add_clin_narrative ( note = soap, soap_cat = None, episode = epi ) # keep copy of HL7 data in document archive folder = gmPerson.cPatient(emr.pk_patient).document_folder hl7_docs = folder.get_documents ( doc_type = u'HL7 data', episodes = [epi['pk_episode']], order_by = u'ORDER BY clin_when DESC' ) if len(hl7_docs) > 0: # there should only ever be one unless the user manually creates more, # also, it should always be the latest since "ORDER BY clin_when DESC" hl7_doc = hl7_docs[0] else: hl7_doc = folder.add_document ( document_type = u'HL7 data', encounter = emr.active_encounter['pk_encounter'], episode = epi['pk_episode'] ) hl7_doc['comment'] = _('list of imported HL7 data files') hl7_doc['clin_when'] = gmDateTime.pydt_now_here() hl7_doc.save() part = hl7_doc.add_part(file = filename) part['obj_comment'] = _('Result dates: %s') % u' / '.join(when_list.keys()) part.save() hl7_doc.set_reviewed(technically_abnormal = False, clinically_relevant = False) return True
def __import_single_PID_hl7_file(filename, emr=None): """Assumes single-PID/single-MSH HL7 file.""" _log.debug('importing single-PID single-MSH HL7 data from [%s]', filename) # read the file MSH_file = io.open(filename, mode = 'rt', encoding = 'utf8', newline = '') HL7 = pyhl7.parse(MSH_file.read(1024 * 1024 * 5)) # 5 MB max MSH_file.close() # sanity checks if len(HL7.segments('MSH')) != 1: _log.error('more than one MSH segment') return False if len(HL7.segments('PID')) != 1: _log.error('more than one PID segment') return False # ensure lab is in database hl7_lab = HL7.extract_field('MSH', field_num = MSH_field__sending_lab) gm_lab = __find_or_create_lab(hl7_lab) # ensure test types exist conn = gmPG2.get_connection(readonly = False) __ensure_hl7_test_types_exist_in_gnumed(link_obj = conn, hl7_data = HL7, pk_test_org = gm_lab['pk_test_org']) # find patient if emr is None: #PID = HL7.segment('PID') pats = __PID2dto(HL7 = HL7) if len(pats) == 0: conn.rollback() return False if len(pats) > 1: conn.rollback() return False emr = pats[0].emr # import values: loop over segments when_list = {} current_result = None previous_segment = None had_errors = False msh_seen = False pid_seen = False last_obr = None obr = {} for seg_idx in range(len(HL7)): seg = HL7[seg_idx] seg_type = seg[0][0] _log.debug('processing line #%s = segment of type <%s>', seg_idx, seg_type) if seg_type == 'MSH': msh_seen = True if seg_type == 'PID': if not msh_seen: conn.rollback() _log.error('PID segment before MSH segment') return False pid_seen = True if seg_type in ['MSH', 'PID']: _log.info('segment already handled') previous_segment = seg_type obr = {} current_result = None continue if seg_type in ['ORC']: _log.info('currently ignoring %s segments', seg_type) previous_segment = seg_type obr = {} current_result = None continue if seg_type == 'OBR': previous_segment = seg_type last_obr = seg current_result = None obr['abbrev'] = ('%s' % seg[OBR_field__service_name][0]).strip() try: obr['name'] = ('%s' % seg[OBR_field__service_name][1]).strip() except IndexError: obr['name'] = obr['abbrev'] for field_name in [OBR_field__ts_ended, OBR_field__ts_started, OBR_field__ts_specimen_received, OBR_field__ts_requested]: obr['clin_when'] = seg[field_name][0].strip() if obr['clin_when'] != '': break continue if seg_type == 'OBX': current_result = None # determine value val_alpha = seg[OBX_field__value][0].strip() is_num, val_num = gmTools.input2decimal(initial = val_alpha) if is_num: val_alpha = None else: val_num = None val_alpha = val_alpha.replace('\.br\\', '\n') # determine test type unit = seg[OBX_field__unit][0].strip() if unit == '': if is_num: unit = '1/1' else: unit = None test_type = __find_or_create_test_type ( loinc = '%s' % seg[OBX_field__type][0][OBX_component__loinc-1], name = '%s' % seg[OBX_field__type][0][OBX_component__name-1], pk_lab = gm_lab['pk_test_org'], unit = unit, link_obj = conn ) # eventually, episode should be read from lab_request epi = emr.add_episode ( link_obj = conn, episode_name = 'administrative', is_open = False, allow_dupes = False ) current_result = emr.add_test_result ( link_obj = conn, episode = epi['pk_episode'], type = test_type['pk_test_type'], intended_reviewer = gmStaff.gmCurrentProvider()['pk_staff'], val_num = val_num, val_alpha = val_alpha, unit = unit ) # handle range information et al ref_range = seg[OBX_field__range][0].strip() if ref_range != '': current_result.reference_range = ref_range flag = seg[OBX_field__abnormal_flag][0].strip() if flag != '': current_result['abnormality_indicator'] = flag current_result['status'] = seg[OBX_field__status][0].strip() current_result['val_grouping'] = seg[OBX_field__subid][0].strip() current_result['source_data'] = '' if last_obr is not None: current_result['source_data'] += str(last_obr) current_result['source_data'] += '\n' current_result['source_data'] += str(seg) clin_when = seg[OBX_field__timestamp][0].strip() if clin_when == '': _log.warning('no <Observation timestamp> in OBX, trying OBR timestamp') clin_when = obr['clin_when'] try: clin_when = __hl7dt2pydt(clin_when) except ValueError: _log.exception('clin_when from OBX or OBR not useable, assuming <today>') if clin_when is not None: current_result['clin_when'] = clin_when current_result.save(conn = conn) when_list[gmDateTime.pydt_strftime(current_result['clin_when'], '%Y %b %d')] = 1 previous_segment = seg_type continue if seg_type == 'NTE': note = seg[NET_field__note][0].strip().replace('\.br\\', '\n') if note == '': _log.debug('empty NTE segment') previous_segment = seg_type # maybe not ? (HL7 providers happen to use empty NTE segments to "structure" raw HL7 |-) continue # if this is an NTE following an OBR (IOW an order-related # comment): make this a test result all of its own :-) if previous_segment == 'OBR': _log.debug('NTE following OBR: general note, using OBR timestamp [%s]', obr['clin_when']) current_result = None name = obr['name'] if name == '': name = _('Comment') # FIXME: please suggest a LOINC for "order comment" test_type = __find_or_create_test_type(name = name, pk_lab = gm_lab['pk_test_org'], abbrev = obr['abbrev'], link_obj = conn) # eventually, episode should be read from lab_request epi = emr.add_episode ( link_obj = conn, episode_name = 'administrative', is_open = False, allow_dupes = False ) nte_result = emr.add_test_result ( link_obj = conn, episode = epi['pk_episode'], type = test_type['pk_test_type'], intended_reviewer = gmStaff.gmCurrentProvider()['pk_staff'], val_alpha = note ) #nte_result['val_grouping'] = seg[OBX_field__subid][0].strip() nte_result['source_data'] = str(seg) try: nte_result['clin_when'] = __hl7dt2pydt(obr['clin_when']) except ValueError: _log.exception('no .clin_when from OBR for NTE pseudo-OBX available') nte_result.save(conn = conn) continue if (previous_segment == 'OBX') and (current_result is not None): current_result['source_data'] += '\n' current_result['source_data'] += str(seg) current_result['note_test_org'] = gmTools.coalesce ( current_result['note_test_org'], note, '%%s\n%s' % note ) current_result.save(conn = conn) previous_segment = seg_type continue _log.error('unexpected NTE segment') had_errors = True break _log.error('unknown segment, aborting') _log.debug('line: %s', seg) had_errors = True break if had_errors: conn.rollback() return False conn.commit() # record import in chart try: no_results = len(HL7.segments('OBX')) except KeyError: no_results = '?' soap = _( 'Imported HL7 file [%s]:\n' ' lab "%s" (%s@%s), %s results (%s)' ) % ( filename, hl7_lab, gm_lab['unit'], gm_lab['organization'], no_results, ' / '.join(list(when_list)) ) epi = emr.add_episode ( episode_name = 'administrative', is_open = False, allow_dupes = False ) emr.add_clin_narrative ( note = soap, soap_cat = None, episode = epi ) # keep copy of HL7 data in document archive folder = gmPerson.cPatient(emr.pk_patient).document_folder hl7_docs = folder.get_documents ( doc_type = 'HL7 data', pk_episodes = [epi['pk_episode']], order_by = 'ORDER BY clin_when DESC' ) if len(hl7_docs) > 0: # there should only ever be one unless the user manually creates more, # also, it should always be the latest since "ORDER BY clin_when DESC" hl7_doc = hl7_docs[0] else: hl7_doc = folder.add_document ( document_type = 'HL7 data', encounter = emr.active_encounter['pk_encounter'], episode = epi['pk_episode'] ) hl7_doc['comment'] = _('list of imported HL7 data files') hl7_doc['pk_org_unit'] = gmPraxis.gmCurrentPraxisBranch()['pk_org_unit'] hl7_doc['clin_when'] = gmDateTime.pydt_now_here() hl7_doc.save() part = hl7_doc.add_part(file = filename) part['obj_comment'] = _('Result dates: %s') % ' / '.join(list(when_list)) part.save() hl7_doc.set_reviewed(technically_abnormal = False, clinically_relevant = False) return True
def create_sql(filename): csv_file = open(filename, mode='rt', encoding='utf-8-sig') csv_lines = gmTools.unicode_csv_reader(csv_file, fieldnames=field_names, delimiter=';', quotechar='"', dict=True) print SQL_start line_idx = 0 skip_line = False for line in csv_lines: line_idx += 1 print "-- line #%s" % line_idx # normalize field content for field in field_names: try: line[field] = line[field].strip().strip(';,').strip().replace( "'", "''") except AttributeError: # trailing fields are a list pass # verify required fields for field in non_empty_fields: if line[field] == '': print "-- ignoring line: empty field [%s]" % field print "--", line print "" skip_line = True break if skip_line: skip_line = False continue # verify numeric fields for field in numeric_fields: if line[field] == '': continue success, num_val = gmTools.input2decimal(initial=line[field]) if not success: print "-- ignoring line: field [%s] not numeric: >>>%s<<<" % ( field, line[field]) print "--", line print "" skip_line = True break line[field] = num_val if skip_line: skip_line = False continue # actually create SQL # loop over strengths for field in numeric_fields: if line[field] == '': continue line['brand_name'] = ('%%(product)s %%(%s)s (%%(company)s)' % field) % line line['strength'] = line[field] print SQL_stage_drug % line print SQL_end
def create_sql(filename): csv_file = io.open(filename, mode = 'rt', encoding = u'utf8') csv_lines = gmTools.unicode_csv_reader ( csv_file, fieldnames = field_names, delimiter = ';', quotechar = '"', dict = True ) print SQL_start line_idx = 0 skip_line = False for line in csv_lines: line_idx += 1 print "-- line #%s" % line_idx # normalize field content for field in field_names: try: line[field] = line[field].strip().strip(u';,').strip().replace(u"'", u"''") except AttributeError: # trailing fields are a list pass # verify required fields for field in non_empty_fields: if line[field] == u'': print "-- ignoring line: empty field [%s]" % field print "--", line print "" skip_line = True break if skip_line: skip_line = False continue # verify numeric fields for field in numeric_fields: if line[field] == u'': continue success, num_val = gmTools.input2decimal(initial = line[field]) if not success: print "-- ignoring line: field [%s] not numeric: >>>%s<<<" % (field, line[field]) print "--", line print "" skip_line = True break line[field] = num_val if skip_line: skip_line = False continue # actually create SQL # loop over strengths for field in numeric_fields: if line[field] == u'': continue line['brand_name'] = (u'%%(brand)s %%(%s)s (%%(company)s)' % field) % line line['strength'] = line[field] print SQL_stage_drug % line print SQL_end