fromtypingimportAny,NamedTuple,TypeVarT=TypeVar("T")# Unbound parameters or Instrument parametersParameterKey=str|tuple[str,str]ParameterDict=dict[ParameterKey,T]Snapshot=dict[str,Any]
[docs]classParameterDiff(NamedTuple):# Cannot be generic in Python < 3.7:# https://stackoverflow.com/questions/50530959/generic-namedtuple-in-python-3-6left_only:ParameterDict[Any]right_only:ParameterDict[Any]changed:ParameterDict[tuple[Any,Any]]
[docs]defextract_param_values(snapshot:Snapshot)->dict[ParameterKey,Any]:""" Given a snapshot, returns a dictionary from instrument and parameter names onto parameter values. """parameters={}snapshot=snapshot.get("station",snapshot)forparam_name,paraminsnapshot["parameters"].items():parameters[param_name]=param["value"]if"instruments"insnapshot:forinstrument_name,instrumentinsnapshot["instruments"].items():forparam_name,paramininstrument["parameters"].items():if"value"inparam:parameters[instrument_name,param_name]=param["value"]returnparameters
[docs]defdiff_param_values(left_snapshot:Snapshot,right_snapshot:Snapshot)->ParameterDiff:""" Given two snapshots, returns the differences between parameter values in each. """left_params,right_params=map(extract_param_values,(left_snapshot,right_snapshot))left_keys,right_keys=(set(params.keys())forparamsin(left_params,right_params))common_keys=left_keys.intersection(right_keys)returnParameterDiff(left_only={key:left_params[key]forkeyinleft_keys.difference(common_keys)},right_only={key:right_params[key]forkeyinright_keys.difference(common_keys)},changed={key:(left_params[key],right_params[key])forkeyincommon_keysifleft_params[key]!=right_params[key]},)