diff --git a/docs/source/spelling_wordlist.txt b/docs/source/spelling_wordlist.txt index 42551c6d..aacae5d6 100644 --- a/docs/source/spelling_wordlist.txt +++ b/docs/source/spelling_wordlist.txt @@ -107,3 +107,5 @@ Waveforms superheterodyne customizations submodule +Enum +boolean \ No newline at end of file diff --git a/scripts/__init__.py b/scripts/__init__.py index e69de29b..9fe790cc 100644 --- a/scripts/__init__.py +++ b/scripts/__init__.py @@ -0,0 +1 @@ +"""Package containing a set of scripts to ease the use of this project.""" diff --git a/scripts/generate_notebooks.py b/scripts/generate_notebooks.py index 4a5ac9de..18cbedbc 100644 --- a/scripts/generate_notebooks.py +++ b/scripts/generate_notebooks.py @@ -17,8 +17,9 @@ def download_example_file(filename: str) -> bytes: """Download example file. - Arguments: + Args: filename: notebook filename. + Returns: Notebook contents """ @@ -43,7 +44,7 @@ def get_notebook_examples() -> None: def generate_and_sync_example_notebooks(src: t.List[Path]) -> None: """Generate and sync given source files to notebooks. - Arguments: + Args: src: Source files """ str_path = [str(path) for path in src] @@ -53,7 +54,7 @@ def generate_and_sync_example_notebooks(src: t.List[Path]) -> None: def generate_notebooks(args: argparse.Namespace) -> None: """Generate notebooks either from local or remote. - Arguments: + Args: args: Namespace arguments """ if args.src == "local": diff --git a/scripts/zhinst_toolkit_symlink.py b/scripts/zhinst_toolkit_symlink.py index e9696652..d22b6af6 100644 --- a/scripts/zhinst_toolkit_symlink.py +++ b/scripts/zhinst_toolkit_symlink.py @@ -1,4 +1,6 @@ -"""A helper script for developers to create symbolic link between existing toolkit and +"""Helper script for developers. + +The script creates a symbolic link between existing toolkit and Python environment directories. By running the script, zhinst-toolkit is added to the ``zhinst`` package namespace @@ -10,7 +12,7 @@ Running the script: - >>> python scripts\\zhinst_toolkit_symlink.py + >>> python scripts/zhinst_toolkit_symlink.py """ import os import sysconfig @@ -22,8 +24,14 @@ def create_symlink(src: Path, dest: Path) -> None: - """Create symbolic link between existing toolkit and + """Create symbolic link between working dir and python environment. + + Create symbolic link between existing toolkit and Python environment directories. + + Args: + src: Toolkit directory (e.g. a/b/src/zhinst/toolkit). + dest: Python environment directory """ try: # Windows: Requires administrator when running tests without symlink diff --git a/setup.cfg b/setup.cfg index ed63fcd5..0db89858 100644 --- a/setup.cfg +++ b/setup.cfg @@ -66,25 +66,15 @@ exclude = per-file-ignores = # disable unused-imports errors on __init__.py __init__.py: F401 +docstring-convention=google [mypy] ignore_missing_imports = True exclude = (?x)( - src/zhinst/toolkit/nodetree/helper\.py$ - | src/zhinst/toolkit/command_table\.py$ + src/zhinst/toolkit/command_table\.py$ | src/zhinst/toolkit/nodetree/nodetree\.py$ | src/zhinst/toolkit/nodetree/node\.py$ - | src/zhinst/toolkit/nodetree/connection_dict\.py$ - | src/zhinst/toolkit/driver/modules/base_module\.py$ - | src/zhinst/toolkit/driver/modules/shfqa_sweeper\.py$ - | src/zhinst/toolkit/driver/modules/daq_module\.py$ - | src/zhinst/toolkit/driver/modules/sweeper_module\.py$ - | src/zhinst/toolkit/driver/devices/uhfqa\.py$ - | src/zhinst/toolkit/driver/devices/hdawg\.py$ - | src/zhinst/toolkit/driver/devices/base\.py$ - | src/zhinst/toolkit/driver/nodes/readout\.py$ - | src/zhinst/toolkit/driver/nodes/spectroscopy\.py$ - | src/zhinst/toolkit/driver/nodes/command_table_node\.py$ - | src/zhinst/toolkit/driver/nodes/generator\.py$ - | src/zhinst/toolkit/driver/nodes/awg\.py$ + | src/zhinst/toolkit/nodetree/connection_dict\.py$ # Weird dict problem + | src/zhinst/toolkit/driver/modules/shfqa_sweeper\.py$ # Weird dict problem + | src/zhinst/toolkit/driver/devices/uhfqa\.py$ # Numpy array ) diff --git a/src/zhinst/toolkit/__init__.py b/src/zhinst/toolkit/__init__.py index f034890d..d76924cd 100644 --- a/src/zhinst/toolkit/__init__.py +++ b/src/zhinst/toolkit/__init__.py @@ -2,7 +2,7 @@ # # This software may be modified and distributed under the terms # of the MIT license. See the LICENSE file for details. -"""The Zurich Instruments Toolkit (zhinst-toolkit) +"""The Zurich Instruments Toolkit (zhinst-toolkit). This package is a collection of Python tools for high level device control. Based on the native interface to Zurich Instruments LabOne, diff --git a/src/zhinst/toolkit/command_table.py b/src/zhinst/toolkit/command_table.py index 5ccb9ec5..7eacb4d9 100644 --- a/src/zhinst/toolkit/command_table.py +++ b/src/zhinst/toolkit/command_table.py @@ -143,6 +143,7 @@ def info(self, value: t.Optional[str] = None) -> dict: Args: value: Info about to specific property. Otherwise return info about the whole property. + Returns: Info about the property. """ @@ -236,8 +237,10 @@ def _derefence_json(schema: t.Union[str, dict]) -> t.Any: Args: schema: JSON schema as a string or dictionary. + Returns: Dereferenced schema. + Raises: ValueError: Wrong `schema` type. """ @@ -260,7 +263,6 @@ class CommandTable: json_schema: JSON Schema of the command table. Example: - .. code-block:: python from zhinst.toolkit import CommandTable diff --git a/src/zhinst/toolkit/driver/devices/base.py b/src/zhinst/toolkit/driver/devices/base.py index 3a8fb0c1..b3495489 100644 --- a/src/zhinst/toolkit/driver/devices/base.py +++ b/src/zhinst/toolkit/driver/devices/base.py @@ -1,4 +1,4 @@ -"""Base Instrument Driver +"""Base Instrument Driver. Natively works with all device types and provides the basic functionality like the device specific nodetree. @@ -111,14 +111,14 @@ def _version_string_to_tuple(version: str) -> t.Tuple[int, int, int]: except ValueError: if i < 3: # ignore dev verisons result[i] = 0 - return tuple(result) + return result[0], result[1], result[2] @staticmethod def _check_python_versions( zi_python_version: t.Tuple[int, int, int], zi_utils_version: t.Tuple[int, int, int], ) -> None: - """Check if the minimum required zhinst packages are installed + """Check if the minimum required zhinst packages are installed. Checks if all zhinst packages that toolkit require have the minimum required version installed. @@ -322,5 +322,5 @@ def serial(self) -> str: @property def device_type(self) -> str: - """Type of the instrument (e.g. MFLI)""" + """Type of the instrument (e.g. MFLI).""" return self._device_type diff --git a/src/zhinst/toolkit/driver/devices/hdawg.py b/src/zhinst/toolkit/driver/devices/hdawg.py index 6f0ad3be..3f8cc076 100644 --- a/src/zhinst/toolkit/driver/devices/hdawg.py +++ b/src/zhinst/toolkit/driver/devices/hdawg.py @@ -14,7 +14,7 @@ class HDAWG(BaseInstrument): """High-level driver for the Zurich Instruments HDAWG.""" def enable_qccs_mode(self) -> None: - """Configure the instrument to work with PQSC + """Configure the instrument to work with PQSC. This method sets the reference clock source to connect the instrument to the PQSC. @@ -41,7 +41,7 @@ def enable_qccs_mode(self) -> None: @lazy_property def awgs(self) -> t.Sequence[AWG]: - """A Sequence of AWG Cores""" + """A Sequence of AWG Cores.""" return NodeList( [ AWG( diff --git a/src/zhinst/toolkit/driver/devices/shfqa.py b/src/zhinst/toolkit/driver/devices/shfqa.py index 7c14fe0f..7780e642 100644 --- a/src/zhinst/toolkit/driver/devices/shfqa.py +++ b/src/zhinst/toolkit/driver/devices/shfqa.py @@ -76,7 +76,7 @@ def configure_channel( @lazy_property def generator(self) -> Generator: - """Generator""" + """Generator.""" return Generator( self._root, self._tree + ("generator",), @@ -88,7 +88,7 @@ def generator(self) -> Generator: @lazy_property def readout(self) -> Readout: - """Readout""" + """Readout.""" return Readout( self._root, self._tree + ("readout",), @@ -100,7 +100,7 @@ def readout(self) -> Readout: @lazy_property def spectroscopy(self) -> Spectroscopy: - """Spectroscopy""" + """Spectroscopy.""" return Spectroscopy( self._root, self._tree + ("spectroscopy",), @@ -139,7 +139,6 @@ def start_continuous_sw_trigger( num_triggers: Number of triggers to be issued wait_time: Time between triggers in seconds """ - deviceutils.start_continuous_sw_trigger( self._session.daq_server, self.serial, @@ -154,7 +153,7 @@ def max_qubits_per_channel(self) -> int: @lazy_property def qachannels(self) -> t.Sequence[QAChannel]: - """A Sequence of QAChannels""" + """A Sequence of QAChannels.""" return NodeList( [ QAChannel(self, self._session, self._tree + ("qachannels", str(i))) @@ -166,7 +165,7 @@ def qachannels(self) -> t.Sequence[QAChannel]: @lazy_property def scopes(self) -> t.Sequence[SHFScope]: - """A Sequence of SHFScopes""" + """A Sequence of SHFScopes.""" return NodeList( [ SHFScope( diff --git a/src/zhinst/toolkit/driver/devices/shfsg.py b/src/zhinst/toolkit/driver/devices/shfsg.py index 57949f3c..e799833f 100644 --- a/src/zhinst/toolkit/driver/devices/shfsg.py +++ b/src/zhinst/toolkit/driver/devices/shfsg.py @@ -19,7 +19,7 @@ class AWGCore(AWG): - """AWG Core Node""" + """AWG Core Node.""" def configure_marker_and_trigger( self, @@ -222,7 +222,7 @@ def awg_modulation_freq(self) -> float: @lazy_property def awg(self) -> AWGCore: - """AWG""" + """AWG.""" return AWGCore( self._root, self._tree + ("awg",), @@ -249,7 +249,7 @@ def factory_reset(self, *, deep: bool = True) -> None: @lazy_property def sgchannels(self) -> t.Sequence[SGChannel]: - """A Sequence of SG Channels""" + """A Sequence of SG Channels.""" return NodeList( [ SGChannel(self, self._session, self._tree + ("sgchannels", str(i))) diff --git a/src/zhinst/toolkit/driver/devices/uhfqa.py b/src/zhinst/toolkit/driver/devices/uhfqa.py index 9c158bc9..1470b541 100644 --- a/src/zhinst/toolkit/driver/devices/uhfqa.py +++ b/src/zhinst/toolkit/driver/devices/uhfqa.py @@ -45,14 +45,12 @@ def write_integration_weights(self, weights: t.Union[Waveforms, dict]) -> None: keys correspond to the indices of the integration weights to be configured. - note: - + Note: Does not raise an error when sample limit is exceeded, but applies only the maximum number of samples. Please refer to LabOne node documentation for the number of maximum integration weight samples. - note: - + Note: This function calls both `/qas/n/integration/weights/n/real` and `/qas/n/integration/weights/n/imag` nodes. @@ -121,6 +119,7 @@ def crosstalk_matrix(self, matrix: Numpy2DArray = None) -> t.Optional[Numpy2DArr for r in range(rows): for c in range(cols): self.crosstalk.rows[r].cols[c](matrix[r, c]) + return None def adjusted_delay(self, value: int = None) -> int: """Set or get the adjustment in the quantum analyzer delay. @@ -166,7 +165,7 @@ def adjusted_delay(self, value: int = None) -> int: @lazy_property def integration(self) -> Integration: - """Integration + """Integration. .. versionadded:: 0.3.2 """ @@ -202,7 +201,7 @@ def enable_qccs_mode(self) -> None: @lazy_property def qas(self) -> t.Sequence[QAS]: - """A Sequence of QAS""" + """A Sequence of QAS.""" return NodeList( [ QAS(self.root, self._tree + ("qas", str(i))) diff --git a/src/zhinst/toolkit/driver/modules/__init__.py b/src/zhinst/toolkit/driver/modules/__init__.py index 9fc46687..bf0b29aa 100644 --- a/src/zhinst/toolkit/driver/modules/__init__.py +++ b/src/zhinst/toolkit/driver/modules/__init__.py @@ -1,3 +1,4 @@ +"""Module for toolkit representations of native LabOne modules.""" import typing as t from zhinst.toolkit.driver.modules.base_module import BaseModule diff --git a/src/zhinst/toolkit/driver/modules/base_module.py b/src/zhinst/toolkit/driver/modules/base_module.py index 26dceddb..6b4818fb 100644 --- a/src/zhinst/toolkit/driver/modules/base_module.py +++ b/src/zhinst/toolkit/driver/modules/base_module.py @@ -1,4 +1,4 @@ -"""Base Module Driver +"""Base Module Driver. Natively works with all module types and provides the basic functionality like the module specific nodetree. @@ -7,6 +7,7 @@ import time import typing as t +from zhinst.ziPython import ModuleBase from zhinst.toolkit.nodetree import Node, NodeTree logger = logging.getLogger(__name__) @@ -15,7 +16,7 @@ from zhinst.toolkit.driver.devices import DeviceType from zhinst.toolkit.session import Session -ZIModule = t.TypeVar("ZIModule") +ZIModule = t.TypeVar("ZIModule", bound=ModuleBase) class BaseModule(Node): @@ -77,7 +78,7 @@ def _set_device(value: t.Union["DeviceType", str]) -> str: str: device serial """ try: - return value.serial + return value.serial # type: ignore except AttributeError: return value @@ -111,7 +112,7 @@ def _set_node(signal: t.Union[Node, str]) -> str: str: raw string node """ try: - node = signal.node_info.path + node = signal.node_info.path # type: ignore except AttributeError: node = signal return node @@ -126,6 +127,7 @@ def wait_done(self, *, timeout: float = 20.0, sleep_time: float = 0.5) -> None: measurement (default: 20). sleep_time (int): Time in seconds to wait between requesting sweeper state. (default: 0.5) + Raises: TimeoutError: The measurement is not completed before timeout. diff --git a/src/zhinst/toolkit/driver/modules/daq_module.py b/src/zhinst/toolkit/driver/modules/daq_module.py index ae1ea6c5..b7902746 100644 --- a/src/zhinst/toolkit/driver/modules/daq_module.py +++ b/src/zhinst/toolkit/driver/modules/daq_module.py @@ -82,7 +82,7 @@ def _set_node(signal: t.Union[Node, str]) -> str: str: A raw string representation of Node """ try: - node = signal.node_info.path + node = signal.node_info.path # type: ignore except AttributeError: node = signal sample_pos = node.find("sample") diff --git a/src/zhinst/toolkit/driver/modules/shfqa_sweeper.py b/src/zhinst/toolkit/driver/modules/shfqa_sweeper.py index 8e875f61..8b6060e6 100644 --- a/src/zhinst/toolkit/driver/modules/shfqa_sweeper.py +++ b/src/zhinst/toolkit/driver/modules/shfqa_sweeper.py @@ -79,8 +79,8 @@ def __init__(self, daq_server: ziDAQServer, session: "Session"): "SetParser": self._set_device, }, "/envelope/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, }, raise_for_invalid_node=False, @@ -105,7 +105,7 @@ def _get_device(self, serial: str) -> t.Union["DeviceType", str]: return serial def _set_device(self, value: t.Union["DeviceType", str]) -> str: - """Convert a toolkit device object into a serial string + """Convert a toolkit device object into a serial string. Args: value: Toolkit device object @@ -116,7 +116,7 @@ def _set_device(self, value: t.Union["DeviceType", str]) -> str: """ serial = "" try: - serial = value.serial + serial = value.serial # type: ignore except AttributeError: serial = value self._raw_module = CoreSweeper(self._daq_server, serial) diff --git a/src/zhinst/toolkit/driver/modules/sweeper_module.py b/src/zhinst/toolkit/driver/modules/sweeper_module.py index dd2ed341..4c5881e1 100644 --- a/src/zhinst/toolkit/driver/modules/sweeper_module.py +++ b/src/zhinst/toolkit/driver/modules/sweeper_module.py @@ -46,7 +46,8 @@ def __init__(self, sweeper_module: ZISweeperModule, session: "Session"): def execute(self) -> None: """Start the sweeper. - Subscription or unsubscription is not possible until the sweep is finished.""" + Subscribe or unsubscribe is not possible until the sweep is finished. + """ self._raw_module.execute() def read(self) -> t.Dict[Node, t.List]: diff --git a/src/zhinst/toolkit/driver/nodes/__init__.py b/src/zhinst/toolkit/driver/nodes/__init__.py index e69de29b..6d2dc7b9 100644 --- a/src/zhinst/toolkit/driver/nodes/__init__.py +++ b/src/zhinst/toolkit/driver/nodes/__init__.py @@ -0,0 +1,4 @@ +"""Adaptions of specific nodes. + +Custom node child classes with additional helper functions and attributes. +""" diff --git a/src/zhinst/toolkit/driver/nodes/awg.py b/src/zhinst/toolkit/driver/nodes/awg.py index 312e3d17..71cb88af 100644 --- a/src/zhinst/toolkit/driver/nodes/awg.py +++ b/src/zhinst/toolkit/driver/nodes/awg.py @@ -241,9 +241,9 @@ def read_from_waveform_memory(self, indexes: t.List[int] = None) -> Waveforms: nodes.append(self.waveform.node_info.path + f"/waves/{index}") else: nodes.append(self.waveform.waves["*"].node_info.path) - nodes = ",".join(nodes) + nodes_str = ",".join(nodes) waveforms_raw = self._session.daq_server.get( - nodes, settingsonly=False, flat=True + nodes_str, settingsonly=False, flat=True ) waveform_info = json.loads( waveforms_raw.pop(self.waveform.descriptors.node_info.path)[0]["vector"] diff --git a/src/zhinst/toolkit/driver/nodes/command_table_node.py b/src/zhinst/toolkit/driver/nodes/command_table_node.py index 3e9a9c29..7ccd6e96 100644 --- a/src/zhinst/toolkit/driver/nodes/command_table_node.py +++ b/src/zhinst/toolkit/driver/nodes/command_table_node.py @@ -1,4 +1,4 @@ -""" zhinst-toolkit Command Table Node adaptions.""" +"""Command Table Node adaptions.""" import json import string import typing as t @@ -89,7 +89,7 @@ def upload_to_device( zhinst.toolkit.exceptions.ValidationError: Incorrect schema. """ try: - self.data(json.dumps(ct.as_dict())) + self.data(json.dumps(ct.as_dict())) # type: ignore except AttributeError: if validate: ct_new = CommandTable(self.load_validation_schema()) diff --git a/src/zhinst/toolkit/driver/nodes/generator.py b/src/zhinst/toolkit/driver/nodes/generator.py index daea3b8f..e1d05abb 100644 --- a/src/zhinst/toolkit/driver/nodes/generator.py +++ b/src/zhinst/toolkit/driver/nodes/generator.py @@ -12,7 +12,7 @@ class Generator(Node): - """Generator node + """Generator node. Implements basic functionality of the generator allowing the user to write and upload their *'.seqC'* code. @@ -167,8 +167,8 @@ def read_from_waveform_memory(self, slots: t.List[int] = None) -> Waveforms: nodes.append(self.waveforms[slot].wave.node_info.path) else: nodes.append(self.waveforms["*"].wave.node_info.path) - nodes = ",".join(nodes) - waveforms_raw = self._daq_server.get(nodes, settingsonly=False, flat=True) + nodes_str = ",".join(nodes) + waveforms_raw = self._daq_server.get(nodes_str, settingsonly=False, flat=True) waveforms = Waveforms() for slot, waveform in enumerate(waveforms_raw.values()): waveforms[slot] = waveform[0]["vector"] @@ -179,8 +179,7 @@ def configure_sequencer_triggering( ) -> None: """Configure the sequencer triggering. - Arguments: - + Args: aux_trigger: Alias for the trigger source used in the sequencer. For the list of available values, use `available_aux_trigger_inputs` play_pulse_delay: Delay in seconds before the start of waveform playback. diff --git a/src/zhinst/toolkit/driver/nodes/readout.py b/src/zhinst/toolkit/driver/nodes/readout.py index 00dc0d97..f3317493 100644 --- a/src/zhinst/toolkit/driver/nodes/readout.py +++ b/src/zhinst/toolkit/driver/nodes/readout.py @@ -200,8 +200,8 @@ def read_integration_weights(self, slots: t.List[int] = None) -> Waveforms: nodes.append(self.integration.weights[slot].wave.node_info.path) else: nodes.append(self.integration.weights["*"].wave.node_info.path) - nodes = ",".join(nodes) - weights_raw = self._daq_server.get(nodes, settingsonly=False, flat=True) + nodes_str = ",".join(nodes) + weights_raw = self._daq_server.get(nodes_str, settingsonly=False, flat=True) weights = Waveforms() for slot, weight in enumerate(weights_raw.values()): weights[slot] = weight[0]["vector"] diff --git a/src/zhinst/toolkit/driver/nodes/shfqa_scope.py b/src/zhinst/toolkit/driver/nodes/shfqa_scope.py index 3365f712..033bb3ad 100644 --- a/src/zhinst/toolkit/driver/nodes/shfqa_scope.py +++ b/src/zhinst/toolkit/driver/nodes/shfqa_scope.py @@ -11,7 +11,7 @@ class SHFScope(Node): - """SHFQA Scope Node + """SHFQA Scope Node. Implements basic functionality of the scope node, e.g allowing the user to read the data. @@ -49,7 +49,6 @@ def run( TimeoutError: The scope did not start within the specified timeout. """ - self.single(single) self.enable(True) try: diff --git a/src/zhinst/toolkit/driver/nodes/spectroscopy.py b/src/zhinst/toolkit/driver/nodes/spectroscopy.py index c2ba29f1..10b453ee 100644 --- a/src/zhinst/toolkit/driver/nodes/spectroscopy.py +++ b/src/zhinst/toolkit/driver/nodes/spectroscopy.py @@ -12,7 +12,7 @@ class Spectroscopy(Node): - """Spectroscopy node + """Spectroscopy node. Implements basic functionality of the spectroscopy, e.g allowing the user to read the result logger data. diff --git a/src/zhinst/toolkit/driver/parsers.py b/src/zhinst/toolkit/driver/parsers.py index f01aebf8..dedceb61 100644 --- a/src/zhinst/toolkit/driver/parsers.py +++ b/src/zhinst/toolkit/driver/parsers.py @@ -1,11 +1,6 @@ -# Copyright (C) 2020 Zurich Instruments -# -# This software may be modified and distributed under the terms -# of the MIT license. See the LICENSE file for details. +"""Predefined parsers for device specific nodes.""" import logging -import numpy as np - UHFQA_SAMPLE_RATE = 1.8e9 SHFQA_SAMPLE_RATE = 2e9 logger = logging.getLogger(__name__) @@ -14,219 +9,129 @@ class Parse: """Input and output parsers for node parameters to validate and parse values.""" - # Define a function to format the value string @staticmethod - def _format_number(n): - if abs(n) > 1e4 or abs(n) < 1e-4: - # Use scientific notation for - # very large and very small numbers - return "{:.3e}".format(n) - else: - return n + def from_bool(value: bool) -> int: + """Convert a boolean value to a integer value. - # Make the mapping and the value case-insensitive if the they are strings - @staticmethod - def _make_mapping_case_insensitive(value, mapping): - key_type = type(list(mapping.keys())[0]) - if isinstance(value, str) and key_type == str: - mapping = {k.lower(): v for k, v in mapping.items()} - value = value.lower() - return value, mapping + Args: + value: A boolean value. - # Define a function to check if input is in allowed values - # defined by mapping - @staticmethod - def _setter_validate_and_parse(value, mapping): - allowed_keys = list(mapping.keys()) - allowed_values = list(mapping.values()) - key_type = type(allowed_keys[0]) - value_type = type(allowed_values[0]) - # Make the mapping and the value case-insensitive if the they are strings - value, mapping = Parse._make_mapping_case_insensitive(value, mapping) - if not isinstance(value, (key_type, value_type)): - raise TypeError(f"This value must be of type {key_type} or {value_type}") - if value not in (list(mapping.keys()) + allowed_values): - raise ValueError( - f"This value must be either one of {allowed_keys} or {allowed_values}" - ) - if isinstance(value, key_type): - value = mapping[value] - return value - - # Define a function to check if output is in allowed values - # defined by mapping - @staticmethod - def _getter_validate_and_parse(value, mapping): - allowed_keys = list(mapping.keys()) - allowed_values = list(mapping.values()) - value_type = type(allowed_values[0]) - if not isinstance(value, value_type): - raise TypeError( - f"The value {value} returned from the instrument is invalid " - f"since it is not of type {value_type}", - ) - if value not in allowed_values: - raise ValueError( - f"The value {value} returned from the instrument is invalid " - f"since it is not one of {allowed_values}", - ) - # Extract the key corresponding to the returned value - key = allowed_keys[allowed_values.index(value)] - return key + Returns: + Integer value. + """ + return int(value) @staticmethod - def set_rf_lf(value): - mapping = {"rf": 1, "lf": 0} - value = Parse._setter_validate_and_parse(value, mapping) - return value + def to_bool(value: int) -> bool: + """Convert a integer value to a boolean value. - @staticmethod - def get_rf_lf(value): - value = int(value) - mapping = {"rf": 1, "lf": 0} - value = Parse._getter_validate_and_parse(value, mapping) - return value + Args: + value: A integer value. - @staticmethod - def set_true_false(value): - mapping = {True: 1, False: 0} - value = Parse._setter_validate_and_parse(value, mapping) - return value + Returns: + Boolean value. + """ + return bool(value) @staticmethod - def get_true_false(value): - value = int(value) - mapping = {True: 1, False: 0} - value = Parse._getter_validate_and_parse(value, mapping) - return value + def phase(raw_phase: float) -> float: + """Corrects the phase to -180 <= value <= 180. - @staticmethod - def set_scope_mode(value): - mapping = {"time": 1, "FFT": 3} - value = Parse._setter_validate_and_parse(value, mapping) - return value + Args: + raw_phase: Raw input phase. - @staticmethod - def get_scope_mode(value): - value = int(value) - mapping = {"time": 1, "FFT": 3} - value = Parse._getter_validate_and_parse(value, mapping) - return value + Returns: + Corrected phase. + """ + return (raw_phase + 180) % 360 - 180 @staticmethod - def get_locked_status(value): - value = int(value) - mapping = {"locked": 0, "error": 1, "busy": 2} - value = Parse._getter_validate_and_parse(value, mapping) - return value + def greater_equal(value: float, limit: float) -> float: + """Ensures that the value is greater or equal a lower limit. - @staticmethod - def phase(v): - return (v + 180) % 360 - 180 + Args: + value: Used value. + limit: Minimum value returned. - @staticmethod - def greater_equal(v, limit): - if v < limit: + Returns: + Clamped value. + """ + if value < limit: logger.warning( - f"The value {Parse._format_number(v)} must be greater than or equal to " - f"{Parse._format_number(limit)} and will be rounded up to: " - f"{Parse._format_number(limit)}" + f"The value {value:.3e} must be greater than or equal to " + f"{limit:.3e} and will be rounded up to: " + f"{limit:.3e}" ) return limit else: - return v + return value @staticmethod - def smaller_equal(v, limit): - if v > limit: + def smaller_equal(value: float, limit: float) -> float: + """Ensures that the value is smaller or equal a upper limit. + + Args: + value: Used value. + limit: Maximum value returned. + + Returns: + Clamped value. + """ + if value > limit: logger.warning( - f"The value {Parse._format_number(v)} must be smaller than or equal to " - f"{Parse._format_number(limit)} and will be rounded down to: " - f"{Parse._format_number(limit)}", + f"The value {value:.3e} must be smaller than or equal to " + f"{limit:.3e} and will be rounded down to: " + f"{limit:.3e}", ) return limit else: - return v + return value @staticmethod - def multiple_of(v, factor, rounding): - if abs(round(v / factor) * factor - v) < 1e-12: - return v + def multiple_of(value: float, factor: float, rounding: str) -> float: + """Rounds a value to a multiple of a given factor. + + Args: + value: Input value. + factor: Factor that the value needs to be multiple of. + rounding: Method of rounding (nearest, down). + + Returns: + Rounded value. + """ + if abs(round(value / factor) * factor - value) < 1e-12: + return value elif rounding == "nearest": - v_rounded = round(v / factor) * factor + v_rounded = round(value / factor) * factor logger.warning( - f"The value {Parse._format_number(v)} is not a multiple of " - f"{Parse._format_number(factor)} and will be rounded to nearest " - f"multiple: {Parse._format_number(v_rounded)}", + f"The value {value:.3e} is not a multiple of " + f"{factor:.3e} and will be rounded to nearest " + f"multiple: {v_rounded:.3e}", ) return v_rounded elif rounding == "down": - v_rounded = round(v // factor) * factor + v_rounded = round(value // factor) * factor logger.warning( - f"The value {Parse._format_number(v)} is not a multiple of " - f"{Parse._format_number(factor)} and will be rounded down to greatest " - f"multiple: {Parse._format_number(v_rounded)}", + f"The value {value:.3e} is not a multiple of " + f"{factor:.3e} and will be rounded down to greatest " + f"multiple: {v_rounded:.3e}", ) return v_rounded - - @staticmethod - def deg2complex(v): - if isinstance(v, complex): - # Return the input without changing it, if it is already - # a complex number - return v - else: - # If it is an angle, convert it to complex number - return np.exp(1j * np.deg2rad(v)) - - @staticmethod - def complex2deg(v): - return np.angle(v, deg=True) - - @staticmethod - def uhfqa_time2samples(v): - min_samples = 4 - multiplicity_samples = 4 - min_time = min_samples / UHFQA_SAMPLE_RATE - multiplicity_time = multiplicity_samples / UHFQA_SAMPLE_RATE - v_rounded = Parse.greater_equal(v, min_time) - v_rounded = Parse.multiple_of(v_rounded, multiplicity_time, "down") - return int(round(v_rounded * UHFQA_SAMPLE_RATE)) - - @staticmethod - def uhfqa_samples2time(v): - return v / UHFQA_SAMPLE_RATE - - @staticmethod - def shfqa_time2samples(v): - min_samples = 4 - max_samples = ((2**23) - 1) * 4 - multiplicity_samples = 4 - min_time = min_samples / SHFQA_SAMPLE_RATE - max_time = max_samples / SHFQA_SAMPLE_RATE - multiplicity_time = multiplicity_samples / SHFQA_SAMPLE_RATE - v_rounded = Parse.greater_equal(v, min_time) - v_rounded = Parse.smaller_equal(v_rounded, max_time) - v_rounded = Parse.multiple_of(v_rounded, multiplicity_time, "down") - return int(round(v_rounded * SHFQA_SAMPLE_RATE)) - - @staticmethod - def shfqa_samples2time(v): - return v / SHFQA_SAMPLE_RATE + raise RuntimeError( + f"Invalid rounding type {rounding} only the " + "following values are allowed: [nearest,down]" + ) node_parser = { "SHFQA": { - "system/clocks/referenceclock/in/status": { - "GetParser": Parse.get_locked_status, - }, "scopes/0/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "scopes/0/channels/*/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "scopes/0/trigger/delay": { "SetParser": lambda v: Parse.multiple_of(v, 2e-9, "nearest"), @@ -239,26 +144,26 @@ def shfqa_samples2time(v): ], }, "scopes/0/segments/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "scopes/0/segments/count": { "SetParser": lambda v: Parse.greater_equal(v, 0), }, "scopes/0/averaging/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "scopes/0/averaging/count": { "SetParser": lambda v: Parse.greater_equal(v, 0), }, "qachannels/*/input/on": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "qachannels/*/output/on": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "qachannels/*/input/range": { "SetParser": [ @@ -282,19 +187,19 @@ def shfqa_samples2time(v): ], }, "qachannels/*/generator/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "qachannels/*/generator/delay": { "SetParser": lambda v: Parse.multiple_of(v, 2e-9, "nearest"), }, "qachannels/*/generator/single": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "qachannels/*/readout/result/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "qachannels/*/oscs/0/gain": { "SetParser": [ @@ -320,12 +225,9 @@ def shfqa_samples2time(v): }, }, "SHFSG": { - "system/clocks/referenceclock/in/status": { - "GetParser": Parse.get_locked_status, - }, "system/clocks/referenceclock/out/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "system/clocks/referenceclock/out/freq": { "SetParser": lambda v: Parse.greater_equal(v, 0), @@ -334,8 +236,8 @@ def shfqa_samples2time(v): "SetParser": lambda v: Parse.greater_equal(v, 0), }, "sgchannels/*/output/on": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "sgchannels/*/output/range": { "SetParser": [ @@ -344,20 +246,16 @@ def shfqa_samples2time(v): lambda v: Parse.multiple_of(v, 5, "nearest"), ], }, - "sgchannels/*/output/rflfpath": { - "GetParser": Parse.get_rf_lf, - "SetParser": Parse.set_rf_lf, - }, "sgchannels/*/awg/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "sgchannels/*/awg/single": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "sgchannels/*/awg/outputs/*/enables/*": { - "GetParser": Parse.get_true_false, + "GetParser": Parse.to_bool, }, "sgchannels/*/awg/outputs/*/gains/*": { "SetParser": [ @@ -389,12 +287,12 @@ def shfqa_samples2time(v): ], }, "sgchannels/*/sines/*/i/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, "sgchannels/*/sines/*/q/enable": { - "GetParser": Parse.get_true_false, - "SetParser": Parse.set_true_false, + "GetParser": Parse.to_bool, + "SetParser": Parse.from_bool, }, }, } diff --git a/src/zhinst/toolkit/interface.py b/src/zhinst/toolkit/interface.py index e3daae81..ee0c0698 100644 --- a/src/zhinst/toolkit/interface.py +++ b/src/zhinst/toolkit/interface.py @@ -10,7 +10,7 @@ class SHFQAChannelMode(Enum): class AveragingMode(IntEnum): - """Averaging modes + """Averaging modes. CYCLIC: All frequency points are measured once from start frequency to stop diff --git a/src/zhinst/toolkit/nodetree/connection_dict.py b/src/zhinst/toolkit/nodetree/connection_dict.py index bb23fdbe..bddec9ac 100644 --- a/src/zhinst/toolkit/nodetree/connection_dict.py +++ b/src/zhinst/toolkit/nodetree/connection_dict.py @@ -1,5 +1,4 @@ -""" Dictionary -""" +"""Implements Connection wrapper around a native python dictionary.""" import fnmatch import json import re @@ -40,7 +39,7 @@ def listNodesJSON(self, path: str, *args, **kwargs) -> str: return json.dumps(json_info) def get(self, path: str, *args, **kwargs) -> t.Any: - """mirrors the behavior of ziPython get command.""" + """Mirrors the behavior of ziPython get command.""" nodes_raw = fnmatch.filter(self._values.keys(), path) return_value = OrderedDict() for node in nodes_raw: @@ -48,7 +47,7 @@ def get(self, path: str, *args, **kwargs) -> t.Any: return return_value def getInt(self, path: str) -> int: - """mirrors the behavior of ziPython getInt command.""" + """Mirrors the behavior of ziPython getInt command.""" try: return int(self._values[path]) except TypeError: @@ -57,14 +56,14 @@ def getInt(self, path: str) -> int: raise def getDouble(self, path: str) -> float: - """mirrors the behavior of ziPython getDouble command.""" + """Mirrors the behavior of ziPython getDouble command.""" return float(self._values[path]) def getString(self, path: str) -> str: - """mirrors the behavior of ziPython getDouble command.""" + """Mirrors the behavior of ziPython getDouble command.""" return str(self._values[path]) - def _parse_input_value(self, path: str, value: str): + def _parse_input_value(self, path: str, value: t.Any): if isinstance(value, str): option_map = {} for key, option in self.json_info[path].get("Options", {}).items(): @@ -79,7 +78,7 @@ def set( value: t.Any = None, **kwargs, ) -> None: - """mirrors the behavior of ziPython set command.""" + """Mirrors the behavior of ziPython set command.""" if isinstance(path, str): self._values[path] = self._parse_input_value(path, value) else: @@ -87,13 +86,13 @@ def set( self._values[node] = self._parse_input_value(node, node_value) def setVector(self, path: str, value: t.Any = None) -> None: - """mirrors the behavior of ziPython setVector command.""" + """Mirrors the behavior of ziPython setVector command.""" self.set(path, value) def subscribe(self, path: str) -> None: - """mirrors the behavior of ziPython subscribe command.""" + """Mirrors the behavior of ziPython subscribe command.""" raise RuntimeError("Can not subscribe within the SHFQA_Sweeper") def unsubscribe(self, path: str) -> None: - """mirrors the behavior of ziPython unsubscribe command.""" + """Mirrors the behavior of ziPython unsubscribe command.""" raise RuntimeError("Can not subscribe within the SHFQA_Sweeper") diff --git a/src/zhinst/toolkit/nodetree/helper.py b/src/zhinst/toolkit/nodetree/helper.py index 96b17d09..568c2bd1 100644 --- a/src/zhinst/toolkit/nodetree/helper.py +++ b/src/zhinst/toolkit/nodetree/helper.py @@ -1,4 +1,4 @@ -"""Helper functions used in toolkit""" +"""Helper functions used in toolkit.""" import typing as t from contextlib import contextmanager from functools import lru_cache @@ -6,7 +6,7 @@ T = t.TypeVar("T") -def lazy_property(property_function: t.Callable[..., T]) -> T: +def lazy_property(property_function: t.Callable[..., T]) -> property: """Alternative for functools.lazy_property. functools.lazy_property is only available since python 3.8. @@ -24,7 +24,7 @@ def lazy_property(property_function: t.Callable[..., T]) -> T: @contextmanager -def create_or_append_set_transaction(nodetree) -> None: +def create_or_append_set_transaction(nodetree) -> t.Generator[None, None, None]: """Context manager for a transactional set. In contrast to the set_transaction from the nodetree this function only diff --git a/src/zhinst/toolkit/nodetree/node.py b/src/zhinst/toolkit/nodetree/node.py index cb6e9067..5ed98f7b 100644 --- a/src/zhinst/toolkit/nodetree/node.py +++ b/src/zhinst/toolkit/nodetree/node.py @@ -198,7 +198,7 @@ def is_vector(self) -> t.Optional[bool]: @property def path(self) -> str: - """LabOne path of the node.""" + """Path (LabOne representation) of the node.""" return self._info["Node"].lower() @property @@ -231,7 +231,7 @@ def options(self) -> t.Dict[int, _option_info]: @lazy_property def enum(self) -> t.Optional[IntEnum]: - """IntEnum of the node options.""" + """Enum of the node options.""" options_reversed = {value.enum: key for key, value in self.options.items()} return ( IntEnum(self.path, options_reversed, module=__name__) @@ -277,8 +277,7 @@ class Node: The call operator supports the following flags: - * deep: - Flag if the set operation should be blocking until the data + * deep: Flag if the set operation should be blocking until the data has arrived at the device, respectively if the get operation should return the value from the device or the cached value on the data server (if there is any). If this flag is set the operation can @@ -295,20 +294,18 @@ class Node: by the device. e.g. important for floating point values with a limited resolution. - Warning: - Does not work for wildcard nodes or non leaf nodes since they - represent multiple nodes that are set in a transactional set - which does not report the acknowledged values. - >>> nodetree.demods[0].freq(29999,99999, deep=True) 3000 - * enum: - Flag if enumerated values should return the enum value as + Warning: + The deep flag does not work for wildcard nodes or non leaf nodes since + they represent multiple nodes that are set in a transactional set which + does not report the acknowledged values. + + * enum: Flag if enumerated values should return the enum value as string. (default = True) - * parse: - Flag if the SetParser/GetParser from the Node, if present, + * parse: Flag if the SetParser/GetParser from the Node, if present, should be applied or not (default = True). The parsers are hard coded lambda functions provided not directly by @@ -409,6 +406,38 @@ def __len__(self): def __call__( self, value: t.Any = None, *, deep=False, enum=True, parse=True, **kwargs ) -> t.Any: + """Call operator that either gets (empty) or gets the value of a node. + + Args: + value: Optional value that should be set to the node. If not + specified the operator will return the value of the node + instead. + deep: Flag if the operation should block until the device has + acknowledged the operation. The operation returns the value + acknowledged by the device. This takes significantly longer + than a normal operation and should be used carefully. + enum: Flag if enumerated values should return the enum value as + string or return the raw number. + parse: Flag if the GetParser or SetParser, if present, should be + applied or not. + + Returns: + Value of the node for a get operation. If the deep flag is set the + acknowledged value from the device is returned (applies also for + the set operation). + + Raises: + AttributeError: If the connection does not support the necessary + function to get/set the value. + RuntimeError: If self.node_info.type if one of the following: + [ZIPWAWave, ZITriggerSample, ZICntSample, ZIImpedanceSample, + ZIScopeWave, ZIAuxInSample]. The reason is that these nodes can + only be polled. + TypeError: if the deep command is not available for this node + (e.g. sample nodes) + KeyError: If the node does not resolve to at least one valid leaf + node. + """ if value is None: return self._get(deep=deep, enum=enum, parse=parse, **kwargs) return self._set(value, deep=deep, enum=enum, parse=parse, **kwargs) @@ -426,7 +455,7 @@ def _is_list(self) -> bool: return len(self._next_layer) > 0 and next(iter(self._next_layer)).isdecimal() def _resolve_wildcards(self) -> t.List[str]: - """Resolves potential wildcards + """Resolves potential wildcards. Also will resolve partial nodes to its leaf nodes. @@ -481,6 +510,7 @@ def _get( value(s) from the device. If multiple values matches the the node a dictionary of the childnodes and their value is returned. If the ``deep`` flag is set the value is a pair (timestamp, value) instead. + Raises: AttributeError: if the connection does not support the necessary function the get the value. @@ -489,7 +519,7 @@ def _get( ZIScopeWave, ZIAuxInSample]. The reason is that these nodes can only be polled. TypeError: if the deep command is not available for this node - (e.g. sample nodes) + (e.g. sample nodes) or connection object. KeyError: If the node does not resolve to at least one valid leaf node. """ @@ -546,7 +576,7 @@ def _parse_get_entry(raw_value: t.Dict[str, t.Any]): def _get_wildcard( self, deep=True, enum=True, parse=True, **kwargs ) -> t.Dict["Node", t.Any]: - """execute a wildcard get. + """Execute a wildcard get. The get is performed as a deep get (for all devices except HF2) regardless of the ``deep`` flag. If the ``deep`` flag is not set the @@ -604,7 +634,7 @@ def _get_wildcard( return result def _get_deep(self, **kwargs) -> t.Tuple[int, t.Any]: - """get the node value from the device. + """Get the node value from the device. The kwargs will be forwarded to the maped ziPython function call. @@ -632,7 +662,7 @@ def _get_deep(self, **kwargs) -> t.Tuple[int, t.Any]: return self._parse_get_entry(raw_value) def _get_cached(self, **kwargs) -> t.Any: - """get the cached node value from the data server. + """Get the cached node value from the data server. The kwargs will be forwarded to the maped ziPython function call. @@ -673,7 +703,7 @@ def _get_cached(self, **kwargs) -> t.Any: def _set( self, value: t.Any, deep=False, enum=True, parse=True, **kwargs ) -> t.Optional[t.Any]: - """set the value to the node. + """Set the value to the node. The kwargs will be forwarded to the maped ziPython function call. @@ -749,7 +779,7 @@ def _set_wildcard(self, value: t.Any, parse: bool = True, **kwargs) -> None: self._root.raw_path_to_node(node_raw)(value, parse=parse, **kwargs) def _set_deep(self, value: t.Any, **kwargs) -> None: - """set the node value from device. + """Set the node value from device. The kwargs will be forwarded to the mapped ziPython function call. @@ -1036,12 +1066,12 @@ def raw_tree(self) -> t.Tuple[str]: @property def root(self) -> "NodeTree": - "Node tree to which this node belongs to." + """Node tree to which this node belongs to.""" return self._root class NodeList(Sequence, Node): - """List of nodelike objects + """List of nodelike objects. List of preinitialized classes that inherit from the ``Node`` class would not support wildcards since they would be of type list. diff --git a/src/zhinst/toolkit/nodetree/nodetree.py b/src/zhinst/toolkit/nodetree/nodetree.py index 7e750ec2..2f0b5de1 100644 --- a/src/zhinst/toolkit/nodetree/nodetree.py +++ b/src/zhinst/toolkit/nodetree/nodetree.py @@ -51,7 +51,7 @@ def unsubscribe(self, path: str) -> None: class Transaction: - """Transaction Manager + """Transaction Manager. Buffers commands (node, value pairs) diff --git a/src/zhinst/toolkit/session.py b/src/zhinst/toolkit/session.py index 843b13f8..9d27714e 100644 --- a/src/zhinst/toolkit/session.py +++ b/src/zhinst/toolkit/session.py @@ -178,7 +178,7 @@ def add_hf2_device(self, serial: str) -> None: class ModuleHandler: - """LabOne modules + """Modules of LabOne. Handler for all additional so called modules by LabOne. A LabOne module is bound to a user session but creates a independent session to the Data Server. @@ -812,7 +812,7 @@ def poll( timeout: float = 0.5, flags: PollFlags = PollFlags.DEFAULT, ) -> t.Dict[Node, t.Dict[str, t.Any]]: - """Polls all subscribed data + """Polls all subscribed data from the data server. Poll the value changes in all subscribed nodes since either subscribing or the last poll (assuming no buffer overflow has occurred on the Data @@ -885,12 +885,12 @@ def devices(self) -> Devices: @property def modules(self) -> ModuleHandler: - """LabOne modules""" + """Modules of LabOne.""" return self._modules @property def is_hf2_server(self) -> bool: - """Flag if the data server is a HF2 Data Server""" + """Flag if the data server is a HF2 Data Server.""" return self._is_hf2_server @property @@ -900,10 +900,10 @@ def daq_server(self) -> ziPython.ziDAQServer: @property def server_host(self) -> str: - """Server host""" + """Server host.""" return self._server_host @property def server_port(self) -> int: - """Server port""" + """Server port.""" return self._server_port diff --git a/src/zhinst/toolkit/waveform.py b/src/zhinst/toolkit/waveform.py index c5f61120..aaf32803 100644 --- a/src/zhinst/toolkit/waveform.py +++ b/src/zhinst/toolkit/waveform.py @@ -11,7 +11,7 @@ class Waveforms(MutableMapping): - """Waveform dictionary + """Waveform dictionary. The key specifies the slot of the waveform on the device. The value is a the waveform itself, represented by a tuple @@ -107,7 +107,7 @@ def assign_native_awg_waveform( slot: slot number raw_waveform: native AWG waveform. channels: Number of channels present in the wave. (default = 1) - markers: Indicates if markers are interleaved in the wave. + markers_present: Indicates if markers are interleaved in the wave. (default = False) """ wave1, wave2, markers = parse_awg_waveform( diff --git a/tests/test_parsers.py b/tests/test_parsers.py index 62682323..af15aa25 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -5,38 +5,13 @@ class TestParsers: - def test_set_rf_lf(self): - assert Parse.set_rf_lf("rf") == 1 - assert Parse.set_rf_lf("lf") == 0 - - def test_get_rf_lf(self): - assert Parse.get_rf_lf(1) == "rf" - assert Parse.get_rf_lf(0) == "lf" - def test_set_true_false(self): - assert Parse.set_true_false(True) == 1 - assert Parse.set_true_false(False) == 0 + assert Parse.from_bool(True) == 1 + assert Parse.from_bool(False) == 0 def test_get_true_false(self): - assert Parse.get_true_false(1) == True - assert Parse.get_true_false(0) == False - - def test_set_scope_mode(self): - assert Parse.set_scope_mode("time") == 1 - assert Parse.set_scope_mode("FFT") == 3 - with pytest.raises(ValueError) as e_info: - Parse.set_scope_mode("invalid") - - def test_get_scope_mode(self): - assert Parse.get_scope_mode(1) == "time" - assert Parse.get_scope_mode(3) == "FFT" - with pytest.raises(ValueError) as e_info: - Parse.get_scope_mode(2) - - def test_get_locked_status(self): - assert Parse.get_locked_status(0) == "locked" - assert Parse.get_locked_status(1) == "error" - assert Parse.get_locked_status(2) == "busy" + assert Parse.to_bool(1) == True + assert Parse.to_bool(0) == False def test_phase(self): assert Parse.phase(90) == 90 @@ -66,18 +41,3 @@ def test_multiple_of(self, caplog): assert len(caplog.records) == 2 assert Parse.multiple_of(12, 6, "down") == 12 assert len(caplog.records) == 2 - - def test_deg2complex(self): - assert Parse.deg2complex(complex(1, 1)) == complex(1, 1) - assert Parse.deg2complex(20) == np.exp(1j * np.deg2rad(20)) - - def test_complex2deg(self): - assert Parse.complex2deg(np.exp(1j * np.deg2rad(20))) == 20 - assert Parse.complex2deg(complex(1, 1)) == 45.0 - - def test_time2samples(self): - assert Parse.uhfqa_time2samples(22) == 39600000000 - assert Parse.uhfqa_samples2time(39600000000) == 22 - assert Parse.shfqa_time2samples(22) == 33554428 - # TODO test why backwards path does not works? - assert Parse.shfqa_samples2time(39600000000) == 19.8 diff --git a/tox.ini b/tox.ini index 01c8d8be..036f2f90 100644 --- a/tox.ini +++ b/tox.ini @@ -23,6 +23,7 @@ commands = [testenv:lint] deps = flake8 + flake8-docstrings commands = flake8