Source code for pylablib.core.devio.interface

### Interface for a generic device class ###

from ..utils import functions
 
_info_node_kinds=["settings","status","full_info"]

[docs]class IDevice(object): """ A base class for an instrument. Contains some useful functions for dealing with device settings. """ def __init__(self): object.__init__(self) self._nodes_ignore_error={"get":(),"set":()} self._info_nodes=dict([(ik,{}) for ik in _info_node_kinds]) self._info_nodes_order=dict([(ik,[]) for ik in _info_node_kinds]) self._add_full_info_node("cls",lambda: self.__class__.__name__)
[docs] def open(self): """Open the connection""" pass
[docs] def close(self): """Close the connection""" pass
[docs] def is_opened(self): """Check if the device is connected""" return True
def __bool__(self): return self.is_opened() def __enter__(self): return self def __exit__(self, *args, **vargs): self.close() return False @staticmethod def _multiplex_func(func, choices, arg_pos=0, multiarg=True): def func_mux(args=None): res=[] if args: for a,ch in zip(args,choices): margs=list(a) if (multiarg and isinstance(a,tuple)) else [a] margs.insert(arg_pos,ch) res.append(func(tuple(margs))) return res else: return [func(ch) for ch in choices] return func_mux def _add_info_node(self, path, kind, getter=None, setter=None, ignore_error=(), mux=None, multiarg=True): """ Adds an info parameter. Args: path: parameter name. kind(str): can be ``"settings"`` (device settings parameter), ``"status"`` (device status parameter) or ``"full_info"`` (full device info). getter: methods for getting this parameter. Can be ``None``, meaning that this parameter is ignored when executing :meth:`get_settings`/:meth:`get_full_status`/:meth:`get_full_info`. setter: methods for setting this parameter. Can be ``None``, meaning that this parameter is ignored when executing :meth:`apply_settings`. ignore_error(tuple): is a list of exception classes; if raised during getter/setter call, they are ignored. mux(tuple): 1- or 2-tuple with parameters for function multiplexing (calling several times and combining result in a list). The first element is an iterable of argument values to be iterated over, the second argument is the position where this argument is inserted (by default, 0) multiarg(bool): if ``True`` and the setter argument is a tuple, interpret it as a tuple of arguments and expand it; otherwise, keep it as a single tuple argument. """ if kind not in self._info_nodes: raise ValueError("unrecognized info node kind: {}".format(kind)) if not isinstance(ignore_error,tuple): ignore_error=(ignore_error,) if multiarg and setter: osetter=setter setter=lambda v: functions.call_cut_args(osetter,*v) if isinstance(v,tuple) else osetter(v) if mux: getter=self._multiplex_func(getter,*mux[:2],multiarg=multiarg) if getter else None setter=self._multiplex_func(setter,*mux[:2],multiarg=multiarg) if setter else None self._info_nodes[kind][path]=(getter,setter,ignore_error) self._info_nodes_order[kind].append(path) def _add_full_info_node(self, path, getter=None, ignore_error=(), mux=None): return self._add_info_node(path,"full_info",getter=getter,ignore_error=ignore_error,mux=mux) def _add_status_node(self, path, getter=None, ignore_error=(), mux=None): return self._add_info_node(path,"status",getter=getter,ignore_error=ignore_error,mux=mux) def _add_settings_node(self, path, getter=None, setter=None, ignore_error=(), mux=None, multiarg=True): return self._add_info_node(path,"settings",getter=getter,setter=setter,ignore_error=ignore_error,mux=mux,multiarg=multiarg) def _get_info(self, kinds, nodes=None): """ Get dict ``{name: value}`` containing all the device settings. `kinds` is the list of info nodes kinds to be included in the info. `nodes` specifies nodes to acquire. """ for kind in kinds: if kind not in self._info_nodes: raise ValueError("unrecognized info node kind: {}".format(kind)) info={} for kind in kinds: for k in self._info_nodes_order[kind]: if (nodes is None or k in nodes): g,_,err=self._info_nodes[kind][k] if g: try: info[k]=g() except err+self._nodes_ignore_error["get"]: pass return info
[docs] def get_settings(self, nodes=None): """ Get dict ``{name: value}`` containing all the device settings. `nodes` specifies nodes to acquire. """ return self._get_info(["settings"],nodes=nodes)
[docs] def get_full_status(self, nodes=None): """ Get dict ``{name: value}`` containing the device status (including settings). `nodes` specifies nodes to acquire. """ return self._get_info(["settings","status"],nodes=nodes)
[docs] def get_full_info(self, nodes=None): """ Get dict ``{name: value}`` containing full device information (including status and settings). `nodes` specifies nodes to acquire. """ return self._get_info(["settings","status","full_info"],nodes=nodes)
[docs] def apply_settings(self, settings): """ Apply the settings. `settings` is the dict ``{name: value}`` of the device available settings. Non-applicable settings are ignored. """ for k in self._info_nodes_order["settings"]: _,s,err=self._info_nodes["settings"][k] if s and (k in settings): try: s(settings[k]) except err+self._nodes_ignore_error["set"]: pass
def __getitem__(self, key): """Get the value of a settings, status, or full info parameter.""" for kind in _info_node_kinds: if key in self._info_nodes[kind]: g=self._info_nodes[kind][key][0] if g: return g() raise ValueError("no getter for value '{}'".format(key)) raise KeyError("no property '{}'".format(key)) def __setitem__(self, key, value): """Set the value of a settings parameter.""" if key in self._info_nodes["settings"]: s=self._info_nodes["settings"][key][1] if s: return s(value) raise ValueError("no setter for value '{}'".format(key)) raise KeyError("no property '{}'".format(key))