def test_generic_codes_prw(): gmPG2.get_connection() app = wx.PyWidgetTester(size = (500, 40)) pw = cGenericCodesPhraseWheel(app.frame, -1) #pw.set_context(context = u'zip', val = u'04318') app.frame.Show(True) app.MainLoop()
def create_vaccine(pk_drug_product=None, product_name=None, indications=None, is_live=None): assert (is_live is not None), '<is_live> must not be <None>' conn = gmPG2.get_connection(readonly = False) if pk_drug_product is None: #prep = _('vaccine') prep = 'vaccine' _log.debug('creating vaccine drug product [%s %s]', product_name, prep) vacc_prod = gmMedication.create_drug_product ( product_name = product_name, preparation = prep, return_existing = True, # indications are ref.dose rows doses = indications, link_obj = conn ) #conn.commit() vacc_prod['atc'] = 'J07' vacc_prod.save(conn = conn) pk_drug_product = vacc_prod['pk_drug_product'] cmd = 'INSERT INTO ref.vaccine (fk_drug_product, is_live) values (%(pk_drug_product)s, %(live)s) RETURNING pk' queries = [{'cmd': cmd, 'args': {'pk_drug_product': pk_drug_product, 'live': is_live}}] rows, idx = gmPG2.run_rw_queries(link_obj = conn, queries = queries, get_col_idx = False, return_data = True, end_tx = True) conn.close() return cVaccine(aPK_obj = rows[0]['pk'])
def set(self, workplace = None, cookie = None, option = None, value = None): """Set (insert or update) option value in database. Any parameter that is None will be set to the database default. Note: you can't change the type of a parameter once it has been created in the backend. If you want to change the type you will have to delete the parameter and recreate it using the new type. """ # sanity checks if None in [option, value]: raise ValueError('invalid arguments (option=<%s>, value=<%s>)' % (option, value)) rw_conn = gmPG2.get_connection(readonly=False) alias = self.__make_alias(workplace, 'CURRENT_USER', cookie, option) opt_value = value sql_type_cast = u'' if isinstance(value, basestring): sql_type_cast = u'::text' elif isinstance(value, types.BooleanType): opt_value = int(opt_value) elif isinstance(value, (types.FloatType, types.IntType, types.LongType, decimal.Decimal, types.BooleanType)): sql_type_cast = u'::numeric' elif isinstance(value, types.ListType): # there can be different syntaxes for list types so don't try to cast them pass elif isinstance(value, types.BufferType): # can go directly into bytea pass else: try: opt_value = gmPG2.dbapi.Binary(pickle.dumps(value)) sql_type_cast = '::bytea' except pickle.PicklingError: _log.error("cannot pickle option of type [%s] (key: %s, value: %s)", type(value), alias, str(value)) raise except: _log.error("don't know how to store option of type [%s] (key: %s, value: %s)", type(value), alias, str(value)) raise cmd = u'select cfg.set_option(%%(opt)s, %%(val)s%s, %%(wp)s, %%(cookie)s, NULL)' % sql_type_cast args = { 'opt': option, 'val': opt_value, 'wp': workplace, 'cookie': cookie } try: rows, idx = gmPG2.run_rw_queries(link_obj=rw_conn, queries=[{'cmd': cmd, 'args': args}], return_data=True) result = rows[0][0] except: _log.exception('cannot set option') result = False rw_conn.commit() # will rollback if transaction failed rw_conn.close() return result
def test(): conn = gmPG2.get_connection() app = wx.PyWidgetTester(size = (600, 600)) dlg = cOrganizationManagerDlg(app.frame, -1, size = (600, 600)) dlg.SetSize((600, 600)) dlg.ShowModal() # app.SetWidget(dlg, -1) app.MainLoop()
def add_items(self, items=None): """Requires no pending changes within the bill itself.""" # should check for item consistency first conn = gmPG2.get_connection(readonly = False) for item in items: item['pk_bill'] = self._payload[self._idx['pk_bill']] item.save(conn = conn) conn.commit() self.refetch_payload() # make sure aggregates are re-filled from view
def get_hints_for_patient(pk_identity=None, include_suppressed_needing_invalidation=False): conn = gmPG2.get_connection() curs = conn.cursor() curs.callproc('clin.get_hints_for_patient', [pk_identity]) rows = curs.fetchall() idx = gmPG2.get_col_indices(curs) curs.close() conn.rollback() if not include_suppressed_needing_invalidation: return [ cDynamicHint(row = {'data': r, 'idx': idx, 'pk_field': 'pk_auto_hint'}) for r in rows if r['rationale4suppression'] != 'magic_tag::please_invalidate_suppression' ] return [ cDynamicHint(row = {'data': r, 'idx': idx, 'pk_field': 'pk_auto_hint'}) for r in rows ]
def get_dbowner_connection(procedure=None, dbo_password=None, dbo_account='gm-dbo'): if procedure is None: procedure = _('<restricted procedure>') # 1) get password for gm-dbo if dbo_password is None: dbo_password = wx.GetPasswordFromUser ( message = _(""" [%s] This is a restricted procedure. We need the current password for the GNUmed database owner. Please enter the current password for <%s>:""") % ( procedure, dbo_account ), caption = procedure ) if dbo_password == '': return None gmLog2.add_word2hide(dbo_password) # 2) connect as gm-dbo login = gmPG2.get_default_login() dsn = gmPG2.make_psycopg2_dsn ( database = login.database, host = login.host, port = login.port, user = dbo_account, password = dbo_password ) try: conn = gmPG2.get_connection ( dsn = dsn, readonly = False, verbose = True, pooled = False ) except: _log.exception('cannot connect') gmGuiHelpers.gm_show_error ( aMessage = _('Cannot connect as the GNUmed database owner <%s>.') % dbo_account, aTitle = procedure ) gmPG2.log_database_access(action = 'failed to connect as database owner for [%s]' % procedure) return None return conn
def create_progress_note(soap=None, episode_id=None, encounter_id=None, link_obj=None): """Create clinical narrative entries. <soap> must be a dict, the keys being SOAP categories (including U and None=admin) and the values being text (possibly multi-line) Existing but empty ('' or None) categories are skipped. """ if soap is None: return True if not gmSoapDefs.are_valid_soap_cats(soap.keys(), allow_upper = True): raise ValueError('invalid SOAP category in <soap> dictionary: %s', soap) if link_obj is None: link_obj = gmPG2.get_connection(readonly = False) conn_rollback = link_obj.rollback conn_commit = link_obj.commit conn_close = link_obj.close else: conn_rollback = lambda x:x conn_commit = lambda x:x conn_close = lambda x:x instances = {} for cat in soap: val = soap[cat] if val is None: continue if ''.join([ v.strip() for v in val ]) == '': continue instance = create_narrative_item ( narrative = '\n'.join([ v.strip() for v in val ]), soap_cat = cat, episode_id = episode_id, encounter_id = encounter_id, link_obj = link_obj ) if instance is None: continue instances[cat] = instance conn_commit() conn_close() return instances
def connect_to_database(max_attempts=3, expected_version=None, require_version=True): """Display the login dialog and try to log into the backend. - up to max_attempts times - returns True/False """ # force programmer to set a valid expected_version gmPG2.known_schema_hashes[expected_version] client_version = _cfg.get(option='client_version') global current_db_name current_db_name = 'gnumed_v%s' % expected_version attempt = 0 dlg = cLoginDialog(None, -1, client_version=client_version) dlg.Centre(wx.BOTH) while attempt < max_attempts: _log.debug('login attempt %s of %s', (attempt + 1), max_attempts) connected = False dlg.ShowModal() login = dlg.panel.GetLoginInfo() if login is None: _log.info("user cancelled login dialog") break # obscure unconditionally, it could be a valid password gmLog2.add_word2hide(login.password) # try getting a connection to verify the parameters do work creds = gmConnectionPool.cPGCredentials() creds.database = login.database creds.host = login.host creds.port = login.port creds.user = login.user creds.password = login.password pool = gmConnectionPool.gmConnectionPool() pool.credentials = creds try: conn = gmPG2.get_raw_connection(verbose=True, readonly=True) _log.info('successfully connected: %s', conn) connected = True except gmPG2.cAuthenticationError as exc: _log.exception('login attempt failed') gmPG2.log_pg_exception_details(exc) attempt += 1 if attempt < max_attempts: if ('host=127.0.0.1' in ('%s' % exc)) or ('host=' not in ('%s' % exc)): msg = msg_auth_error_local else: msg = msg_auth_error msg = msg % exc msg = regex.sub( r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg) gmGuiHelpers.gm_show_error(msg, _('Connecting to backend')) del exc continue except gmPG2.dbapi.OperationalError as exc: _log.exception('login attempt failed') gmPG2.log_pg_exception_details(exc) msg = msg_login_problem_generic % exc msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg) gmGuiHelpers.gm_show_error(msg, _('Connecting to backend')) del exc continue conn.close() if not __database_is_acceptable_for_use( require_version=require_version, expected_version=expected_version, login=login): _log.info('database not suitable for use') connected = False break dlg.panel.save_state() gmExceptionHandlingWidgets.set_is_public_database( _cfg.get(option='is_public_db')) gmExceptionHandlingWidgets.set_helpdesk(_cfg.get(option='helpdesk')) _log.debug('establishing DB listener connection') conn = gmPG2.get_connection( verbose=True, connection_name='GNUmed-[DbListenerThread]', pooled=False) gmBackendListener.gmBackendListener(conn=conn) break dlg.DestroyLater() return connected
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 = 'utf-8-sig', 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 connect_to_database(max_attempts=3, expected_version=None, require_version=True): """Display the login dialog and try to log into the backend. - up to max_attempts times - returns True/False """ # force programmer to set a valid expected_version expected_hash = gmPG2.known_schema_hashes[expected_version] client_version = _cfg.get(option='client_version') global current_db_name current_db_name = 'gnumed_v%s' % expected_version attempt = 0 dlg = cLoginDialog(None, -1, client_version=client_version) dlg.Centre(wx.BOTH) while attempt < max_attempts: _log.debug('login attempt %s of %s', (attempt + 1), max_attempts) connected = False dlg.ShowModal() login = dlg.panel.GetLoginInfo() if login is None: _log.info("user cancelled login dialog") break gmLog2.add_word2hide(login.password) # try getting a connection to verify the parameters work creds = gmConnectionPool.cPGCredentials() creds.database = login.database creds.host = login.host creds.port = login.port creds.user = login.user creds.password = login.password pool = gmConnectionPool.gmConnectionPool() pool.credentials = creds try: conn = gmPG2.get_raw_connection(verbose=True, readonly=True) connected = True except gmPG2.cAuthenticationError as e: attempt += 1 _log.error("login attempt failed: %s", e) if attempt < max_attempts: if ('host=127.0.0.1' in ('%s' % e)) or ('host=' not in ('%s' % e)): msg = _( 'Unable to connect to database:\n\n' '%s\n\n' "Are you sure you have got a local database installed ?\n" '\n' "Please retry with proper credentials or cancel.\n" '\n' ' (for the public and any new GNUmed data-\n' ' bases the default user name and password\n' ' are {any-doc, any-doc})\n' '\n' 'You may also need to check the PostgreSQL client\n' 'authentication configuration in pg_hba.conf. For\n' 'details see:\n' '\n' 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL') else: msg = _( "Unable to connect to database:\n\n" "%s\n\n" "Please retry with proper credentials or cancel.\n" "\n" "For the public and any new GNUmed databases the\n" "default user name and password are {any-doc, any-doc}.\n" "\n" 'You may also need to check the PostgreSQL client\n' 'authentication configuration in pg_hba.conf. For\n' 'details see:\n' '\n' 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL') msg = msg % e msg = regex.sub( r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg) gmGuiHelpers.gm_show_error(msg, _('Connecting to backend')) del e continue except gmPG2.dbapi.OperationalError as exc: _log.exception('login attempt failed') gmPG2.log_pg_exception_details(exc) msg = _( "Unable to connect to database:\n\n" "%s\n\n" "Please retry another backend / user / password combination !\n" "\n" " (for the public and any new GNUmed databases\n" " the default user name and password are\n" " {any-doc, any-doc})\n" "\n") % exc msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg) gmGuiHelpers.gm_show_error(msg, _('Connecting to backend')) del exc continue conn.close() seems_bootstrapped = gmPG2.schema_exists(schema='gm') if not seems_bootstrapped: _log.error( 'schema [gm] does not exist - database not bootstrapped ?') msg = _('The database you connected to does not seem\n' 'to have been boostrapped properly.\n' '\n' 'Make sure you have run the GNUmed database\n' 'bootstrapper tool to create a new database.\n' '\n' 'Further help can be found on the website at\n' '\n' ' http://wiki.gnumed.de\n' '\n' 'or on the GNUmed mailing list.') gmGuiHelpers.gm_show_error(msg, _('Verifying database')) connected = False break compatible = gmPG2.database_schema_compatible(version=expected_version) if compatible or not require_version: dlg.panel.save_state() if not compatible: connected_db_version = gmPG2.get_schema_version() msg = msg_generic % (client_version, connected_db_version, expected_version, gmTools.coalesce(login.host, '<localhost>'), login.database, login.user) if require_version: gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version')) connected = False continue gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version')) # FIXME: make configurable max_skew = 1 # minutes if _cfg.get(option='debug'): max_skew = 10 if not gmPG2.sanity_check_time_skew(tolerance=(max_skew * 60)): if _cfg.get(option='debug'): gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings')) else: gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings')) connected = False continue sanity_level, message = gmPG2.sanity_check_database_settings() if sanity_level != 0: gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings')) if sanity_level == 2: connected = False continue gmExceptionHandlingWidgets.set_is_public_database( _cfg.get(option='is_public_db')) gmExceptionHandlingWidgets.set_helpdesk(_cfg.get(option='helpdesk')) gmLog2.log_multiline(logging.DEBUG, message='fingerprint', text=gmPG2.get_db_fingerprint(eol='\n')) conn = gmPG2.get_connection( verbose=True, connection_name='GNUmed-[DbListenerThread]', pooled=False) listener = gmBackendListener.gmBackendListener(conn=conn) break dlg.DestroyLater() return connected
cmd = """ SELECT soap_cat, narrative, src_table, (SELECT rank FROM clin.soap_cat_ranks scr WHERE scr.soap_cat = vn4s.soap_cat) AS rank FROM clin.v_narrative4search vn4s WHERE pk_patient = %(pat)s ORDER BY pk_encounter -- sort of chronologically sorted , pk_health_issue , pk_episode , rank , src_table """ conn = gmPG2.get_connection(encoding='utf8') rows, idx = gmPG2.run_ro_queries(link_obj=conn, queries=[{'cmd': cmd, 'args': {'pat': sys.argv[1]}}]) f = io.open('emr-%s-narrative-dump.txt' % sys.argv[1], mode = 'wt', encoding = 'utf8', errors = 'strict') for row in rows: f.write('%s: %s (%s)\n'.encode('utf8') % (row['soap_cat'], row['narrative'], row['src_table'])) f.close() #============================================================
def set(self, workplace=None, cookie=None, option=None, value=None): """Set (insert or update) option value in database. Any parameter that is None will be set to the database default. Note: you can't change the type of a parameter once it has been created in the backend. If you want to change the type you will have to delete the parameter and recreate it using the new type. """ # sanity checks if None in [option, value]: raise ValueError('invalid arguments (option=<%s>, value=<%s>)' % (option, value)) rw_conn = gmPG2.get_connection(readonly=False) alias = self.__make_alias(workplace, 'CURRENT_USER', cookie, option) opt_value = value sql_type_cast = '' if isinstance(value, str): sql_type_cast = '::text' elif isinstance(value, bool): opt_value = int(opt_value) elif isinstance(value, (float, int, decimal.Decimal, bool)): sql_type_cast = '::numeric' elif isinstance(value, list): # there can be different syntaxes for list types so don't try to cast them pass elif isinstance(value, buffer): # can go directly into bytea pass else: try: opt_value = gmPG2.dbapi.Binary(pickle.dumps(value)) sql_type_cast = '::bytea' except pickle.PicklingError: _log.error( "cannot pickle option of type [%s] (key: %s, value: %s)", type(value), alias, str(value)) raise except: _log.error( "don't know how to store option of type [%s] (key: %s, value: %s)", type(value), alias, str(value)) raise cmd = 'select cfg.set_option(%%(opt)s, %%(val)s%s, %%(wp)s, %%(cookie)s, NULL)' % sql_type_cast args = { 'opt': option, 'val': opt_value, 'wp': workplace, 'cookie': cookie } try: rows, idx = gmPG2.run_rw_queries(link_obj=rw_conn, queries=[{ 'cmd': cmd, 'args': args }], return_data=True) result = rows[0][0] except: _log.exception('cannot set option') result = False rw_conn.commit() # will rollback if transaction failed rw_conn.close() return result
narrative, src_table, (SELECT rank FROM clin.soap_cat_ranks scr WHERE scr.soap_cat = vn4s.soap_cat) AS rank FROM clin.v_narrative4search vn4s WHERE pk_patient = %(pat)s ORDER BY pk_encounter -- sort of chronologically sorted , pk_health_issue , pk_episode , rank , src_table """ conn = gmPG2.get_connection(encoding='utf8') rows, idx = gmPG2.run_ro_queries(link_obj=conn, queries=[{ 'cmd': cmd, 'args': { 'pat': sys.argv[1] } }]) f = io.open('emr-%s-narrative-dump.txt' % sys.argv[1], mode='wt', encoding='utf8', errors='strict') for row in rows:
def __init__(self): self._generate_queries = self._generate_queries_de # make a cursor self.conn = gmPG2.get_connection() self.curs = self.conn.cursor()
def connect_to_database(max_attempts=3, expected_version=None, require_version=True): """Display the login dialog and try to log into the backend. - up to max_attempts times - returns True/False """ # force programmer to set a valid expected_version expected_hash = gmPG2.known_schema_hashes[expected_version] client_version = _cfg.get(option = 'client_version') global current_db_name current_db_name = 'gnumed_v%s' % expected_version attempt = 0 dlg = cLoginDialog(None, -1, client_version = client_version) dlg.Centre(wx.BOTH) while attempt < max_attempts: _log.debug('login attempt %s of %s', (attempt+1), max_attempts) connected = False dlg.ShowModal() login = dlg.panel.GetLoginInfo() if login is None: _log.info("user cancelled login dialog") break gmLog2.add_word2hide(login.password) # try getting a connection to verify the DSN works dsn = gmPG2.make_psycopg2_dsn ( database = login.database, host = login.host, port = login.port, user = login.user, password = login.password ) try: conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True) connected = True except gmPG2.cAuthenticationError as e: attempt += 1 _log.error("login attempt failed: %s", e) if attempt < max_attempts: if ('host=127.0.0.1' in ('%s' % e)) or ('host=' not in ('%s' % e)): msg = _( 'Unable to connect to database:\n\n' '%s\n\n' "Are you sure you have got a local database installed ?\n" '\n' "Please retry with proper credentials or cancel.\n" '\n' ' (for the public and any new GNUmed data-\n' ' bases the default user name and password\n' ' are {any-doc, any-doc})\n' '\n' 'You may also need to check the PostgreSQL client\n' 'authentication configuration in pg_hba.conf. For\n' 'details see:\n' '\n' 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL' ) else: msg = _( "Unable to connect to database:\n\n" "%s\n\n" "Please retry with proper credentials or cancel.\n" "\n" "For the public and any new GNUmed databases the\n" "default user name and password are {any-doc, any-doc}.\n" "\n" 'You may also need to check the PostgreSQL client\n' 'authentication configuration in pg_hba.conf. For\n' 'details see:\n' '\n' 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL' ) msg = msg % e msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg) gmGuiHelpers.gm_show_error ( msg, _('Connecting to backend') ) del e continue except gmPG2.dbapi.OperationalError as exc: _log.exception('login attempt failed') gmPG2.log_pg_exception_details(exc) msg = _( "Unable to connect to database:\n\n" "%s\n\n" "Please retry another backend / user / password combination !\n" "\n" " (for the public and any new GNUmed databases\n" " the default user name and password are\n" " {any-doc, any-doc})\n" "\n" ) % exc msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg) gmGuiHelpers.gm_show_error(msg, _('Connecting to backend')) del exc continue conn.close() # connect was successful gmPG2.set_default_login(login = login) gmPG2.set_default_client_encoding(encoding = dlg.panel.backend_profile.encoding) seems_bootstrapped = gmPG2.schema_exists(schema = 'gm') if not seems_bootstrapped: _log.error('schema [gm] does not exist - database not bootstrapped ?') msg = _( 'The database you connected to does not seem\n' 'to have been boostrapped properly.\n' '\n' 'Make sure you have run the GNUmed database\n' 'bootstrapper tool to create a new database.\n' '\n' 'Further help can be found on the website at\n' '\n' ' http://wiki.gnumed.de\n' '\n' 'or on the GNUmed mailing list.' ) gmGuiHelpers.gm_show_error(msg, _('Verifying database')) connected = False break compatible = gmPG2.database_schema_compatible(version = expected_version) if compatible or not require_version: dlg.panel.save_state() if not compatible: connected_db_version = gmPG2.get_schema_version() msg = msg_generic % ( client_version, connected_db_version, expected_version, gmTools.coalesce(login.host, '<localhost>'), login.database, login.user ) if require_version: gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version')) connected = False continue gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version')) # FIXME: make configurable max_skew = 1 # minutes if _cfg.get(option = 'debug'): max_skew = 10 if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)): if _cfg.get(option = 'debug'): gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings')) else: gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings')) connected = False continue sanity_level, message = gmPG2.sanity_check_database_settings() if sanity_level != 0: gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings')) if sanity_level == 2: connected = False continue gmExceptionHandlingWidgets.set_is_public_database(login.public_db) gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk) conn = gmPG2.get_connection(verbose = True, connection_name = 'GNUmed-[DbListenerThread]', pooled = False) listener = gmBackendListener.gmBackendListener(conn = conn) break dlg.DestroyLater() return connected
def test_atc_import(): atc_import(cfg_fname = sys.argv[2], conn = gmPG2.get_connection(readonly = False))
def save_payload(self, conn=None): """Store updated values (if any) in database. Optionally accepts a pre-existing connection - returns a tuple (<True|False>, <data>) - True: success - False: an error occurred * data is (error, message) * for error meanings see gmPG2.run_rw_queries() """ if not self._is_modified: return (True, None) args = {} for field in self._idx.keys(): args[field] = self._payload[self._idx[field]] self.modified_payload = args close_conn = self.__noop if conn is None: conn = gmPG2.get_connection(readonly=False) close_conn = conn.close queries = [] for query in self.__class__._cmds_store_payload: queries.append({'cmd': query, 'args': args}) rows, idx = gmPG2.run_rw_queries ( link_obj = conn, queries = queries, return_data = True, get_col_idx = True ) # this can happen if: # - someone else updated the row so XMIN does not match anymore # - the PK went away (rows were deleted from under us) # - another WHERE condition of the UPDATE did not produce any rows to update # - savepoints are used since subtransactions may relevantly change the xmin/xmax ... if len(rows) == 0: return (False, (u'cannot update row', _('[%s:%s]: row not updated (nothing returned), row in use ?') % (self.__class__.__name__, self.pk_obj))) # update cached values from should-be-first-and-only result # row of last query, # update all fields returned such that computed # columns see their new values row = rows[0] for key in idx: try: self._payload[self._idx[key]] = row[idx[key]] except KeyError: conn.rollback() close_conn() _log.error('[%s:%s]: cannot update instance, XMIN refetch key mismatch on [%s]' % (self.__class__.__name__, self.pk_obj, key)) _log.error('payload keys: %s' % str(self._idx)) _log.error('XMIN refetch keys: %s' % str(idx)) _log.error(args) raise conn.commit() close_conn() self._is_modified = False # update to new "original" payload self.original_payload = {} for field in self._idx.keys(): self.original_payload[field] = self._payload[self._idx[field]] return (True, None)
pass l = login() l.database = 'gnumed_v9' l.host = 'publicdb.gnumed.de' l.port = '5432' l.user = '******' l.password = '******' gmPG2.set_default_login(l) gmPG2.set_default_client_timezone(timezone='Asia/Colombo') gmPG2.set_default_client_timezone(timezone='Asia/Calcutta') conn = gmPG2.get_connection() cmd = """select * from dem.v_staff where db_user = CURRENT_USER""" try: rows, idx = gmPG2.run_ro_queries(queries=[{'cmd': cmd}], verbose=True) for row in rows: _log.info(row) print rows print "==> success" except Exception: _log.exception('query failed') gmLog2.log_stack_trace('query failed') print "==> failure" # =======================================================================
def __init__(self): self.ro_conn = gmPG2.get_connection()
ddl.append('-- ----------------------------------------------') return ddl #================================================================== # main #------------------------------------------------------------------ if __name__ == "__main__" : tmp = '' try: tmp = raw_input("audit trail parent table [%s]: " % audit_trail_parent_table) except KeyboardError: pass if tmp != '': audit_trail_parent_table = tmp conn = gmPG2.get_connection(readonly=False, pooled=False) curs = conn.cursor() schema = create_audit_ddl(curs) curs.close() conn.close() if schema is None: print "error creating schema" sys.exit(-1) file = io.open('audit-trail-schema.sql', mode = 'wb', encoding = 'utf8') for line in schema: file.write("%s;\n" % line) file.close()
def save_payload(self, conn=None): """Store updated values (if any) in database. Optionally accepts a pre-existing connection - returns a tuple (<True|False>, <data>) - True: success - False: an error occurred * data is (error, message) * for error meanings see gmPG2.run_rw_queries() """ if not self._is_modified: return (True, None) args = {} for field in self._idx.keys(): args[field] = self._payload[self._idx[field]] self.payload_most_recently_attempted_to_store = args close_conn = self.__noop if conn is None: conn = gmPG2.get_connection(readonly=False) close_conn = conn.close queries = [] for query in self.__class__._cmds_store_payload: queries.append({'cmd': query, 'args': args}) rows, idx = gmPG2.run_rw_queries(link_obj=conn, queries=queries, return_data=True, get_col_idx=True) # success ? if len(rows) == 0: # nothing updated - this can happen if: # - someone else updated the row so XMIN does not match anymore # - the PK went away (rows were deleted from under us) # - another WHERE condition of the UPDATE did not produce any rows to update # - savepoints are used since subtransactions may relevantly change the xmin/xmax ... return (False, ( 'cannot update row', _('[%s:%s]: row not updated (nothing returned), row in use ?') % (self.__class__.__name__, self.pk_obj))) # update cached values from should-be-first-and-only # result row of last query, # update all fields returned such that computed # columns see their new values (given they are # returned by the query) row = rows[0] for key in idx: try: self._payload[self._idx[key]] = row[idx[key]] except KeyError: conn.rollback() close_conn() _log.error( '[%s:%s]: cannot update instance, XMIN refetch key mismatch on [%s]' % (self.__class__.__name__, self.pk_obj, key)) _log.error('payload keys: %s' % str(self._idx)) _log.error('XMIN refetch keys: %s' % str(idx)) _log.error(args) raise # only at conn.commit() time will data actually # get committed (and thusly trigger based notifications # be sent out), so reset the local modification flag # right before that self._is_modified = False conn.commit() close_conn() # update to new "original" payload self.payload_most_recently_fetched = {} for field in self._idx.keys(): self.payload_most_recently_fetched[field] = self._payload[ self._idx[field]] return (True, None)
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 test_atc_import(): atc_import(cfg_fname=sys.argv[2], conn=gmPG2.get_connection(readonly=False))
def __init__(self, *args, **kwargs): gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) mp = gmLOINC.cLOINCMatchProvider() mp.setThresholds(1, 2, 4) #mp.print_queries = True #mp.word_separators = '[ \t:@]+' self.matcher = mp self.selection_only = False self.final_regex = r'\d{1,5}-\d{1}$' self.SetToolTip(_('Select a LOINC (Logical Observation Identifiers Names and Codes).')) #================================================================ # main #---------------------------------------------------------------- if __name__ == '__main__': if len(sys.argv) < 2: sys.exit() if sys.argv[1] != 'test': sys.exit() from Gnumed.pycommon import gmPG2 #---------------------------------------- gmPG2.get_connection() app = wx.PyWidgetTester(size = (600, 80)) app.SetWidget(cLOINCPhraseWheel, -1) app.MainLoop()
#================================================================== # main #------------------------------------------------------------------ if __name__ == "__main__": tmp = '' try: tmp = raw_input("audit trail parent table [%s]: " % AUDIT_TRAIL_PARENT_TABLE) except KeyboardError: pass if tmp != '': AUDIT_TRAIL_PARENT_TABLE = tmp conn = gmPG2.get_connection(readonly=False, pooled=False) curs = conn.cursor() schema = create_audit_ddl(curs) curs.close() conn.close() if schema is None: print "error creating schema" sys.exit(-1) f = io.open('audit-trail-schema.sql', mode='wb', encoding='utf8') for line in schema: f.write("%s;\n" % line) f.close()