Source code for qcodes.parameters.function

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from qcodes.metadatable import MetadatableWithName
from qcodes.validators import Validator, validate_all

from .command import Command

if TYPE_CHECKING:
    from collections.abc import Callable, Sequence

    from qcodes.instrument import InstrumentBase


[docs] class Function(MetadatableWithName): """ Defines a function that an instrument can execute. This class is meant for simple cases, principally things that map to simple commands like ``*RST`` (reset) or those with just a few arguments. It requires a fixed argument count, and positional args only. You execute this function object like a normal function, or use its .call method. Note: Parsers only apply if call_cmd is a string. The function form of call_cmd should do its own parsing. Note: We do not recommend the usage of Function for any new driver. Function does not add any significant features over a method defined on the class. Args: name: the local name of this function instrument: an instrument that handles this function. Default None. call_cmd: command to execute on the instrument: - a string (with positional fields to .format, "{}" or "{0}" etc) you can only use a string if an instrument is provided, this string will be passed to instrument.write - a function (with arg count matching args list) args: list of Validator objects, one for each arg to the Function arg_parser: function to transform the input arg(s) to encoded value(s) sent to the instrument. If there are multiple arguments, this function should accept all the arguments in order, and return a tuple of values. return_parser: function to transform the response from the instrument to the final output value. may be a type casting function like `int` or `float`. If None (default), will not wait for or read any response. docstring: documentation string for the __doc__ field of the object. The __doc__ field of the instance is used by some help systems, but not all (particularly not builtin `help()`) **kwargs: Arbitrary keyword arguments passed to parent class """ def __init__( self, name: str, instrument: InstrumentBase | None = None, call_cmd: str | Callable[..., Any] | None = None, args: Sequence[Validator[Any]] | None = None, arg_parser: Callable[..., Any] | None = None, return_parser: Callable[..., Any] | None = None, docstring: str | None = None, **kwargs: Any ): super().__init__(**kwargs) self._instrument = instrument self.name = name if docstring is not None: self.__doc__ = docstring if args is None: args = [] self._set_args(args) self._set_call(call_cmd, arg_parser, return_parser) def _set_args(self, args: Sequence[Validator[Any]]) -> None: for arg in args: if not isinstance(arg, Validator): raise TypeError("all args must be Validator objects") self._args = args self._arg_count = len(args) def _set_call( self, call_cmd: str | Callable[..., Any] | None, arg_parser: Callable[..., Any] | None, return_parser: Callable[..., Any] | None, ) -> None: if self._instrument: ask_or_write = self._instrument.write if isinstance(call_cmd, str) and return_parser: ask_or_write = self._instrument.ask else: ask_or_write = None self._call = Command( arg_count=self._arg_count, cmd=call_cmd, exec_str=ask_or_write, input_parser=arg_parser, output_parser=return_parser, )
[docs] def validate(self, *args: Any) -> None: """ Check that all arguments to this Function are allowed. Args: *args: Variable length argument list, passed to the call_cmd """ if self._instrument: func_name = ( ( getattr(self._instrument, "name", "") or str(self._instrument.__class__) ) + "." + self.name ) else: func_name = self.name if len(args) != self._arg_count: raise TypeError( f"{func_name} called with {len(args)} args but requires {self._arg_count}" ) validate_all(*zip(self._args, args), context="Function: " + func_name)
def __call__(self, *args: Any) -> Any: self.validate(*args) return self._call(*args)
[docs] def call(self, *args: Any) -> Any: """ Call methods wraps __call__ Args: *args: argument to pass to Command __call__ function """ return self.__call__(*args)
[docs] def get_attrs(self) -> list[str]: """ Attributes recreated as properties in the RemoteFunction proxy. Returns (list): __doc__, _args, and _arg_count get proxied """ return ["__doc__", "_args", "_arg_count"]
@property def short_name(self) -> str: """ Name excluding name of any instrument that this function may be bound to. """ return self.name @property def full_name(self) -> str: """ Name of the function including the name of the instrument and submodule that the function may be bound to. The names are separated by underscores, like this: ``instrument_submodule_function``. """ return "_".join(self.name_parts) @property def name_parts(self) -> list[str]: """ List of the parts that make up the full name of this function """ if self.instrument is not None: name_parts = getattr(self.instrument, "name_parts", []) if name_parts == []: # add fallback for the case where someone has bound # the function to something that is not an instrument # but perhaps it has a name anyway? name = getattr(self.instrument, "name", None) if name is not None: name_parts = [name] else: name_parts = [] name_parts.append(self.short_name) return name_parts @property def instrument(self) -> InstrumentBase | None: return self._instrument