"""Utilities for writing Stan Json files"""try:importujsonasjsonuj_version=tuple(map(int,json.__version__.split(".")))ifuj_version<(5,5,0):raiseImportError("ujson version too old")# pragma: no coverUJSON_AVAILABLE=Trueexcept:UJSON_AVAILABLE=FalseimportjsonfromtypingimportAny,Mappingimportnumpyasnpdefprocess_dictionary(d:Mapping[str,Any])->Mapping[str,Any]:return{k:process_value(v)fork,vind.items()}# pylint: disable=too-many-return-statementsdefprocess_value(val:Any)->Any:ifvalisNone:returnNoneifisinstance(val,bool):# stan uses 0, 1returnint(val)ifisinstance(val,complex):# treat as 2-long arrayreturn[val.real,val.imag]ifisinstance(val,dict):# if a tuple was manually specifiedreturnprocess_dictionary(val)ifisinstance(val,tuple):# otherwise, turn a tuple into a dictreturndict(zip(range(1,len(val)+1),map(process_value,val)))ifisinstance(val,list):return[process_value(i)foriinval]original_module=getattr(type(val),"__module__","")if("numpy"inoriginal_moduleor"xarray"inoriginal_moduleor"pandas"inoriginal_module):numpy_val=np.asanyarray(val)# fast paths for numeric typesifnumpy_val.dtype.kindin"iuf":returnnumpy_val.tolist()ifnumpy_val.dtype.kind=="c":returnnp.stack([np.asarray(numpy_val.real),np.asarray(numpy_val.imag)],axis=-1).tolist()ifnumpy_val.dtype.kind=="b":returnnumpy_val.astype(int).tolist()# should only be object arrays (tuples, etc)returnprocess_value(numpy_val.tolist())returnvaldefdump_stan_json(data:Mapping[str,Any])->str:""" Convert a mapping of strings to data to a JSON string. Values can be any numeric type, a boolean (converted to int), or any collection compatible with :func:`numpy.asarray`, e.g a :class:`pandas.Series`. Produces a string compatible with the `Json Format for Cmdstan <https://mc-stan.org/docs/cmdstan-guide/json.html>`__ :param data: A mapping from strings to values. This can be a dictionary or something more exotic like an :class:`xarray.Dataset`. This will be copied before type conversion, not modified """returnjson.dumps(process_dictionary(data))
[docs]defwrite_stan_json(path:str,data:Mapping[str,Any])->None:""" Dump a mapping of strings to data to a JSON file. Values can be any numeric type, a boolean (converted to int), or any collection compatible with :func:`numpy.asarray`, e.g a :class:`pandas.Series`. Produces a file compatible with the `Json Format for Cmdstan <https://mc-stan.org/docs/cmdstan-guide/json.html>`__ :param path: File path for the created json. Will be overwritten if already in existence. :param data: A mapping from strings to values. This can be a dictionary or something more exotic like an :class:`xarray.Dataset`. This will be copied before type conversion, not modified """withopen(path,"w")asfd:ifUJSON_AVAILABLE:json.dump(process_dictionary(data),fd)else:forchunkinjson.JSONEncoder().iterencode(process_dictionary(data)):fd.write(chunk)