Skip to content

Commit

Permalink
Merge #4286 #4291
Browse files Browse the repository at this point in the history
4286: API: Move command module into parametes and undocument r=jenshnielsen a=jenshnielsen

To make this possible also move Function into Parameters where it more naturally belongs

4291: DoNd: Add support for per group experiment in do_nd r=jenshnielsen a=jenshnielsen



Co-authored-by: Jens H. Nielsen <[email protected]>
Co-authored-by: Jens Hedegaard Nielsen <[email protected]>
  • Loading branch information
3 people authored Jun 20, 2022
3 parents 8619142 + a9612ed + 2e5d078 commit 4b47875
Show file tree
Hide file tree
Showing 16 changed files with 447 additions and 371 deletions.
5 changes: 0 additions & 5 deletions docs/api/utils/command.rst

This file was deleted.

2 changes: 0 additions & 2 deletions docs/api/utils/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ qcodes.utils
.. autosummary::

qcodes.utils
qcodes.utils.command
qcodes.utils.deprecate
qcodes.utils.helpers
qcodes.utils.magic
Expand All @@ -23,7 +22,6 @@ qcodes.utils
:maxdepth: 4
:hidden:

command
deprecate
helpers
magic
Expand Down
2 changes: 1 addition & 1 deletion qcodes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
from qcodes.instrument import (
ChannelList,
ChannelTuple,
Function,
Instrument,
InstrumentChannel,
IPInstrument,
Expand All @@ -60,6 +59,7 @@
ArrayParameter,
CombinedParameter,
DelegateParameter,
Function,
ManualParameter,
MultiParameter,
Parameter,
Expand Down
24 changes: 20 additions & 4 deletions qcodes/dataset/do_nd.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ def dond(
*params: Union[AbstractSweep, Union[ParamMeasT, Sequence[ParamMeasT]]],
write_period: Optional[float] = None,
measurement_name: str = "",
exp: Optional[Experiment] = None,
exp: Optional[Union[Experiment, Sequence[Experiment]]] = None,
enter_actions: ActionsT = (),
exit_actions: ActionsT = (),
do_plot: Optional[bool] = None,
Expand Down Expand Up @@ -712,7 +712,8 @@ def dond(
measurement_name: Name of the measurement. This will be passed down to
the dataset produced by the measurement. If not given, a default
value of 'results' is used for the dataset.
exp: The experiment to use for this measurement.
exp: The experiment to use for this measurement. If you create multiple
measurements using groups you may also supply multiple experiments.
enter_actions: A list of functions taking no arguments that will be
called before the measurements start.
exit_actions: A list of functions taking no arguments that will be
Expand Down Expand Up @@ -927,7 +928,7 @@ def _create_measurements(
all_setpoint_params: Sequence[ParameterBase],
enter_actions: ActionsT,
exit_actions: ActionsT,
exp: Optional[Experiment],
experiments: Optional[Union[Experiment, Sequence[Experiment]]],
grouped_parameters: Dict[str, ParameterGroup],
shapes: Shapes,
write_period: Optional[float],
Expand All @@ -938,7 +939,22 @@ def _create_measurements(
_extra_log_info = log_info
else:
_extra_log_info = "Using 'qcodes.dataset.dond'"
for group in grouped_parameters.values():

if not isinstance(experiments, Sequence):
experiments_internal: Sequence[Optional[Experiment]] = [
experiments for _ in grouped_parameters
]
else:
experiments_internal = experiments

if len(experiments_internal) != len(grouped_parameters):
raise ValueError(
f"Inconsistent number of "
f"parameter groups and experiments "
f"got {len(grouped_parameters)} and {len(experiments_internal)}"
)

for group, exp in zip(grouped_parameters.values(), experiments_internal):
meas_name = group["meas_name"]
meas_params = group["params"]
meas = Measurement(name=meas_name, exp=exp)
Expand Down
3 changes: 1 addition & 2 deletions qcodes/instrument/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
ArrayParameter,
CombinedParameter,
DelegateParameter,
Function,
ManualParameter,
MultiParameter,
Parameter,
Expand All @@ -16,14 +17,12 @@

from .base import Instrument, InstrumentBase, find_or_create_instrument
from .channel import ChannelList, ChannelTuple, InstrumentChannel, InstrumentModule
from .function import Function
from .ip import IPInstrument
from .visa import VisaInstrument

__all__ = [
"ChannelList",
"ChannelTuple",
"Function",
"IPInstrument",
"Instrument",
"InstrumentBase",
Expand Down
4 changes: 1 addition & 3 deletions qcodes/instrument/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@
from typing_extensions import Protocol

from qcodes.logger.instrument_logger import get_instrument_logger
from qcodes.parameters import Parameter, ParameterBase
from qcodes.parameters import Function, Parameter, ParameterBase
from qcodes.utils.helpers import DelegateAttributes, full_class, strip_attrs
from qcodes.utils.metadata import Metadatable
from qcodes.utils.validators import Anything

from .function import Function

if TYPE_CHECKING:
from qcodes.instrument.channel import ChannelTuple, InstrumentModule
from qcodes.logger.instrument_logger import InstrumentLoggerAdapter
Expand Down
149 changes: 4 additions & 145 deletions qcodes/instrument/function.py
Original file line number Diff line number Diff line change
@@ -1,146 +1,5 @@
from typing import TYPE_CHECKING, Optional, Union, Callable, Any, Sequence, List
# left here for backwards compatibility
# but not part of the api officially
from qcodes.parameters import Function

from qcodes.utils.metadata import Metadatable
from qcodes.utils.command import Command
from qcodes.utils.validators import Validator, validate_all

if TYPE_CHECKING:
from .base import Instrument, InstrumentBase


class Function(Metadatable):
"""
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. If your case is more complicated, you're probably better off
simply making a new method in your Instrument subclass definition.
The function validators.validate_all can help reduce boilerplate code
in this case.
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.
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: Optional['InstrumentBase'] = None,
call_cmd: Optional[Union[str, Callable[..., Any]]] = None,
args: Optional[Sequence[Validator[Any]]] = None,
arg_parser: Optional[Callable[..., Any]] = None,
return_parser: Optional[Callable[..., Any]] = None,
docstring: Optional[str] = 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: Optional[Union[str, Callable[..., Any]]],
arg_parser: Optional[Callable[..., Any]],
return_parser: Optional[Callable[..., Any]]) -> 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)

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(
'{} called with {} args but requires {}'.format(
func_name, len(args), 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)

def call(self, *args: Any) -> Any:
"""
Call methods wraps __call__
Args:
*args: argument to pass to Command __call__ function
"""
return self.__call__(*args)

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']
__all__ = ["Function"]
4 changes: 3 additions & 1 deletion qcodes/parameters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
from .array_parameter import ArrayParameter
from .combined_parameter import CombinedParameter, combine
from .delegate_parameter import DelegateParameter
from .function import Function
from .group_parameter import Group, GroupParameter
from .grouped_parameter import DelegateGroup, DelegateGroupParameter, GroupedParameter
from .multi_channel_instrument_parameter import MultiChannelInstrumentParameter
Expand All @@ -94,6 +95,7 @@
"DelegateGroupParameter",
"DelegateParameter",
"ElapsedTimeParameter",
"Function",
"Group",
"GroupParameter",
"GroupedParameter",
Expand All @@ -105,11 +107,11 @@
"ParamDataType",
"ParamRawDataType",
"Parameter",
"ParameterBase",
"ParameterWithSetpoints",
"ScaledParameter",
"SweepFixedValues",
"SweepValues",
"ParameterBase",
"combine",
"expand_setpoints_helper",
"invert_val_mapping",
Expand Down
Loading

0 comments on commit 4b47875

Please sign in to comment.