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

# Source Code for Module Gnumed.business.gmSOAPimporter

      1  """GNUmed SOAP importer
      2
      3  (specification by Karsten Hilbert <Karsten.Hilbert@gmx.net>)
      4
      5  This script is designed for importing GNUmed SOAP input "bundles".
      6
      7          - "bundle" is list of dicts
      8          - each "bundle" is processed dict by dict
      9          - the dicts in the list are INDEPENDANT of each other
     10          - each dict contains information for one new clin_narrative row
     11          - each dict has the keys: 'soap', 'types', 'text', 'clin_context'
     12                  - 'soap':
     13                          - relates to clin_narrative.soap_cat
     14                  - 'types':
     15                          - a list of strings
     16                          - the strings must be found in clin_item_type.type
     17                          - strings not found in clin_item_type.type are ignored during
     18                            import and the user is warned about that
     19                  - 'text':
     20                          - the narrative for clin_narrative.narrative, imported as is
     21                  - 'clin_context':
     22                          - 'clin_context' is a dictionary containing clinical
     23                            context information, required to properly create clinical items.
     24                            Its 'episode_id' must always be supplied.
     25  """
     26  #===============================================================
     27  __version__ = "$Revision: 1.24 $"
     28  __author__ = "Carlos Moro <cfmoro1976@yahoo.es>"
     29  __license__ = "GPL v2 or later (details at http://www.gnu.org)"
     30
     31  # stdlib
     32  import sys, re, logging
     33
     34
     35  # GNUmed
     36  from Gnumed.pycommon import gmExceptions, gmI18N, gmDispatcher
     37  from Gnumed.business import gmClinNarrative, gmPerson, gmPersonSearch
     38
     39
     40  _log = logging.getLogger('gm.soap')
     41
     42
     43  # module level constants
     44  soap_bundle_SOAP_CAT_KEY = "soap"
     45  soap_bundle_TYPES_KEY = "types"
     46  soap_bundle_TEXT_KEY = "text"
     47  soap_bundle_CLIN_CTX_KEY = "clin_context"
     48  soap_bundle_TYPE_KEY = "type"
     49  soap_bundle_EPISODE_ID_KEY = "episode_id"
     50  soap_bundle_ENCOUNTER_ID_KEY = "encounter_id"
     51  soap_bundle_STAFF_ID_KEY = "staff_id"
     52  soap_bundle_SOAP_CATS = ['s','o','a','p']               # these are pretty much fixed
     53  #===============================================================
     54 -class cSOAPImporter:
     55          """
     56          Main SOAP importer class
     57          """
     58          #-----------------------------------------------------------
     59 -        def __init__(self):
     60                  pass
     61          #-----------------------------------------------------------
     62          # external API
     63          #-----------------------------------------------------------
     64 -        def import_soap(self, bundle=None):
     65                  """
     66                  Import supplied GNUmed SOAP input "bundle". For details consult current
     67                  module's description information.
     68
     69                  @param bundle: GNUmed SOAP input data (as described in module's information)
     70                  @type bundle: list of dicts
     71                  """
     72                  # process each entry in soap bundle independently
     73                  for soap_entry in bundle:
     74                          if not self.__import_narrative(soap_entry):
     75                                  _log.error('skipping soap entry')
     76                                  continue
     77                  gmDispatcher.send(signal = 'clin_item_updated')
     78                  return True
     79          #-----------------------------------------------------------
     80          # internal helpers
     81          #-----------------------------------------------------------
     82 -        def __import_narrative(self, soap_entry):
     83                  """Import soap entry into GNUmed backend.
     84
     85                  @param soap_entry: dictionary containing information related
     86                                                     to one SOAP input line
     87                  @type soap_entry: dictionary with keys 'soap', 'types', 'text'
     88
     89                  FIXME: Later we may want to allow for explicitly setting a staff ID to be
     90                  FIXME: used for import. This would allow to import data "on behalf of" someone.
     91                  """
     92                  if not self.__verify_soap_entry(soap_entry=soap_entry):
     93                          _log.error('cannot verify soap entry')
     94                          return False
     95                  # obtain clinical context information
     96                  emr = gmPerson.gmCurrentPatient().get_emr()
     97                  epi_id = soap_entry[soap_bundle_CLIN_CTX_KEY][soap_bundle_EPISODE_ID_KEY]
     98                  try:
     99                          enc_id = soap_entry[soap_bundle_CLIN_CTX_KEY][soap_bundle_ENCOUNTER_ID_KEY]
    100                  except KeyError:
    101                          enc = emr.active_encounter
    102                          enc_id = enc['pk_encounter']
    103
    104                  # create narrative row
    105                  status, narr = gmClinNarrative.create_clin_narrative (
    106                          narrative = soap_entry[soap_bundle_TEXT_KEY],
    107                          soap_cat = soap_entry[soap_bundle_SOAP_CAT_KEY],
    108                          episode_id = epi_id,
    109                          encounter_id = enc_id
    110                  )
    111
    112  #               # attach types
    113  #               if soap_entry.has_key(soap_bundle_TYPES_KEY):
    114  #                       print "code missing to attach types to imported narrative"
    115
    116                  return status
    117          #-----------------------------------------------------------
    118 -        def __verify_soap_entry(self, soap_entry):
    119                  """Perform basic integrity check of a supplied SOAP entry.
    120
    121                  @param soap_entry: dictionary containing information related to one
    122                                                     SOAP input
    123                  @type soap_entry: dictionary with keys 'soap', 'types', 'text'
    124                  """
    125                  required_keys = [
    126                          soap_bundle_SOAP_CAT_KEY,
    127                          soap_bundle_CLIN_CTX_KEY,
    128                          soap_bundle_TEXT_KEY
    129                  ]
    130                  # verify key existence
    131                  for a_key in required_keys:
    132                          try:
    133                                  soap_entry[a_key]
    134                          except KeyError:
    135                                  _log.error('key [%s] is missing from soap entry' % a_key)
    136                                  _log.error('%s' % soap_entry)
    137                                  return False
    138                  # verify key *values*
    139                  if not soap_entry[soap_bundle_SOAP_CAT_KEY] in soap_bundle_SOAP_CATS:
    140                          _log.error('invalid soap category [%s]' % soap_entry[soap_bundle_SOAP_CAT_KEY])
    141                          _log.error('%s' % soap_entry)
    142                          return False
    143                  try:
    144                          soap_entry[soap_bundle_CLIN_CTX_KEY][soap_bundle_EPISODE_ID_KEY]
    145                  except KeyError:
    146                          _log.error('SOAP entry does not provide mandatory episode ID')
    147                          _log.error('%s' % soap_entry)
    148                          return False
    149                  return True
    150          #-----------------------------------------------------------
    151  #       def _verify_types(self, soap_entry):
    152  #               """
    153  #               Perform types key check of a supplied SOAP entry
    154  #
    155  #               @param soap_entry: dictionary containing information related to one
    156  #                                                  SOAP input
    157  #               @type soap_entry: dictionary with keys 'soap', 'types', 'text'
    158  #               """
    159  #
    160  #               # FIXME fetch from backend
    161  #               allowed_types = ['Hx']
    162  #               for input_type in soap_entry[soap_bundle_TYPES_KEY]:
    163  #                       if not input_type in allowed_types:
    164  #                               _log.error('bad clin_item_type.type in supplied soap entry [%s]' %
    165  #                               soap_entry)
    166  #                               return False
    167  #               return True
    168
    169  #================================================================
    170  # MAIN
    171  #----------------------------------------------------------------
    172  if __name__ == '__main__':
    173          _log.info("starting SOAP importer...")
    174
    175          try:
    176                  # obtain patient
    177                  patient = gmPersonSearch.ask_for_patient()
    178                  if patient is None:
    179                          print "No patient. Exiting gracefully..."
    180                          sys.exit(0)
    181                  gmPerson.set_active_patient(patient=patient)
    182
    183                  # now import
    184                  importer = cSOAPImporter()
    185                  bundle = [
    186                          {soap_bundle_SOAP_CAT_KEY: 's',
    187                           soap_bundle_TYPES_KEY: ['Hx'],
    188                           soap_bundle_TEXT_KEY: 'Test subjective narrative',
    189                           soap_bundle_CLIN_CTX_KEY: {soap_bundle_EPISODE_ID_KEY: '1'}
    190                          },
    191                          {soap_bundle_SOAP_CAT_KEY: 'o',
    192                           soap_bundle_TYPES_KEY: ['Hx'],
    193                           soap_bundle_TEXT_KEY: 'Test objective narrative',
    194                           soap_bundle_CLIN_CTX_KEY: {soap_bundle_EPISODE_ID_KEY: '1'}
    195                          },
    196                          {soap_bundle_SOAP_CAT_KEY: 'a',
    197                           soap_bundle_TYPES_KEY: ['Hx'],
    198                           soap_bundle_TEXT_KEY: 'Test assesment narrative',
    199                           soap_bundle_CLIN_CTX_KEY: {soap_bundle_EPISODE_ID_KEY: '1'}
    200                          },
    201                          {soap_bundle_SOAP_CAT_KEY: 'p',
    202                           soap_bundle_TYPES_KEY: ['Hx'],
    203                           soap_bundle_TEXT_KEY: 'Test plan narrative. [:tetanus:]. [:pneumoniae:].',
    204                           soap_bundle_CLIN_CTX_KEY: {
    205                                  soap_bundle_EPISODE_ID_KEY: '1',
    206                                  soap_bundle_ENCOUNTER_ID_KEY: '1',
    207                                  soap_bundle_STAFF_ID_KEY: '1'
    208                                  },
    209                          }
    210                  ]
    211                  importer.import_soap(bundle)
    212
    213                  # clean up
    214                  if patient is not None:
    215                          try:
    216                                  patient.cleanup()
    217                          except:
    218                                  print "error cleaning up patient"
    219          except StandardError:
    220                  _log.exception("unhandled exception caught !", sys.exc_info(), 1)
    221                  # but re-raise them
    222                  raise
    223
    224          _log.info("closing SOAP importer...")
    225  #================================================================
    226