diff --git a/docs/pyerrors/input/json.html b/docs/pyerrors/input/json.html index 29da7a98..84c3fc5a 100644 --- a/docs/pyerrors/input/json.html +++ b/docs/pyerrors/input/json.html @@ -279,519 +279,524 @@ 186 else: 187 raise Exception("Unkown datatype.") 188 -189 if indent: -190 return json.dumps(d, indent=indent, ensure_ascii=False, write_mode=json.WM_SINGLE_LINE_ARRAY) -191 else: -192 return json.dumps(d, indent=indent, ensure_ascii=False, write_mode=json.WM_COMPACT) +189 def _jsonifier(o): +190 if isinstance(o, np.int64): +191 return int(o) +192 raise TypeError('%r is not JSON serializable' % o) 193 -194 -195def dump_to_json(ol, fname, description='', indent=1, gz=True): -196 """Export a list of Obs or structures containing Obs to a .json(.gz) file -197 -198 Parameters -199 ---------- -200 ol : list -201 List of objects that will be exported. At the moment, these objects can be -202 either of: Obs, list, numpy.ndarray, Corr. -203 All Obs inside a structure have to be defined on the same set of configurations. -204 fname : str -205 Filename of the output file. -206 description : str -207 Optional string that describes the contents of the json file. -208 indent : int -209 Specify the indentation level of the json file. None or 0 is permissible and -210 saves disk space. -211 gz : bool -212 If True, the output is a gzipped json. If False, the output is a json file. -213 """ -214 -215 jsonstring = create_json_string(ol, description, indent) -216 -217 if not fname.endswith('.json') and not fname.endswith('.gz'): -218 fname += '.json' +194 if indent: +195 return json.dumps(d, indent=indent, ensure_ascii=False, default=_jsonifier, write_mode=json.WM_SINGLE_LINE_ARRAY) +196 else: +197 return json.dumps(d, indent=indent, ensure_ascii=False, default=_jsonifier, write_mode=json.WM_COMPACT) +198 +199 +200def dump_to_json(ol, fname, description='', indent=1, gz=True): +201 """Export a list of Obs or structures containing Obs to a .json(.gz) file +202 +203 Parameters +204 ---------- +205 ol : list +206 List of objects that will be exported. At the moment, these objects can be +207 either of: Obs, list, numpy.ndarray, Corr. +208 All Obs inside a structure have to be defined on the same set of configurations. +209 fname : str +210 Filename of the output file. +211 description : str +212 Optional string that describes the contents of the json file. +213 indent : int +214 Specify the indentation level of the json file. None or 0 is permissible and +215 saves disk space. +216 gz : bool +217 If True, the output is a gzipped json. If False, the output is a json file. +218 """ 219 -220 if gz: -221 if not fname.endswith('.gz'): -222 fname += '.gz' -223 -224 fp = gzip.open(fname, 'wb') -225 fp.write(jsonstring.encode('utf-8')) -226 else: -227 fp = open(fname, 'w', encoding='utf-8') -228 fp.write(jsonstring) -229 fp.close() -230 -231 -232def _parse_json_dict(json_dict, verbose=True, full_output=False): -233 """Reconstruct a list of Obs or structures containing Obs from a dict that -234 was built out of a json string. +220 jsonstring = create_json_string(ol, description, indent) +221 +222 if not fname.endswith('.json') and not fname.endswith('.gz'): +223 fname += '.json' +224 +225 if gz: +226 if not fname.endswith('.gz'): +227 fname += '.gz' +228 +229 fp = gzip.open(fname, 'wb') +230 fp.write(jsonstring.encode('utf-8')) +231 else: +232 fp = open(fname, 'w', encoding='utf-8') +233 fp.write(jsonstring) +234 fp.close() 235 -236 The following structures are supported: Obs, list, numpy.ndarray, Corr -237 If the list contains only one element, it is unpacked from the list. -238 -239 Parameters -240 ---------- -241 json_string : str -242 json string containing the data. -243 verbose : bool -244 Print additional information that was written to the file. -245 full_output : bool -246 If True, a dict containing auxiliary information and the data is returned. -247 If False, only the data is returned. -248 """ -249 -250 def _gen_obsd_from_datad(d): -251 retd = {} -252 if d: -253 retd['names'] = [] -254 retd['idl'] = [] -255 retd['deltas'] = [] -256 retd['is_merged'] = {} -257 for ens in d: -258 for rep in ens['replica']: -259 rep_name = rep['name'] -260 if len(rep_name) > len(ens["id"]): -261 if rep_name[len(ens["id"])] != "|": -262 tmp_list = list(rep_name) -263 tmp_list = tmp_list[:len(ens["id"])] + ["|"] + tmp_list[len(ens["id"]):] -264 rep_name = ''.join(tmp_list) -265 retd['names'].append(rep_name) -266 retd['idl'].append([di[0] for di in rep['deltas']]) -267 retd['deltas'].append(np.array([di[1:] for di in rep['deltas']])) -268 retd['is_merged'][rep_name] = rep.get('is_merged', False) -269 return retd -270 -271 def _gen_covobsd_from_cdatad(d): -272 retd = {} -273 for ens in d: -274 retl = [] -275 name = ens['id'] -276 layouts = ens.get('layout', '1').strip() -277 layout = [int(ls.strip()) for ls in layouts.split(',') if len(ls) > 0] -278 cov = np.reshape(ens['cov'], layout) -279 grad = ens['grad'] -280 nobs = len(grad[0]) -281 for i in range(nobs): -282 retl.append({'name': name, 'cov': cov, 'grad': [g[i] for g in grad]}) -283 retd[name] = retl -284 return retd -285 -286 def get_Obs_from_dict(o): -287 layouts = o.get('layout', '1').strip() -288 if layouts != '1': -289 raise Exception("layout is %s has to be 1 for type Obs." % (layouts), RuntimeWarning) +236 +237def _parse_json_dict(json_dict, verbose=True, full_output=False): +238 """Reconstruct a list of Obs or structures containing Obs from a dict that +239 was built out of a json string. +240 +241 The following structures are supported: Obs, list, numpy.ndarray, Corr +242 If the list contains only one element, it is unpacked from the list. +243 +244 Parameters +245 ---------- +246 json_string : str +247 json string containing the data. +248 verbose : bool +249 Print additional information that was written to the file. +250 full_output : bool +251 If True, a dict containing auxiliary information and the data is returned. +252 If False, only the data is returned. +253 """ +254 +255 def _gen_obsd_from_datad(d): +256 retd = {} +257 if d: +258 retd['names'] = [] +259 retd['idl'] = [] +260 retd['deltas'] = [] +261 retd['is_merged'] = {} +262 for ens in d: +263 for rep in ens['replica']: +264 rep_name = rep['name'] +265 if len(rep_name) > len(ens["id"]): +266 if rep_name[len(ens["id"])] != "|": +267 tmp_list = list(rep_name) +268 tmp_list = tmp_list[:len(ens["id"])] + ["|"] + tmp_list[len(ens["id"]):] +269 rep_name = ''.join(tmp_list) +270 retd['names'].append(rep_name) +271 retd['idl'].append([di[0] for di in rep['deltas']]) +272 retd['deltas'].append(np.array([di[1:] for di in rep['deltas']])) +273 retd['is_merged'][rep_name] = rep.get('is_merged', False) +274 return retd +275 +276 def _gen_covobsd_from_cdatad(d): +277 retd = {} +278 for ens in d: +279 retl = [] +280 name = ens['id'] +281 layouts = ens.get('layout', '1').strip() +282 layout = [int(ls.strip()) for ls in layouts.split(',') if len(ls) > 0] +283 cov = np.reshape(ens['cov'], layout) +284 grad = ens['grad'] +285 nobs = len(grad[0]) +286 for i in range(nobs): +287 retl.append({'name': name, 'cov': cov, 'grad': [g[i] for g in grad]}) +288 retd[name] = retl +289 return retd 290 -291 values = o['value'] -292 od = _gen_obsd_from_datad(o.get('data', {})) -293 cd = _gen_covobsd_from_cdatad(o.get('cdata', {})) -294 -295 if od: -296 ret = Obs([[ddi[0] + values[0] for ddi in di] for di in od['deltas']], od['names'], idl=od['idl']) -297 ret._value = values[0] -298 ret.is_merged = od['is_merged'] -299 else: -300 ret = Obs([], [], means=[]) -301 ret._value = values[0] -302 for name in cd: -303 co = cd[name][0] -304 ret._covobs[name] = Covobs(None, co['cov'], co['name'], grad=co['grad']) -305 ret.names.append(co['name']) -306 -307 ret.reweighted = o.get('reweighted', False) -308 ret.tag = o.get('tag', [None])[0] -309 return ret -310 -311 def get_List_from_dict(o): -312 layouts = o.get('layout', '1').strip() -313 layout = int(layouts) -314 values = o['value'] -315 od = _gen_obsd_from_datad(o.get('data', {})) -316 cd = _gen_covobsd_from_cdatad(o.get('cdata', {})) -317 -318 ret = [] -319 taglist = o.get('tag', layout * [None]) -320 for i in range(layout): -321 if od: -322 ret.append(Obs([list(di[:, i] + values[i]) for di in od['deltas']], od['names'], idl=od['idl'])) -323 ret[-1]._value = values[i] -324 ret[-1].is_merged = od['is_merged'] -325 else: -326 ret.append(Obs([], [], means=[])) -327 ret[-1]._value = values[i] -328 print('Created Obs with means= ', values[i]) -329 for name in cd: -330 co = cd[name][i] -331 ret[-1]._covobs[name] = Covobs(None, co['cov'], co['name'], grad=co['grad']) -332 ret[-1].names.append(co['name']) -333 -334 ret[-1].reweighted = o.get('reweighted', False) -335 ret[-1].tag = taglist[i] -336 return ret -337 -338 def get_Array_from_dict(o): -339 layouts = o.get('layout', '1').strip() -340 layout = [int(ls.strip()) for ls in layouts.split(',') if len(ls) > 0] -341 N = np.prod(layout) -342 values = o['value'] -343 od = _gen_obsd_from_datad(o.get('data', {})) -344 cd = _gen_covobsd_from_cdatad(o.get('cdata', {})) -345 -346 ret = [] -347 taglist = o.get('tag', N * [None]) -348 for i in range(N): -349 if od: -350 ret.append(Obs([di[:, i] + values[i] for di in od['deltas']], od['names'], idl=od['idl'])) -351 ret[-1]._value = values[i] -352 ret[-1].is_merged = od['is_merged'] -353 else: -354 ret.append(Obs([], [], means=[])) -355 ret[-1]._value = values[i] -356 for name in cd: -357 co = cd[name][i] -358 ret[-1]._covobs[name] = Covobs(None, co['cov'], co['name'], grad=co['grad']) -359 ret[-1].names.append(co['name']) -360 ret[-1].reweighted = o.get('reweighted', False) -361 ret[-1].tag = taglist[i] -362 return np.reshape(ret, layout) -363 -364 def get_Corr_from_dict(o): -365 if isinstance(o.get('tag'), list): # supports the old way -366 taglist = o.get('tag') # This had to be modified to get the taglist from the dictionary -367 temp_prange = None -368 elif isinstance(o.get('tag'), dict): -369 tagdic = o.get('tag') -370 taglist = tagdic['tag'] -371 if 'prange' in tagdic: -372 temp_prange = tagdic['prange'] -373 else: -374 temp_prange = None -375 else: -376 raise Exception("The tag is not a list or dict") -377 -378 corr_tag = taglist[-1] -379 tmp_o = o -380 tmp_o['tag'] = taglist[:-1] -381 if len(tmp_o['tag']) == 0: -382 del tmp_o['tag'] -383 dat = get_Array_from_dict(tmp_o) -384 my_corr = Corr([None if np.isnan(o.ravel()[0].value) else o for o in list(dat)]) -385 if corr_tag != 'None': -386 my_corr.tag = corr_tag -387 -388 my_corr.prange = temp_prange -389 return my_corr -390 -391 prog = json_dict.get('program', '') -392 version = json_dict.get('version', '') -393 who = json_dict.get('who', '') -394 date = json_dict.get('date', '') -395 host = json_dict.get('host', '') -396 if prog and verbose: -397 print('Data has been written using %s.' % (prog)) -398 if version and verbose: -399 print('Format version %s' % (version)) -400 if np.any([who, date, host] and verbose): -401 print('Written by %s on %s on host %s' % (who, date, host)) -402 description = json_dict.get('description', '') -403 if description and verbose: -404 print() -405 print('Description: ', description) -406 obsdata = json_dict['obsdata'] -407 ol = [] -408 for io in obsdata: -409 if io['type'] == 'Obs': -410 ol.append(get_Obs_from_dict(io)) -411 elif io['type'] == 'List': -412 ol.append(get_List_from_dict(io)) -413 elif io['type'] == 'Array': -414 ol.append(get_Array_from_dict(io)) -415 elif io['type'] == 'Corr': -416 ol.append(get_Corr_from_dict(io)) -417 else: -418 raise Exception("Unkown datatype.") -419 -420 if full_output: -421 retd = {} -422 retd['program'] = prog -423 retd['version'] = version -424 retd['who'] = who -425 retd['date'] = date -426 retd['host'] = host -427 retd['description'] = description -428 retd['obsdata'] = ol -429 -430 return retd -431 else: -432 if len(obsdata) == 1: -433 ol = ol[0] +291 def get_Obs_from_dict(o): +292 layouts = o.get('layout', '1').strip() +293 if layouts != '1': +294 raise Exception("layout is %s has to be 1 for type Obs." % (layouts), RuntimeWarning) +295 +296 values = o['value'] +297 od = _gen_obsd_from_datad(o.get('data', {})) +298 cd = _gen_covobsd_from_cdatad(o.get('cdata', {})) +299 +300 if od: +301 ret = Obs([[ddi[0] + values[0] for ddi in di] for di in od['deltas']], od['names'], idl=od['idl']) +302 ret._value = values[0] +303 ret.is_merged = od['is_merged'] +304 else: +305 ret = Obs([], [], means=[]) +306 ret._value = values[0] +307 for name in cd: +308 co = cd[name][0] +309 ret._covobs[name] = Covobs(None, co['cov'], co['name'], grad=co['grad']) +310 ret.names.append(co['name']) +311 +312 ret.reweighted = o.get('reweighted', False) +313 ret.tag = o.get('tag', [None])[0] +314 return ret +315 +316 def get_List_from_dict(o): +317 layouts = o.get('layout', '1').strip() +318 layout = int(layouts) +319 values = o['value'] +320 od = _gen_obsd_from_datad(o.get('data', {})) +321 cd = _gen_covobsd_from_cdatad(o.get('cdata', {})) +322 +323 ret = [] +324 taglist = o.get('tag', layout * [None]) +325 for i in range(layout): +326 if od: +327 ret.append(Obs([list(di[:, i] + values[i]) for di in od['deltas']], od['names'], idl=od['idl'])) +328 ret[-1]._value = values[i] +329 ret[-1].is_merged = od['is_merged'] +330 else: +331 ret.append(Obs([], [], means=[])) +332 ret[-1]._value = values[i] +333 print('Created Obs with means= ', values[i]) +334 for name in cd: +335 co = cd[name][i] +336 ret[-1]._covobs[name] = Covobs(None, co['cov'], co['name'], grad=co['grad']) +337 ret[-1].names.append(co['name']) +338 +339 ret[-1].reweighted = o.get('reweighted', False) +340 ret[-1].tag = taglist[i] +341 return ret +342 +343 def get_Array_from_dict(o): +344 layouts = o.get('layout', '1').strip() +345 layout = [int(ls.strip()) for ls in layouts.split(',') if len(ls) > 0] +346 N = np.prod(layout) +347 values = o['value'] +348 od = _gen_obsd_from_datad(o.get('data', {})) +349 cd = _gen_covobsd_from_cdatad(o.get('cdata', {})) +350 +351 ret = [] +352 taglist = o.get('tag', N * [None]) +353 for i in range(N): +354 if od: +355 ret.append(Obs([di[:, i] + values[i] for di in od['deltas']], od['names'], idl=od['idl'])) +356 ret[-1]._value = values[i] +357 ret[-1].is_merged = od['is_merged'] +358 else: +359 ret.append(Obs([], [], means=[])) +360 ret[-1]._value = values[i] +361 for name in cd: +362 co = cd[name][i] +363 ret[-1]._covobs[name] = Covobs(None, co['cov'], co['name'], grad=co['grad']) +364 ret[-1].names.append(co['name']) +365 ret[-1].reweighted = o.get('reweighted', False) +366 ret[-1].tag = taglist[i] +367 return np.reshape(ret, layout) +368 +369 def get_Corr_from_dict(o): +370 if isinstance(o.get('tag'), list): # supports the old way +371 taglist = o.get('tag') # This had to be modified to get the taglist from the dictionary +372 temp_prange = None +373 elif isinstance(o.get('tag'), dict): +374 tagdic = o.get('tag') +375 taglist = tagdic['tag'] +376 if 'prange' in tagdic: +377 temp_prange = tagdic['prange'] +378 else: +379 temp_prange = None +380 else: +381 raise Exception("The tag is not a list or dict") +382 +383 corr_tag = taglist[-1] +384 tmp_o = o +385 tmp_o['tag'] = taglist[:-1] +386 if len(tmp_o['tag']) == 0: +387 del tmp_o['tag'] +388 dat = get_Array_from_dict(tmp_o) +389 my_corr = Corr([None if np.isnan(o.ravel()[0].value) else o for o in list(dat)]) +390 if corr_tag != 'None': +391 my_corr.tag = corr_tag +392 +393 my_corr.prange = temp_prange +394 return my_corr +395 +396 prog = json_dict.get('program', '') +397 version = json_dict.get('version', '') +398 who = json_dict.get('who', '') +399 date = json_dict.get('date', '') +400 host = json_dict.get('host', '') +401 if prog and verbose: +402 print('Data has been written using %s.' % (prog)) +403 if version and verbose: +404 print('Format version %s' % (version)) +405 if np.any([who, date, host] and verbose): +406 print('Written by %s on %s on host %s' % (who, date, host)) +407 description = json_dict.get('description', '') +408 if description and verbose: +409 print() +410 print('Description: ', description) +411 obsdata = json_dict['obsdata'] +412 ol = [] +413 for io in obsdata: +414 if io['type'] == 'Obs': +415 ol.append(get_Obs_from_dict(io)) +416 elif io['type'] == 'List': +417 ol.append(get_List_from_dict(io)) +418 elif io['type'] == 'Array': +419 ol.append(get_Array_from_dict(io)) +420 elif io['type'] == 'Corr': +421 ol.append(get_Corr_from_dict(io)) +422 else: +423 raise Exception("Unkown datatype.") +424 +425 if full_output: +426 retd = {} +427 retd['program'] = prog +428 retd['version'] = version +429 retd['who'] = who +430 retd['date'] = date +431 retd['host'] = host +432 retd['description'] = description +433 retd['obsdata'] = ol 434 -435 return ol -436 -437 -438def import_json_string(json_string, verbose=True, full_output=False): -439 """Reconstruct a list of Obs or structures containing Obs from a json string. -440 -441 The following structures are supported: Obs, list, numpy.ndarray, Corr -442 If the list contains only one element, it is unpacked from the list. -443 -444 Parameters -445 ---------- -446 json_string : str -447 json string containing the data. -448 verbose : bool -449 Print additional information that was written to the file. -450 full_output : bool -451 If True, a dict containing auxiliary information and the data is returned. -452 If False, only the data is returned. -453 """ -454 -455 return _parse_json_dict(json.loads(json_string), verbose, full_output) -456 -457 -458def load_json(fname, verbose=True, gz=True, full_output=False): -459 """Import a list of Obs or structures containing Obs from a .json(.gz) file. -460 -461 The following structures are supported: Obs, list, numpy.ndarray, Corr -462 If the list contains only one element, it is unpacked from the list. -463 -464 Parameters -465 ---------- -466 fname : str -467 Filename of the input file. -468 verbose : bool -469 Print additional information that was written to the file. -470 gz : bool -471 If True, assumes that data is gzipped. If False, assumes JSON file. -472 full_output : bool -473 If True, a dict containing auxiliary information and the data is returned. -474 If False, only the data is returned. -475 """ -476 if not fname.endswith('.json') and not fname.endswith('.gz'): -477 fname += '.json' -478 if gz: -479 if not fname.endswith('.gz'): -480 fname += '.gz' -481 with gzip.open(fname, 'r') as fin: -482 d = json.load(fin) -483 else: -484 if fname.endswith('.gz'): -485 warnings.warn("Trying to read from %s without unzipping!" % fname, UserWarning) -486 with open(fname, 'r', encoding='utf-8') as fin: -487 d = json.loads(fin.read()) -488 -489 return _parse_json_dict(d, verbose, full_output) -490 -491 -492def _ol_from_dict(ind, reps='DICTOBS'): -493 """Convert a dictionary of Obs objects to a list and a dictionary that contains -494 placeholders instead of the Obs objects. +435 return retd +436 else: +437 if len(obsdata) == 1: +438 ol = ol[0] +439 +440 return ol +441 +442 +443def import_json_string(json_string, verbose=True, full_output=False): +444 """Reconstruct a list of Obs or structures containing Obs from a json string. +445 +446 The following structures are supported: Obs, list, numpy.ndarray, Corr +447 If the list contains only one element, it is unpacked from the list. +448 +449 Parameters +450 ---------- +451 json_string : str +452 json string containing the data. +453 verbose : bool +454 Print additional information that was written to the file. +455 full_output : bool +456 If True, a dict containing auxiliary information and the data is returned. +457 If False, only the data is returned. +458 """ +459 +460 return _parse_json_dict(json.loads(json_string), verbose, full_output) +461 +462 +463def load_json(fname, verbose=True, gz=True, full_output=False): +464 """Import a list of Obs or structures containing Obs from a .json(.gz) file. +465 +466 The following structures are supported: Obs, list, numpy.ndarray, Corr +467 If the list contains only one element, it is unpacked from the list. +468 +469 Parameters +470 ---------- +471 fname : str +472 Filename of the input file. +473 verbose : bool +474 Print additional information that was written to the file. +475 gz : bool +476 If True, assumes that data is gzipped. If False, assumes JSON file. +477 full_output : bool +478 If True, a dict containing auxiliary information and the data is returned. +479 If False, only the data is returned. +480 """ +481 if not fname.endswith('.json') and not fname.endswith('.gz'): +482 fname += '.json' +483 if gz: +484 if not fname.endswith('.gz'): +485 fname += '.gz' +486 with gzip.open(fname, 'r') as fin: +487 d = json.load(fin) +488 else: +489 if fname.endswith('.gz'): +490 warnings.warn("Trying to read from %s without unzipping!" % fname, UserWarning) +491 with open(fname, 'r', encoding='utf-8') as fin: +492 d = json.loads(fin.read()) +493 +494 return _parse_json_dict(d, verbose, full_output) 495 -496 Parameters -497 ---------- -498 ind : dict -499 Dict of JSON valid structures and objects that will be exported. -500 At the moment, these object can be either of: Obs, list, numpy.ndarray, Corr. -501 All Obs inside a structure have to be defined on the same set of configurations. -502 reps : str -503 Specify the structure of the placeholder in exported dict to be reps[0-9]+. -504 """ -505 -506 obstypes = (Obs, Corr, np.ndarray) -507 -508 if not reps.isalnum(): -509 raise Exception('Placeholder string has to be alphanumeric!') -510 ol = [] -511 counter = 0 +496 +497def _ol_from_dict(ind, reps='DICTOBS'): +498 """Convert a dictionary of Obs objects to a list and a dictionary that contains +499 placeholders instead of the Obs objects. +500 +501 Parameters +502 ---------- +503 ind : dict +504 Dict of JSON valid structures and objects that will be exported. +505 At the moment, these object can be either of: Obs, list, numpy.ndarray, Corr. +506 All Obs inside a structure have to be defined on the same set of configurations. +507 reps : str +508 Specify the structure of the placeholder in exported dict to be reps[0-9]+. +509 """ +510 +511 obstypes = (Obs, Corr, np.ndarray) 512 -513 def dict_replace_obs(d): -514 nonlocal ol -515 nonlocal counter -516 x = {} -517 for k, v in d.items(): -518 if isinstance(v, dict): -519 v = dict_replace_obs(v) -520 elif isinstance(v, list) and all([isinstance(o, Obs) for o in v]): -521 v = obslist_replace_obs(v) -522 elif isinstance(v, list): -523 v = list_replace_obs(v) -524 elif isinstance(v, obstypes): -525 ol.append(v) -526 v = reps + '%d' % (counter) -527 counter += 1 -528 elif isinstance(v, str): -529 if bool(re.match(r'%s[0-9]+' % (reps), v)): -530 raise Exception('Dict contains string %s that matches the placeholder! %s Cannot be savely exported.' % (v, reps)) -531 x[k] = v -532 return x -533 -534 def list_replace_obs(li): -535 nonlocal ol -536 nonlocal counter -537 x = [] -538 for e in li: -539 if isinstance(e, list): -540 e = list_replace_obs(e) -541 elif isinstance(e, list) and all([isinstance(o, Obs) for o in e]): -542 e = obslist_replace_obs(e) -543 elif isinstance(e, dict): -544 e = dict_replace_obs(e) -545 elif isinstance(e, obstypes): -546 ol.append(e) -547 e = reps + '%d' % (counter) -548 counter += 1 -549 elif isinstance(e, str): -550 if bool(re.match(r'%s[0-9]+' % (reps), e)): -551 raise Exception('Dict contains string %s that matches the placeholder! %s Cannot be savely exported.' % (e, reps)) -552 x.append(e) -553 return x -554 -555 def obslist_replace_obs(li): -556 nonlocal ol -557 nonlocal counter -558 il = [] -559 for e in li: -560 il.append(e) -561 -562 ol.append(il) -563 x = reps + '%d' % (counter) -564 counter += 1 -565 return x +513 if not reps.isalnum(): +514 raise Exception('Placeholder string has to be alphanumeric!') +515 ol = [] +516 counter = 0 +517 +518 def dict_replace_obs(d): +519 nonlocal ol +520 nonlocal counter +521 x = {} +522 for k, v in d.items(): +523 if isinstance(v, dict): +524 v = dict_replace_obs(v) +525 elif isinstance(v, list) and all([isinstance(o, Obs) for o in v]): +526 v = obslist_replace_obs(v) +527 elif isinstance(v, list): +528 v = list_replace_obs(v) +529 elif isinstance(v, obstypes): +530 ol.append(v) +531 v = reps + '%d' % (counter) +532 counter += 1 +533 elif isinstance(v, str): +534 if bool(re.match(r'%s[0-9]+' % (reps), v)): +535 raise Exception('Dict contains string %s that matches the placeholder! %s Cannot be savely exported.' % (v, reps)) +536 x[k] = v +537 return x +538 +539 def list_replace_obs(li): +540 nonlocal ol +541 nonlocal counter +542 x = [] +543 for e in li: +544 if isinstance(e, list): +545 e = list_replace_obs(e) +546 elif isinstance(e, list) and all([isinstance(o, Obs) for o in e]): +547 e = obslist_replace_obs(e) +548 elif isinstance(e, dict): +549 e = dict_replace_obs(e) +550 elif isinstance(e, obstypes): +551 ol.append(e) +552 e = reps + '%d' % (counter) +553 counter += 1 +554 elif isinstance(e, str): +555 if bool(re.match(r'%s[0-9]+' % (reps), e)): +556 raise Exception('Dict contains string %s that matches the placeholder! %s Cannot be savely exported.' % (e, reps)) +557 x.append(e) +558 return x +559 +560 def obslist_replace_obs(li): +561 nonlocal ol +562 nonlocal counter +563 il = [] +564 for e in li: +565 il.append(e) 566 -567 nd = dict_replace_obs(ind) -568 -569 return ol, nd -570 +567 ol.append(il) +568 x = reps + '%d' % (counter) +569 counter += 1 +570 return x 571 -572def dump_dict_to_json(od, fname, description='', indent=1, reps='DICTOBS', gz=True): -573 """Export a dict of Obs or structures containing Obs to a .json(.gz) file -574 -575 Parameters -576 ---------- -577 od : dict -578 Dict of JSON valid structures and objects that will be exported. -579 At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. -580 All Obs inside a structure have to be defined on the same set of configurations. -581 fname : str -582 Filename of the output file. -583 description : str -584 Optional string that describes the contents of the json file. -585 indent : int -586 Specify the indentation level of the json file. None or 0 is permissible and -587 saves disk space. -588 reps : str -589 Specify the structure of the placeholder in exported dict to be reps[0-9]+. -590 gz : bool -591 If True, the output is a gzipped json. If False, the output is a json file. -592 """ -593 -594 if not isinstance(od, dict): -595 raise Exception('od has to be a dictionary. Did you want to use dump_to_json?') -596 -597 infostring = ('This JSON file contains a python dictionary that has been parsed to a list of structures. ' -598 'OBSDICT contains the dictionary, where Obs or other structures have been replaced by ' -599 '' + reps + '[0-9]+. The field description contains the additional description of this JSON file. ' -600 'This file may be parsed to a dict with the pyerrors routine load_json_dict.') +572 nd = dict_replace_obs(ind) +573 +574 return ol, nd +575 +576 +577def dump_dict_to_json(od, fname, description='', indent=1, reps='DICTOBS', gz=True): +578 """Export a dict of Obs or structures containing Obs to a .json(.gz) file +579 +580 Parameters +581 ---------- +582 od : dict +583 Dict of JSON valid structures and objects that will be exported. +584 At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. +585 All Obs inside a structure have to be defined on the same set of configurations. +586 fname : str +587 Filename of the output file. +588 description : str +589 Optional string that describes the contents of the json file. +590 indent : int +591 Specify the indentation level of the json file. None or 0 is permissible and +592 saves disk space. +593 reps : str +594 Specify the structure of the placeholder in exported dict to be reps[0-9]+. +595 gz : bool +596 If True, the output is a gzipped json. If False, the output is a json file. +597 """ +598 +599 if not isinstance(od, dict): +600 raise Exception('od has to be a dictionary. Did you want to use dump_to_json?') 601 -602 desc_dict = {'INFO': infostring, 'OBSDICT': {}, 'description': description} -603 ol, desc_dict['OBSDICT'] = _ol_from_dict(od, reps=reps) -604 -605 dump_to_json(ol, fname, description=desc_dict, indent=indent, gz=gz) +602 infostring = ('This JSON file contains a python dictionary that has been parsed to a list of structures. ' +603 'OBSDICT contains the dictionary, where Obs or other structures have been replaced by ' +604 '' + reps + '[0-9]+. The field description contains the additional description of this JSON file. ' +605 'This file may be parsed to a dict with the pyerrors routine load_json_dict.') 606 -607 -608def _od_from_list_and_dict(ol, ind, reps='DICTOBS'): -609 """Parse a list of Obs or structures containing Obs and an accompanying -610 dict, where the structures have been replaced by placeholders to a -611 dict that contains the structures. +607 desc_dict = {'INFO': infostring, 'OBSDICT': {}, 'description': description} +608 ol, desc_dict['OBSDICT'] = _ol_from_dict(od, reps=reps) +609 +610 dump_to_json(ol, fname, description=desc_dict, indent=indent, gz=gz) +611 612 -613 The following structures are supported: Obs, list, numpy.ndarray, Corr -614 -615 Parameters -616 ---------- -617 ol : list -618 List of objects - -619 At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. -620 All Obs inside a structure have to be defined on the same set of configurations. -621 ind : dict -622 Dict that defines the structure of the resulting dict and contains placeholders -623 reps : str -624 Specify the structure of the placeholder in imported dict to be reps[0-9]+. -625 """ -626 if not reps.isalnum(): -627 raise Exception('Placeholder string has to be alphanumeric!') -628 -629 counter = 0 -630 -631 def dict_replace_string(d): -632 nonlocal counter -633 nonlocal ol -634 x = {} -635 for k, v in d.items(): -636 if isinstance(v, dict): -637 v = dict_replace_string(v) -638 elif isinstance(v, list): -639 v = list_replace_string(v) -640 elif isinstance(v, str) and bool(re.match(r'%s[0-9]+' % (reps), v)): -641 index = int(v[len(reps):]) -642 v = ol[index] -643 counter += 1 -644 x[k] = v -645 return x -646 -647 def list_replace_string(li): -648 nonlocal counter -649 nonlocal ol -650 x = [] -651 for e in li: -652 if isinstance(e, list): -653 e = list_replace_string(e) -654 elif isinstance(e, dict): -655 e = dict_replace_string(e) -656 elif isinstance(e, str) and bool(re.match(r'%s[0-9]+' % (reps), e)): -657 index = int(e[len(reps):]) -658 e = ol[index] -659 counter += 1 -660 x.append(e) -661 return x -662 -663 nd = dict_replace_string(ind) -664 -665 if counter == 0: -666 raise Exception('No placeholder has been replaced! Check if reps is set correctly.') +613def _od_from_list_and_dict(ol, ind, reps='DICTOBS'): +614 """Parse a list of Obs or structures containing Obs and an accompanying +615 dict, where the structures have been replaced by placeholders to a +616 dict that contains the structures. +617 +618 The following structures are supported: Obs, list, numpy.ndarray, Corr +619 +620 Parameters +621 ---------- +622 ol : list +623 List of objects - +624 At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. +625 All Obs inside a structure have to be defined on the same set of configurations. +626 ind : dict +627 Dict that defines the structure of the resulting dict and contains placeholders +628 reps : str +629 Specify the structure of the placeholder in imported dict to be reps[0-9]+. +630 """ +631 if not reps.isalnum(): +632 raise Exception('Placeholder string has to be alphanumeric!') +633 +634 counter = 0 +635 +636 def dict_replace_string(d): +637 nonlocal counter +638 nonlocal ol +639 x = {} +640 for k, v in d.items(): +641 if isinstance(v, dict): +642 v = dict_replace_string(v) +643 elif isinstance(v, list): +644 v = list_replace_string(v) +645 elif isinstance(v, str) and bool(re.match(r'%s[0-9]+' % (reps), v)): +646 index = int(v[len(reps):]) +647 v = ol[index] +648 counter += 1 +649 x[k] = v +650 return x +651 +652 def list_replace_string(li): +653 nonlocal counter +654 nonlocal ol +655 x = [] +656 for e in li: +657 if isinstance(e, list): +658 e = list_replace_string(e) +659 elif isinstance(e, dict): +660 e = dict_replace_string(e) +661 elif isinstance(e, str) and bool(re.match(r'%s[0-9]+' % (reps), e)): +662 index = int(e[len(reps):]) +663 e = ol[index] +664 counter += 1 +665 x.append(e) +666 return x 667 -668 return nd +668 nd = dict_replace_string(ind) 669 -670 -671def load_json_dict(fname, verbose=True, gz=True, full_output=False, reps='DICTOBS'): -672 """Import a dict of Obs or structures containing Obs from a .json(.gz) file. -673 -674 The following structures are supported: Obs, list, numpy.ndarray, Corr +670 if counter == 0: +671 raise Exception('No placeholder has been replaced! Check if reps is set correctly.') +672 +673 return nd +674 675 -676 Parameters -677 ---------- -678 fname : str -679 Filename of the input file. -680 verbose : bool -681 Print additional information that was written to the file. -682 gz : bool -683 If True, assumes that data is gzipped. If False, assumes JSON file. -684 full_output : bool -685 If True, a dict containing auxiliary information and the data is returned. -686 If False, only the data is returned. -687 reps : str -688 Specify the structure of the placeholder in imported dict to be reps[0-9]+. -689 """ -690 indata = load_json(fname, verbose=verbose, gz=gz, full_output=True) -691 description = indata['description']['description'] -692 indict = indata['description']['OBSDICT'] -693 ol = indata['obsdata'] -694 od = _od_from_list_and_dict(ol, indict, reps=reps) -695 -696 if full_output: -697 indata['description'] = description -698 indata['obsdata'] = od -699 return indata -700 else: -701 return od +676def load_json_dict(fname, verbose=True, gz=True, full_output=False, reps='DICTOBS'): +677 """Import a dict of Obs or structures containing Obs from a .json(.gz) file. +678 +679 The following structures are supported: Obs, list, numpy.ndarray, Corr +680 +681 Parameters +682 ---------- +683 fname : str +684 Filename of the input file. +685 verbose : bool +686 Print additional information that was written to the file. +687 gz : bool +688 If True, assumes that data is gzipped. If False, assumes JSON file. +689 full_output : bool +690 If True, a dict containing auxiliary information and the data is returned. +691 If False, only the data is returned. +692 reps : str +693 Specify the structure of the placeholder in imported dict to be reps[0-9]+. +694 """ +695 indata = load_json(fname, verbose=verbose, gz=gz, full_output=True) +696 description = indata['description']['description'] +697 indict = indata['description']['OBSDICT'] +698 ol = indata['obsdata'] +699 od = _od_from_list_and_dict(ol, indict, reps=reps) +700 +701 if full_output: +702 indata['description'] = description +703 indata['obsdata'] = od +704 return indata +705 else: +706 return od @@ -979,10 +984,15 @@ 187 else: 188 raise Exception("Unkown datatype.") 189 -190 if indent: -191 return json.dumps(d, indent=indent, ensure_ascii=False, write_mode=json.WM_SINGLE_LINE_ARRAY) -192 else: -193 return json.dumps(d, indent=indent, ensure_ascii=False, write_mode=json.WM_COMPACT) +190 def _jsonifier(o): +191 if isinstance(o, np.int64): +192 return int(o) +193 raise TypeError('%r is not JSON serializable' % o) +194 +195 if indent: +196 return json.dumps(d, indent=indent, ensure_ascii=False, default=_jsonifier, write_mode=json.WM_SINGLE_LINE_ARRAY) +197 else: +198 return json.dumps(d, indent=indent, ensure_ascii=False, default=_jsonifier, write_mode=json.WM_COMPACT) @@ -1017,41 +1027,41 @@ saves disk space. -
196def dump_to_json(ol, fname, description='', indent=1, gz=True): -197 """Export a list of Obs or structures containing Obs to a .json(.gz) file -198 -199 Parameters -200 ---------- -201 ol : list -202 List of objects that will be exported. At the moment, these objects can be -203 either of: Obs, list, numpy.ndarray, Corr. -204 All Obs inside a structure have to be defined on the same set of configurations. -205 fname : str -206 Filename of the output file. -207 description : str -208 Optional string that describes the contents of the json file. -209 indent : int -210 Specify the indentation level of the json file. None or 0 is permissible and -211 saves disk space. -212 gz : bool -213 If True, the output is a gzipped json. If False, the output is a json file. -214 """ -215 -216 jsonstring = create_json_string(ol, description, indent) -217 -218 if not fname.endswith('.json') and not fname.endswith('.gz'): -219 fname += '.json' +@@ -1089,24 +1099,24 @@ If True, the output is a gzipped json. If False, the output is a json file.201def dump_to_json(ol, fname, description='', indent=1, gz=True): +202 """Export a list of Obs or structures containing Obs to a .json(.gz) file +203 +204 Parameters +205 ---------- +206 ol : list +207 List of objects that will be exported. At the moment, these objects can be +208 either of: Obs, list, numpy.ndarray, Corr. +209 All Obs inside a structure have to be defined on the same set of configurations. +210 fname : str +211 Filename of the output file. +212 description : str +213 Optional string that describes the contents of the json file. +214 indent : int +215 Specify the indentation level of the json file. None or 0 is permissible and +216 saves disk space. +217 gz : bool +218 If True, the output is a gzipped json. If False, the output is a json file. +219 """ 220 -221 if gz: -222 if not fname.endswith('.gz'): -223 fname += '.gz' -224 -225 fp = gzip.open(fname, 'wb') -226 fp.write(jsonstring.encode('utf-8')) -227 else: -228 fp = open(fname, 'w', encoding='utf-8') -229 fp.write(jsonstring) -230 fp.close() +221 jsonstring = create_json_string(ol, description, indent) +222 +223 if not fname.endswith('.json') and not fname.endswith('.gz'): +224 fname += '.json' +225 +226 if gz: +227 if not fname.endswith('.gz'): +228 fname += '.gz' +229 +230 fp = gzip.open(fname, 'wb') +231 fp.write(jsonstring.encode('utf-8')) +232 else: +233 fp = open(fname, 'w', encoding='utf-8') +234 fp.write(jsonstring) +235 fp.close()
439def import_json_string(json_string, verbose=True, full_output=False): -440 """Reconstruct a list of Obs or structures containing Obs from a json string. -441 -442 The following structures are supported: Obs, list, numpy.ndarray, Corr -443 If the list contains only one element, it is unpacked from the list. -444 -445 Parameters -446 ---------- -447 json_string : str -448 json string containing the data. -449 verbose : bool -450 Print additional information that was written to the file. -451 full_output : bool -452 If True, a dict containing auxiliary information and the data is returned. -453 If False, only the data is returned. -454 """ -455 -456 return _parse_json_dict(json.loads(json_string), verbose, full_output) +@@ -1141,38 +1151,38 @@ If False, only the data is returned.444def import_json_string(json_string, verbose=True, full_output=False): +445 """Reconstruct a list of Obs or structures containing Obs from a json string. +446 +447 The following structures are supported: Obs, list, numpy.ndarray, Corr +448 If the list contains only one element, it is unpacked from the list. +449 +450 Parameters +451 ---------- +452 json_string : str +453 json string containing the data. +454 verbose : bool +455 Print additional information that was written to the file. +456 full_output : bool +457 If True, a dict containing auxiliary information and the data is returned. +458 If False, only the data is returned. +459 """ +460 +461 return _parse_json_dict(json.loads(json_string), verbose, full_output)
459def load_json(fname, verbose=True, gz=True, full_output=False): -460 """Import a list of Obs or structures containing Obs from a .json(.gz) file. -461 -462 The following structures are supported: Obs, list, numpy.ndarray, Corr -463 If the list contains only one element, it is unpacked from the list. -464 -465 Parameters -466 ---------- -467 fname : str -468 Filename of the input file. -469 verbose : bool -470 Print additional information that was written to the file. -471 gz : bool -472 If True, assumes that data is gzipped. If False, assumes JSON file. -473 full_output : bool -474 If True, a dict containing auxiliary information and the data is returned. -475 If False, only the data is returned. -476 """ -477 if not fname.endswith('.json') and not fname.endswith('.gz'): -478 fname += '.json' -479 if gz: -480 if not fname.endswith('.gz'): -481 fname += '.gz' -482 with gzip.open(fname, 'r') as fin: -483 d = json.load(fin) -484 else: -485 if fname.endswith('.gz'): -486 warnings.warn("Trying to read from %s without unzipping!" % fname, UserWarning) -487 with open(fname, 'r', encoding='utf-8') as fin: -488 d = json.loads(fin.read()) -489 -490 return _parse_json_dict(d, verbose, full_output) +@@ -1209,40 +1219,40 @@ If False, only the data is returned.464def load_json(fname, verbose=True, gz=True, full_output=False): +465 """Import a list of Obs or structures containing Obs from a .json(.gz) file. +466 +467 The following structures are supported: Obs, list, numpy.ndarray, Corr +468 If the list contains only one element, it is unpacked from the list. +469 +470 Parameters +471 ---------- +472 fname : str +473 Filename of the input file. +474 verbose : bool +475 Print additional information that was written to the file. +476 gz : bool +477 If True, assumes that data is gzipped. If False, assumes JSON file. +478 full_output : bool +479 If True, a dict containing auxiliary information and the data is returned. +480 If False, only the data is returned. +481 """ +482 if not fname.endswith('.json') and not fname.endswith('.gz'): +483 fname += '.json' +484 if gz: +485 if not fname.endswith('.gz'): +486 fname += '.gz' +487 with gzip.open(fname, 'r') as fin: +488 d = json.load(fin) +489 else: +490 if fname.endswith('.gz'): +491 warnings.warn("Trying to read from %s without unzipping!" % fname, UserWarning) +492 with open(fname, 'r', encoding='utf-8') as fin: +493 d = json.loads(fin.read()) +494 +495 return _parse_json_dict(d, verbose, full_output)
573def dump_dict_to_json(od, fname, description='', indent=1, reps='DICTOBS', gz=True): -574 """Export a dict of Obs or structures containing Obs to a .json(.gz) file -575 -576 Parameters -577 ---------- -578 od : dict -579 Dict of JSON valid structures and objects that will be exported. -580 At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. -581 All Obs inside a structure have to be defined on the same set of configurations. -582 fname : str -583 Filename of the output file. -584 description : str -585 Optional string that describes the contents of the json file. -586 indent : int -587 Specify the indentation level of the json file. None or 0 is permissible and -588 saves disk space. -589 reps : str -590 Specify the structure of the placeholder in exported dict to be reps[0-9]+. -591 gz : bool -592 If True, the output is a gzipped json. If False, the output is a json file. -593 """ -594 -595 if not isinstance(od, dict): -596 raise Exception('od has to be a dictionary. Did you want to use dump_to_json?') -597 -598 infostring = ('This JSON file contains a python dictionary that has been parsed to a list of structures. ' -599 'OBSDICT contains the dictionary, where Obs or other structures have been replaced by ' -600 '' + reps + '[0-9]+. The field description contains the additional description of this JSON file. ' -601 'This file may be parsed to a dict with the pyerrors routine load_json_dict.') +@@ -1282,37 +1292,37 @@ If True, the output is a gzipped json. If False, the output is a json file.578def dump_dict_to_json(od, fname, description='', indent=1, reps='DICTOBS', gz=True): +579 """Export a dict of Obs or structures containing Obs to a .json(.gz) file +580 +581 Parameters +582 ---------- +583 od : dict +584 Dict of JSON valid structures and objects that will be exported. +585 At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. +586 All Obs inside a structure have to be defined on the same set of configurations. +587 fname : str +588 Filename of the output file. +589 description : str +590 Optional string that describes the contents of the json file. +591 indent : int +592 Specify the indentation level of the json file. None or 0 is permissible and +593 saves disk space. +594 reps : str +595 Specify the structure of the placeholder in exported dict to be reps[0-9]+. +596 gz : bool +597 If True, the output is a gzipped json. If False, the output is a json file. +598 """ +599 +600 if not isinstance(od, dict): +601 raise Exception('od has to be a dictionary. Did you want to use dump_to_json?') 602 -603 desc_dict = {'INFO': infostring, 'OBSDICT': {}, 'description': description} -604 ol, desc_dict['OBSDICT'] = _ol_from_dict(od, reps=reps) -605 -606 dump_to_json(ol, fname, description=desc_dict, indent=indent, gz=gz) +603 infostring = ('This JSON file contains a python dictionary that has been parsed to a list of structures. ' +604 'OBSDICT contains the dictionary, where Obs or other structures have been replaced by ' +605 '' + reps + '[0-9]+. The field description contains the additional description of this JSON file. ' +606 'This file may be parsed to a dict with the pyerrors routine load_json_dict.') +607 +608 desc_dict = {'INFO': infostring, 'OBSDICT': {}, 'description': description} +609 ol, desc_dict['OBSDICT'] = _ol_from_dict(od, reps=reps) +610 +611 dump_to_json(ol, fname, description=desc_dict, indent=indent, gz=gz)
672def load_json_dict(fname, verbose=True, gz=True, full_output=False, reps='DICTOBS'): -673 """Import a dict of Obs or structures containing Obs from a .json(.gz) file. -674 -675 The following structures are supported: Obs, list, numpy.ndarray, Corr -676 -677 Parameters -678 ---------- -679 fname : str -680 Filename of the input file. -681 verbose : bool -682 Print additional information that was written to the file. -683 gz : bool -684 If True, assumes that data is gzipped. If False, assumes JSON file. -685 full_output : bool -686 If True, a dict containing auxiliary information and the data is returned. -687 If False, only the data is returned. -688 reps : str -689 Specify the structure of the placeholder in imported dict to be reps[0-9]+. -690 """ -691 indata = load_json(fname, verbose=verbose, gz=gz, full_output=True) -692 description = indata['description']['description'] -693 indict = indata['description']['OBSDICT'] -694 ol = indata['obsdata'] -695 od = _od_from_list_and_dict(ol, indict, reps=reps) -696 -697 if full_output: -698 indata['description'] = description -699 indata['obsdata'] = od -700 return indata -701 else: -702 return od +677def load_json_dict(fname, verbose=True, gz=True, full_output=False, reps='DICTOBS'): +678 """Import a dict of Obs or structures containing Obs from a .json(.gz) file. +679 +680 The following structures are supported: Obs, list, numpy.ndarray, Corr +681 +682 Parameters +683 ---------- +684 fname : str +685 Filename of the input file. +686 verbose : bool +687 Print additional information that was written to the file. +688 gz : bool +689 If True, assumes that data is gzipped. If False, assumes JSON file. +690 full_output : bool +691 If True, a dict containing auxiliary information and the data is returned. +692 If False, only the data is returned. +693 reps : str +694 Specify the structure of the placeholder in imported dict to be reps[0-9]+. +695 """ +696 indata = load_json(fname, verbose=verbose, gz=gz, full_output=True) +697 description = indata['description']['description'] +698 indict = indata['description']['OBSDICT'] +699 ol = indata['obsdata'] +700 od = _od_from_list_and_dict(ol, indict, reps=reps) +701 +702 if full_output: +703 indata['description'] = description +704 indata['obsdata'] = od +705 return indata +706 else: +707 return od