Source code for instrumentserver.helpers

import inspect
from typing import Any, Dict, List, Tuple, Union

from qcodes import Instrument, Parameter

from .serialize import toParamDict

# TODO: check for usage of get params / methods functions -- might not be needed


[docs] def stringToArgsAndKwargs(value: str) -> Tuple[List[Any], Dict[str, Any]]: """Create argument list and kwarg dict from a string. Example:: >>> stringToArgsAndKwargs("1, True, abc=12.3") [1, True], {'abc': 12.3} :returns: list of arguments and dictionary with keyword arguments. :raises: ``ValueError`` if: - kwargs are not in the right format (i.e. not``key=value``) - args or kwarg values cannot be evaluated with ``eval``. """ value = value.strip() if value == "": return [], {} args = [] kwargs = {} elts = [v.strip() for v in value.split(",")] for elt in elts: if "=" in elt: keyandval = elt.split("=") if len(keyandval) != 2: raise ValueError(f"{elt} cannot be interpreted as kwarg") try: kwargs[keyandval[0].strip()] = eval(keyandval[1].strip()) except Exception as e: raise ValueError(f"Cannot evaluate '{keyandval[1]}', {type(e)} raised.") else: try: args.append(eval(elt)) except Exception as e: raise ValueError(f"Cannot evaluate '{elt}', {type(e)} raised.") return args, kwargs
[docs] def typeClassPath(t: type) -> str: return f"{t.__module__}.{t.__qualname__}"
[docs] def objectClassPath(o: Any) -> str: return f"{o.__class__.__module__}.{o.__class__.__qualname__}"
[docs] def nestedAttributeFromString(root: Any, loc: str) -> Any: """Return a sub-object. Example:: >>> nestedAttributeFromString(parent_object, 'foo.bar.spam.bacon') returns the object that can be found at parent_object.foo.bar.spam.bacon. """ mods = loc.split(".") obj = root for m in mods: obj = getattr(obj, m) return obj
[docs] def getInstrumentParameters(ins: Instrument) -> Dict[str, Dict[str, str]]: """Return the parameters of an instrument. :param ins: instrument instance :returns: a param dict with entries `unit`, `vals`, for each instrument parameter. """ paramDict = toParamDict([ins], includeMeta=["unit", "vals"]) for k, v in paramDict.items(): paramDict[k].pop("value", None) return paramDict
[docs] def getInstrumentMethods( ins: Instrument, ) -> Dict[str, Dict[str, Union[str, List[str]]]]: """Return the methods of an instrument. :param ins: instrument instance :returns: a dictionary, with keys being the names of methods that are not private and not inherited from qcodes.Instrument. Each entry is a dictionary containing: - 'parameters': List of string representations of the parameters - 'doc': Docstring of the method - 'return': string representation of the return type. """ funcs: dict = {} for attr_name in dir(ins): if attr_name[0] != "_" and attr_name not in dir(Instrument): obj = getattr(ins, attr_name) if callable(obj) and not isinstance(obj, Parameter): funcs[attr_name] = dict() for fname in funcs.keys(): fun = getattr(ins, fname) signature = inspect.signature(fun) funcs[fname]["parameters"] = [ str(signature.parameters[a]) for a in signature.parameters ] funcs[fname]["doc"] = str(fun.__doc__) funcs[fname]["return"] = str(signature.return_annotation) return funcs
[docs] def flat_to_nested_dict(flat_dict: Dict) -> Dict: """ Converts a flat dictionary with keys separated by dots into a nested dictionary. :param flat_dict: A flat dictionary where keys are strings with dot-separated parts. :return: A nested dictionary reconstructed from the flat structure. Example: .. code-block:: python flat = { "a.b.c": 1, "a.b.d": 2, "x": 3 } result = flat_to_nested_dict(flat) # result: {"a": {"b": {"c": 1,"d": 2}},"x": 3} """ nested: Dict[str, Any] = {} for key, value in flat_dict.items(): parts = key.split(".") d = nested for part in parts[:-1]: d = d.setdefault(part, {}) d[parts[-1]] = value return nested
[docs] def is_flat_dict(d: dict) -> bool: """ Detects if a dictionary is flat (i.e. all values are non-dicts). """ return all(not isinstance(v, dict) for v in d.values())
[docs] def flatten_dict(d: Dict[str, Any], sep: str = ".") -> Dict[str, Any]: """ Detects if a dictionary is flat (i.e. all values are non-dicts). If it is not flat, recursively flattens it using dot-separated keys. :param d: A dictionary, potentially nested. :param sep: Separator to use for the flattened keys. :return: A flat dictionary if input was nested; original dictionary if already flat. Example: .. code-block:: python flatten_dict({"a": 1, "b.c": 2}) # returns: {"a": 1, "b.c": 2} flatten_dict({"a": {"b": 1}, "x": 3}) # returns: {"a.b": 1, "x": 3} """ if is_flat_dict(d): return d def flatten(nested: Dict[str, Any], parent_key: str = "") -> Dict[str, Any]: items: Dict[str, Any] = {} for k, v in nested.items(): new_key = f"{parent_key}{sep}{k}" if parent_key else k if isinstance(v, dict): items.update(flatten(v, new_key)) else: items[new_key] = v return items return flatten(d)