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  # $Source: /cvsroot/gnumed/gnumed/gnumed/client/business/gmSOAPimporter.py,v $ 
 28  # $Id: gmSOAPimporter.py,v 1.24 2009/12/21 14:59:31 ncq Exp $ 
 29  __version__ = "$Revision: 1.24 $" 
 30  __author__ = "Carlos Moro <cfmoro1976@yahoo.es>" 
 31  __license__ = "GPL (details at http://www.gnu.org)" 
 32   
 33  # stdlib 
 34  import sys, re, logging 
 35   
 36   
 37  # 3rd party 
 38  import mx.DateTime as mxDT 
 39   
 40   
 41  # GnuMed 
 42  from Gnumed.pycommon import gmExceptions, gmI18N, gmDispatcher 
 43  from Gnumed.business import gmClinNarrative, gmPerson 
 44   
 45   
 46  _log = logging.getLogger('gm.soap') 
 47   
 48   
 49  # module level constants 
 50  soap_bundle_SOAP_CAT_KEY = "soap" 
 51  soap_bundle_TYPES_KEY = "types" 
 52  soap_bundle_TEXT_KEY = "text" 
 53  soap_bundle_CLIN_CTX_KEY = "clin_context" 
 54  soap_bundle_TYPE_KEY = "type" 
 55  soap_bundle_EPISODE_ID_KEY = "episode_id" 
 56  soap_bundle_ENCOUNTER_ID_KEY = "encounter_id" 
 57  soap_bundle_STAFF_ID_KEY = "staff_id" 
 58  soap_bundle_SOAP_CATS = ['s','o','a','p']               # these are pretty much fixed 
 59  #=============================================================== 
