Source code for qcodes.utils.metadata

from typing import (

from .helpers import deep_update

T = TypeVar('T')
# NB: At the moment, the Snapshot type is a bit weak, as the Any
#     for the value type doesn't tell us anything about the schema
#     followed by snapshots.
#     This is needed, however, since snapshots are Dict instances with
#     homogeneous keys and heterogeneous values, something that
#     recent Python versions largely replace with features like
#     typing.NamedTuple and @dataclass.
#     As those become more widely available, the weakness of this
#     type constraint will become less of an issue.
Snapshot = Dict[str, Any]
ParameterKey = Union[
    # Unbound parameters
    # Instrument parameters
    Tuple[str, str]
ParameterDict = Dict[ParameterKey, T]
RunId = NewType('RunId', int)

[docs]class Metadatable: def __init__(self, metadata=None): self.metadata = {} self.load_metadata(metadata or {})
[docs] def load_metadata(self, metadata: Dict[Any, Any]) -> None: """ Load metadata into this classes metadata dictionary. Args: metadata: Metadata to load. """ deep_update(self.metadata, metadata)
[docs] def snapshot(self, update: Optional[bool] = False) -> Dict[Any, Any]: """ Decorate a snapshot dictionary with metadata. DO NOT override this method if you want metadata in the snapshot instead, override :meth:`snapshot_base`. Args: update: Passed to snapshot_base. Returns: Base snapshot. """ snap = self.snapshot_base(update=update) if len(self.metadata): snap['metadata'] = self.metadata return snap
[docs] def snapshot_base( self, update: Optional[bool] = False, params_to_skip_update: Optional[Sequence[str]] = None ) -> Dict[Any, Any]: """ Override this with the primary information for a subclass. """ return {}
[docs]class ParameterDiff(NamedTuple): # Cannot be generic in Python < 3.7: # left_only: ParameterDict[Any] right_only: ParameterDict[Any] changed: ParameterDict[Tuple[Any, Any]]
[docs]def extract_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) for param_name, param in snapshot['parameters'].items(): parameters[param_name] = param['value'] if 'instruments' in snapshot: for instrument_name, instrument in snapshot['instruments'].items(): for param_name, param in instrument['parameters'].items(): if 'value' in param: parameters[instrument_name, param_name] = param['value'] return parameters
[docs]def diff_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()) for params in (left_params, right_params) ) common_keys = left_keys.intersection(right_keys) return ParameterDiff( left_only={ key: left_params[key] for key in left_keys.difference(common_keys) }, right_only={ key: right_params[key] for key in right_keys.difference(common_keys) }, changed={ key: (left_params[key], right_params[key]) for key in common_keys if left_params[key] != right_params[key] } )
[docs]def diff_param_values_by_id(left_id: RunId, right_id: RunId) -> ParameterDiff: """ Given the IDs of two datasets, returns the differences between parameter values in each of their snapshots. """ # Local import to reduce load time and # avoid circular references. from qcodes.dataset.data_set import load_by_id left_snapshot = load_by_id(left_id).snapshot right_snapshot = load_by_id(right_id).snapshot if left_snapshot is None or right_snapshot is None: if left_snapshot is None: empty = left_id else: empty = right_id raise RuntimeError(f"Tried to compare two snapshots" f"but the snapshot of {empty} " f"is empty.") return diff_param_values(left_snapshot, right_snapshot)