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