60 -class cSOAPImporter:
61 """ 62 Main SOAP importer class 63 """ 64 65 #-----------------------------------------------------------
66 - def __init__(self):
67 pass
68 #----------------------------------------------------------- 69 # external API 70 #-----------------------------------------------------------
71 - def import_soap(self, bundle=None):
72 """ 73 Import supplied GnuMed SOAP input "bundle". For details consult current 74 module's description information. 75 76 @param bundle: GnuMed SOAP input data (as described in module's information) 77 @type bundle: list of dicts 78 """ 79 # process each entry in soap bundle independently 80 for soap_entry in bundle: 81 if not self.__import_narrative(soap_entry): 82 _log.error('skipping soap entry') 83 continue 84 gmDispatcher.send(signal = 'clin_item_updated') 85 return True
86 #----------------------------------------------------------- 87 # internal helpers 88 #-----------------------------------------------------------
89 - def __import_narrative(self, soap_entry):
90 """Import soap entry into GnuMed backend. 91 92 @param soap_entry: dictionary containing information related 93 to one SOAP input line 94 @type soap_entry: dictionary with keys 'soap', 'types', 'text' 95 96 FIXME: Later we may want to allow for explicitly setting a staff ID to be 97 FIXME: used for import. This would allow to import data "on behalf of" someone. 98 """ 99 if not self.__verify_soap_entry(soap_entry=soap_entry): 100 _log.error('cannot verify soap entry') 101 return False 102 # obtain clinical context information 103 emr = gmPerson.gmCurrentPatient().get_emr() 104 epi_id = soap_entry[soap_bundle_CLIN_CTX_KEY][soap_bundle_EPISODE_ID_KEY] 105 try: 106 enc_id = soap_entry[soap_bundle_CLIN_CTX_KEY][soap_bundle_ENCOUNTER_ID_KEY] 107 except KeyError: 108 enc = emr.active_encounter 109 enc_id = enc['pk_encounter'] 110 111 # create narrative row 112 status, narr = gmClinNarrative.create_clin_narrative ( 113 narrative = soap_entry[soap_bundle_TEXT_KEY], 114 soap_cat = soap_entry[soap_bundle_SOAP_CAT_KEY], 115 episode_id = epi_id, 116 encounter_id = enc_id 117 ) 118 119 # # attach types 120 # if soap_entry.has_key(soap_bundle_TYPES_KEY): 121 # print "code missing to attach types to imported narrative" 122 123 return status
124 #-----------------------------------------------------------
125 - def __verify_soap_entry(self, soap_entry):
126 """Perform basic integrity check of a supplied SOAP entry. 127 128 @param soap_entry: dictionary containing information related to one 129 SOAP input 130 @type soap_entry: dictionary with keys 'soap', 'types', 'text' 131 """ 132 required_keys = [ 133 soap_bundle_SOAP_CAT_KEY, 134 soap_bundle_CLIN_CTX_KEY, 135 soap_bundle_TEXT_KEY 136 ] 137 # verify key existence 138 for a_key in required_keys: 139 try: 140 soap_entry[a_key] 141 except KeyError: 142 _log.error('key [%s] is missing from soap entry' % a_key) 143 _log.error('%s' % soap_entry) 144 return False 145 # verify key *values* 146 if not soap_entry[soap_bundle_SOAP_CAT_KEY] in soap_bundle_SOAP_CATS: 147 _log.error('invalid soap category [%s]' % soap_entry[soap_bundle_SOAP_CAT_KEY]) 148 _log.error('%s' % soap_entry) 149 return False 150 try: 151 soap_entry[soap_bundle_CLIN_CTX_KEY][soap_bundle_EPISODE_ID_KEY] 152 except KeyError: 153 _log.error('SOAP entry does not provide mandatory episode ID') 154 _log.error('%s' % soap_entry) 155 return False 156 return True
157 #----------------------------------------------------------- 158 # def _verify_types(self, soap_entry): 159 # """ 160 # Perform types key check of a supplied SOAP entry 161 # 162 # @param soap_entry: dictionary containing information related to one 163 # SOAP input 164 # @type soap_entry: dictionary with keys 'soap', 'types', 'text' 165 # """ 166 # 167 # # FIXME fetch from backend 168 # allowed_types = ['Hx'] 169 # for input_type in soap_entry[soap_bundle_TYPES_KEY]: 170 # if not input_type in allowed_types: 171 # _log.error('bad clin_item_type.type in supplied soap entry [%s]' % 172 # soap_entry) 173 # return False 174 # return True 175 176 #================================================================ 177 # MAIN 178 #---------------------------------------------------------------- 179 if __name__ == '__main__': 180 _log.info("starting SOAP importer...") 181 182 try: 183 # obtain patient 184 patient = gmPerson.ask_for_patient() 185 if patient is None: 186 print "No patient. Exiting gracefully..." 187 sys.exit(0) 188 gmPerson.set_active_patient(patient=patient) 189 190 # now import 191 importer = cSOAPImporter() 192 bundle = [ 193 {soap_bundle_SOAP_CAT_KEY: 's', 194 soap_bundle_TYPES_KEY: ['Hx'], 195 soap_bundle_TEXT_KEY: 'Test subjective narrative', 196 soap_bundle_CLIN_CTX_KEY: {soap_bundle_EPISODE_ID_KEY: '1'} 197 }, 198 {soap_bundle_SOAP_CAT_KEY: 'o', 199 soap_bundle_TYPES_KEY: ['Hx'], 200 soap_bundle_TEXT_KEY: 'Test objective narrative', 201 soap_bundle_CLIN_CTX_KEY: {soap_bundle_EPISODE_ID_KEY: '1'} 202 }, 203 {soap_bundle_SOAP_CAT_KEY: 'a', 204 soap_bundle_TYPES_KEY: ['Hx'], 205 soap_bundle_TEXT_KEY: 'Test assesment narrative', 206 soap_bundle_CLIN_CTX_KEY: {soap_bundle_EPISODE_ID_KEY: '1'} 207 }, 208 {soap_bundle_SOAP_CAT_KEY: 'p', 209 soap_bundle_TYPES_KEY: ['Hx'], 210 soap_bundle_TEXT_KEY: 'Test plan narrative. [:tetanus:]. [:pneumoniae:].', 211 soap_bundle_CLIN_CTX_KEY: { 212 soap_bundle_EPISODE_ID_KEY: '1', 213 soap_bundle_ENCOUNTER_ID_KEY: '1', 214 soap_bundle_STAFF_ID_KEY: '1' 215 }, 216 } 217 ] 218 importer.import_soap(bundle) 219 220 # clean up 221 if patient is not None: 222 try: 223 patient.cleanup() 224 except: 225 print "error cleaning up patient" 226 except StandardError: 227 _log.exception("unhandled exception caught !", sys.exc_info(), 1) 228 # but re-raise them 229 raise 230 231 _log.info("closing SOAP importer...") 232 #================================================================ 233 # $Log: gmSOAPimporter.py,v $ 234 # Revision 1.24 2009/12/21 14:59:31 ncq 235 # - typo 236 # 237 # Revision 1.23 2009/09/13 18:25:54 ncq 238 # - no more get-active-encounter() 239 # 240 # Revision 1.22 2008/02/25 17:31:41 ncq 241 # - logging cleanup 242 # 243 # Revision 1.21 2008/01/30 13:34:50 ncq 244 # - switch to std lib logging 245 # 246 # Revision 1.20 2007/12/23 11:55:21 ncq 247 # - cleanup 248 # 249 # Revision 1.19 2007/12/11 12:59:11 ncq 250 # - cleanup and explicit signal handling 251 # 252 # Revision 1.18 2007/03/08 11:31:08 ncq 253 # - just cleanup 254 # 255 # Revision 1.17 2006/10/31 11:27:15 ncq 256 # - remove use of gmPG 257 # 258 # Revision 1.16 2006/10/25 07:17:40 ncq 259 # - no more gmPG 260 # - no more cClinItem 261 # 262 # Revision 1.15 2006/10/23 13:06:54 ncq 263 # - vaccs DB object not yet converted 264 # 265 # Revision 1.14 2006/07/19 21:37:51 ncq 266 # - cleanup 267 # 268 # Revision 1.13 2006/06/17 13:58:39 ncq 269 # - cleanup 270 # 271 # Revision 1.12 2006/05/12 12:05:04 ncq 272 # - cleanup 273 # 274 # Revision 1.11 2006/05/04 09:49:20 ncq 275 # - get_clinical_record() -> get_emr() 276 # - adjust to changes in set_active_patient() 277 # - need explicit set_active_patient() after ask_for_patient() if wanted 278 # 279 # Revision 1.10 2005/10/19 09:14:46 ncq 280 # - remove half-baked support for embedded data, now handled elsewhere 281 # - general cleanup/doc fixes 282 # 283 # Revision 1.9 2005/10/11 21:50:33 ncq 284 # - create_clin_narrative() should not be aware of emr object 285 # 286 # Revision 1.8 2005/10/08 12:33:08 sjtan 287 # tree can be updated now without refetching entire cache; done by passing emr object to create_xxxx methods and calling emr.update_cache(key,obj);refresh_historical_tree non-destructively checks for changes and removes removed nodes and adds them if cache mismatch. 288 # 289 # Revision 1.7 2005/05/17 08:03:30 ncq 290 # - cleanup 291 # 292 # Revision 1.6 2005/04/12 09:59:16 ncq 293 # - cleanup 294 # - enable actual backend storage 295 # 296 # Revision 1.5 2005/01/31 13:00:40 ncq 297 # - use ask_for_patient() in gmPerson 298 # 299 # Revision 1.4 2005/01/31 10:37:26 ncq 300 # - gmPatient.py -> gmPerson.py 301 # 302 # Revision 1.3 2004/12/20 09:51:28 ncq 303 # - tie constants to bundle not importer re naming 304 # 305 # Revision 1.2 2004/12/19 18:41:55 cfmoro 306 # Struct keys made module level constants 307 # 308 # Revision 1.1 2004/12/18 16:14:13 ncq 309 # - moved here from test area 310 # 311 # Revision 1.7 2004/12/18 16:00:37 ncq 312 # - final touch up before moving over 313 # 314 # Revision 1.6 2004/12/16 17:59:38 cfmoro 315 # Encapsulation syntax fixed (_ replaced by __). Using tab indentation, in consistency with the rest of gnumed files 316 # 317 # Revision 1.5 2004/12/13 19:37:08 ncq 318 # - cleanup after review by Carlos 319 # - will be moved to main trunk RSN 320 # 321 # 322