From 0977c347535cc6d13f74b0079f939ae780c6259b Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Fri, 17 May 2024 22:35:55 +0200 Subject: [PATCH 01/12] Add types to Lakeshore instrument kwargs --- .../Lakeshore/Lakeshore_model_325.py | 63 +++++++++---- .../Lakeshore/Lakeshore_model_336.py | 37 ++++++-- .../Lakeshore/Lakeshore_model_372.py | 29 ++++-- .../instrument_drivers/Lakeshore/Model_325.py | 22 ++++- .../instrument_drivers/Lakeshore/Model_336.py | 11 ++- .../instrument_drivers/Lakeshore/Model_372.py | 11 ++- .../Lakeshore/_lakeshore_model_335.py | 29 ++++-- .../Lakeshore/lakeshore_base.py | 93 ++++++++++--------- 8 files changed, 204 insertions(+), 91 deletions(-) diff --git a/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_325.py b/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_325.py index 0231e1bb307..4548cd25053 100644 --- a/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_325.py +++ b/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_325.py @@ -12,14 +12,20 @@ cast, ) -from qcodes.instrument import ChannelList, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + ChannelList, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import Group, GroupParameter from qcodes.validators import Enum, Numbers if TYPE_CHECKING: from collections.abc import Iterable - from typing_extensions import Buffer, Self + from typing_extensions import Buffer, Self, Unpack def _read_curve_file(curve_file: TextIO) -> dict[Any, Any]: @@ -154,11 +160,15 @@ class LakeshoreModel325Curve(InstrumentChannel): valid_sensor_units = ("mV", "V", "Ohm", "log Ohm") temperature_key = "Temperature (K)" - def __init__(self, parent: "LakeshoreModel325", index: int) -> None: - + def __init__( + self, + parent: "LakeshoreModel325", + index: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ) -> None: self._index = index name = f"curve_{index}" - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.add_parameter("serial_number", parameter_class=GroupParameter) @@ -288,8 +298,13 @@ class LakeshoreModel325Sensor(InstrumentChannel): inp (str): Either "A" or "B" """ - def __init__(self, parent: "LakeshoreModel325", name: str, inp: str) -> None: - + def __init__( + self, + parent: "LakeshoreModel325", + name: str, + inp: str, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ) -> None: if inp not in ["A", "B"]: raise ValueError("Please either specify input 'A' or 'B'") @@ -365,21 +380,27 @@ def curve(self) -> LakeshoreModel325Curve: class LakeshoreModel325Heater(InstrumentChannel): - """ - InstrumentChannel for heater control on a Lakeshore Model 325. - - Args: - parent (LakeshoreModel325): The instrument this heater belongs to - name (str) - loop (int): Either 1 or 2 - """ + def __init__( + self, + parent: "LakeshoreModel325", + name: str, + loop: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ) -> None: + """ + InstrumentChannel for heater control on a Lakeshore Model 325. - def __init__(self, parent: "LakeshoreModel325", name: str, loop: int) -> None: + Args: + parent: The instrument this heater belongs to + name: Name of the Channel + loop: Either 1 or 2 + **kwargs: Forwarded to baseclass. + """ if loop not in [1, 2]: raise ValueError("Please either specify loop 1 or 2") - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self._loop = loop self.add_parameter( @@ -514,8 +535,12 @@ class LakeshoreModel325(VisaInstrument): QCoDeS driver for Lakeshore Model 325 Temperature Controller. """ - def __init__(self, name: str, address: str, **kwargs: Any) -> None: - super().__init__(name, address, terminator="\r\n", **kwargs) + default_terminator = "\r\n" + + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ) -> None: + super().__init__(name, address, **kwargs) sensors = ChannelList( self, "sensor", LakeshoreModel325Sensor, snapshotable=False diff --git a/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_336.py b/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_336.py index f1f17ad7c68..c867131ea2e 100644 --- a/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_336.py +++ b/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_336.py @@ -1,10 +1,15 @@ -from typing import Any, ClassVar +from typing import TYPE_CHECKING, ClassVar import qcodes.validators as vals from qcodes.parameters import Group, GroupParameter from .lakeshore_base import BaseOutput, BaseSensorChannel, LakeshoreBase +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import InstrumentBaseKWArgs, VisaInstrumentKWArgs + # There are 4 sensors channels (a.k.a. measurement inputs) in Model 336. # Unlike other Lakeshore models, Model 336 refers to the channels using # letters, and not numbers @@ -42,9 +47,13 @@ class LakeshoreModel336CurrentSource(BaseOutput): } def __init__( - self, parent: "LakeshoreModel336", output_name: str, output_index: int + self, + parent: "LakeshoreModel336", + output_name: str, + output_index: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", ): - super().__init__(parent, output_name, output_index, has_pid=True) + super().__init__(parent, output_name, output_index, has_pid=True, **kwargs) self.P.vals = vals.Numbers(0.1, 1000) self.I.vals = vals.Numbers(0.1, 1000) @@ -71,9 +80,13 @@ class LakeshoreModel336VoltageSource(BaseOutput): RANGES: ClassVar[dict[str, int]] = {"off": 0, "low": 1, "medium": 2, "high": 3} def __init__( - self, parent: "LakeshoreModel336", output_name: str, output_index: int + self, + parent: "LakeshoreModel336", + output_name: str, + output_index: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", ): - super().__init__(parent, output_name, output_index, has_pid=False) + super().__init__(parent, output_name, output_index, has_pid=False, **kwargs) class LakeshoreModel336Channel(BaseSensorChannel): @@ -91,8 +104,14 @@ class LakeshoreModel336Channel(BaseSensorChannel): 128: "Sensor Units Overrange", } - def __init__(self, parent: "LakeshoreModel336", name: str, channel: str): - super().__init__(parent, name, channel) + def __init__( + self, + parent: "LakeshoreModel336", + name: str, + channel: str, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): + super().__init__(parent, name, channel, **kwargs) # Parameters related to Input Type Parameter Command (INTYPE) self.add_parameter( @@ -174,7 +193,9 @@ class LakeshoreModel336(LakeshoreBase): _channel_name_to_command_map ) - def __init__(self, name: str, address: str, **kwargs: Any) -> None: + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ) -> None: super().__init__(name, address, **kwargs) self.output_1 = LakeshoreModel336CurrentSource(self, "output_1", 1) diff --git a/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_372.py b/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_372.py index 3a5e273c33d..d13c1469012 100644 --- a/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_372.py +++ b/src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_372.py @@ -1,4 +1,4 @@ -from typing import Any, ClassVar +from typing import TYPE_CHECKING, Any, ClassVar import qcodes.validators as vals from qcodes.instrument_drivers.Lakeshore.lakeshore_base import ( @@ -8,6 +8,11 @@ ) from qcodes.parameters import Group, GroupParameter +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import InstrumentBaseKWArgs, VisaInstrumentKWArgs + # There are 16 sensors channels (a.k.a. measurement inputs) in Model 372 _n_channels = 16 @@ -43,9 +48,13 @@ class LakeshoreModel372Output(BaseOutput): } def __init__( - self, parent: "LakeshoreModel372", output_name: str, output_index: int + self, + parent: "LakeshoreModel372", + output_name: str, + output_index: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", ) -> None: - super().__init__(parent, output_name, output_index, has_pid=True) + super().__init__(parent, output_name, output_index, has_pid=True, **kwargs) # Add more parameters for OUTMODE command # and redefine the corresponding group @@ -111,8 +120,14 @@ class LakeshoreModel372Channel(BaseSensorChannel): 128: "T. UNDER", } - def __init__(self, parent: "LakeshoreModel372", name: str, channel: str): - super().__init__(parent, name, channel) + def __init__( + self, + parent: "LakeshoreModel372", + name: str, + channel: str, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): + super().__init__(parent, name, channel, **kwargs) # Parameters related to Input Channel Parameter Command (INSET) self.add_parameter( @@ -298,7 +313,9 @@ class LakeshoreModel372(LakeshoreBase): CHANNEL_CLASS = LakeshoreModel372Channel - def __init__(self, name: str, address: str, **kwargs: Any) -> None: + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ) -> None: super().__init__(name, address, **kwargs) heaters = {"sample_heater": 0, "warmup_heater": 1, "analog_heater": 2} diff --git a/src/qcodes/instrument_drivers/Lakeshore/Model_325.py b/src/qcodes/instrument_drivers/Lakeshore/Model_325.py index 01eb5d3afda..513d604399d 100644 --- a/src/qcodes/instrument_drivers/Lakeshore/Model_325.py +++ b/src/qcodes/instrument_drivers/Lakeshore/Model_325.py @@ -6,9 +6,14 @@ from collections.abc import Iterable from enum import IntFlag from itertools import takewhile -from typing import Any, Optional, TextIO, cast - -from qcodes.instrument import ChannelList, InstrumentChannel, VisaInstrument +from typing import TYPE_CHECKING, Any, Optional, TextIO, cast + +from qcodes.instrument import ( + ChannelList, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import Group, GroupParameter from qcodes.validators import Enum, Numbers @@ -19,14 +24,21 @@ from .Lakeshore_model_325 import _get_sanitize_data as get_sanitize_data from .Lakeshore_model_325 import _read_curve_file as read_curve_file +if TYPE_CHECKING: + from typing_extensions import Unpack + class Model_325(VisaInstrument): """ Lakeshore Model 325 Temperature Controller Driver """ - def __init__(self, name: str, address: str, **kwargs: Any) -> None: - super().__init__(name, address, terminator="\r\n", **kwargs) + default_terminator = "\r\n" + + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ) -> None: + super().__init__(name, address, **kwargs) sensors = ChannelList( self, "sensor", Model_325_Sensor, snapshotable=False) diff --git a/src/qcodes/instrument_drivers/Lakeshore/Model_336.py b/src/qcodes/instrument_drivers/Lakeshore/Model_336.py index 7b8f592f9fc..5ce940dfa65 100644 --- a/src/qcodes/instrument_drivers/Lakeshore/Model_336.py +++ b/src/qcodes/instrument_drivers/Lakeshore/Model_336.py @@ -3,7 +3,7 @@ It will eventually be deprecated and removed """ -from typing import Any, ClassVar +from typing import TYPE_CHECKING, Any, ClassVar import qcodes.validators as vals from qcodes.parameters import Group, GroupParameter @@ -18,6 +18,11 @@ ) from .Lakeshore_model_336 import _channel_name_to_command_map +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import VisaInstrumentKWArgs + class Model_336(LakeshoreBase): """ @@ -31,7 +36,9 @@ class Model_336(LakeshoreBase): input_channel_parameter_values_to_channel_name_on_instrument = \ _channel_name_to_command_map - def __init__(self, name: str, address: str, **kwargs: Any) -> None: + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ) -> None: super().__init__(name, address, **kwargs) self.output_1 = Output_336_CurrentSource(self, "output_1", 1) # type: ignore[arg-type] diff --git a/src/qcodes/instrument_drivers/Lakeshore/Model_372.py b/src/qcodes/instrument_drivers/Lakeshore/Model_372.py index 5586f94584c..f2a4e9a11d3 100644 --- a/src/qcodes/instrument_drivers/Lakeshore/Model_372.py +++ b/src/qcodes/instrument_drivers/Lakeshore/Model_372.py @@ -3,7 +3,7 @@ It will eventually be deprecated and removed """ -from typing import Any, ClassVar +from typing import TYPE_CHECKING, Any, ClassVar import qcodes.validators as vals from qcodes.instrument_drivers.Lakeshore.lakeshore_base import ( @@ -16,6 +16,11 @@ from .Lakeshore_model_372 import LakeshoreModel372Channel as Model_372_Channel from .Lakeshore_model_372 import LakeshoreModel372Output as Output_372 +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import VisaInstrumentKWArgs + # There are 16 sensors channels (a.k.a. measurement inputs) in Model 372 _n_channels = 16 @@ -37,7 +42,9 @@ class Model_372(LakeshoreBase): CHANNEL_CLASS = Model_372_Channel - def __init__(self, name: str, address: str, **kwargs: Any) -> None: + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ) -> None: super().__init__(name, address, **kwargs) heaters = {'sample_heater': 0, 'warmup_heater': 1, 'analog_heater': 2} diff --git a/src/qcodes/instrument_drivers/Lakeshore/_lakeshore_model_335.py b/src/qcodes/instrument_drivers/Lakeshore/_lakeshore_model_335.py index 1fcc25595e1..ae93924350b 100644 --- a/src/qcodes/instrument_drivers/Lakeshore/_lakeshore_model_335.py +++ b/src/qcodes/instrument_drivers/Lakeshore/_lakeshore_model_335.py @@ -1,4 +1,4 @@ -from typing import Any, ClassVar +from typing import TYPE_CHECKING, ClassVar import pyvisa.constants import pyvisa.resources @@ -8,6 +8,11 @@ from .lakeshore_base import BaseOutput, BaseSensorChannel, LakeshoreBase +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import InstrumentBaseKWArgs, VisaInstrumentKWArgs + # There are 2 sensors channels (a.k.a. measurement inputs) in Model 335. # Unlike other Lakeshore models, Model 335 refers to the channels using # letters, and not numbers @@ -39,8 +44,14 @@ class LakeshoreModel335Channel(BaseSensorChannel): 128: "Sensor Units Overrange", } - def __init__(self, parent: "LakeshoreModel335", name: str, channel: str): - super().__init__(parent, name, channel) + def __init__( + self, + parent: "LakeshoreModel335", + name: str, + channel: str, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): + super().__init__(parent, name, channel, **kwargs) # Parameters related to Input Type Parameter Command (INTYPE) self.add_parameter( @@ -137,9 +148,13 @@ class LakeshoreModel335CurrentSource(BaseOutput): } def __init__( - self, parent: "LakeshoreModel335", output_name: str, output_index: int + self, + parent: "LakeshoreModel335", + output_name: str, + output_index: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", ): - super().__init__(parent, output_name, output_index, has_pid=True) + super().__init__(parent, output_name, output_index, has_pid=True, **kwargs) self.P.vals = vals.Numbers(0.1, 1000) self.I.vals = vals.Numbers(0.1, 1000) @@ -159,7 +174,9 @@ class LakeshoreModel335(LakeshoreBase): _channel_name_to_command_map ) - def __init__(self, name: str, address: str, **kwargs: Any) -> None: + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ) -> None: super().__init__(name, address, print_connect_message=False, **kwargs) if isinstance(self.visa_handle, pyvisa.resources.serial.SerialInstrument): diff --git a/src/qcodes/instrument_drivers/Lakeshore/lakeshore_base.py b/src/qcodes/instrument_drivers/Lakeshore/lakeshore_base.py index 1a65ec67602..f43765149eb 100644 --- a/src/qcodes/instrument_drivers/Lakeshore/lakeshore_base.py +++ b/src/qcodes/instrument_drivers/Lakeshore/lakeshore_base.py @@ -5,42 +5,48 @@ import numpy as np from qcodes import validators as vals -from qcodes.instrument import ChannelList, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + ChannelList, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import Group, GroupParameter if TYPE_CHECKING: from collections.abc import Sequence + from typing_extensions import Unpack -class BaseOutput(InstrumentChannel): - """ - Base class for the outputs of Lakeshore temperature controllers - - Args: - parent - instrument that this channel belongs to - output_name - name of this output - output_index - identifier for this output that is used in VISA commands of the - instrument - has_pid - if True, then the output supports closed loop control, - hence it will have three parameters to set it up: 'P', 'I', and 'D' - """ +class BaseOutput(InstrumentChannel): MODES: ClassVar[dict[str, int]] = {} RANGES: ClassVar[dict[str, int]] = {} _input_channel_parameter_kwargs: ClassVar[dict[str, Any]] = {} def __init__( - self, - parent: "LakeshoreBase", - output_name: str, - output_index: int, - has_pid: bool = True): - super().__init__(parent, output_name) + self, + parent: "LakeshoreBase", + output_name: str, + output_index: int, + has_pid: bool = True, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): + """ + Base class for the outputs of Lakeshore temperature controllers + + Args: + parent: instrument that this channel belongs to + output_name: name of this output + output_index: identifier for this output that is used in VISA commands of the + instrument + has_pid: if True, then the output supports closed loop control, + hence it will have three parameters to set it up: 'P', 'I', and 'D' + **kwargs: Forwarded to baseclass. + """ + super().__init__(parent, output_name, **kwargs) self.INVERSE_RANGES: dict[int, str] = {v: k for k, v in self.RANGES.items()} @@ -330,28 +336,28 @@ def wait_until_set_point_reached( class BaseSensorChannel(InstrumentChannel): - """ - Base class for Lakeshore Temperature Controller sensor channels - - Args: - parent - instrument instance that this channel belongs to - name - name of the channel - channel - string identifier of the channel as referenced in commands; - for example, '1' or '6' for model 372, or 'A' and 'C' for model 336 - """ - # A dictionary of sensor statuses that assigns a string representation of # the status to a status bit weighting (e.g. {4: 'VMIX OVL'}) SENSOR_STATUSES: ClassVar[dict[int, str]] = {} def __init__( - self, - parent: "LakeshoreBase", - name: str, - channel: str): + self, + parent: "LakeshoreBase", + name: str, + channel: str, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): + """ + Base class for Lakeshore Temperature Controller sensor channels + + Args: + parent: instrument instance that this channel belongs to + name: name of the channel + channel: string identifier of the channel as referenced in commands; + for example, '1' or '6' for model 372, or 'A' and 'C' for model 336 + **kwargs: Forwarded to base class. + """ + super().__init__(parent, name) self._channel = channel # Channel on the temperature controller @@ -488,15 +494,16 @@ class LakeshoreBase(VisaInstrument): dict[Any, str] ] + default_terminator = "\r\n" + def __init__( self, name: str, address: str, - terminator: str = "\r\n", print_connect_message: bool = True, - **kwargs: Any, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ) -> None: - super().__init__(name, address, terminator=terminator, **kwargs) + super().__init__(name, address, **kwargs) # Allow access to channels either by referring to the channel name # or through a channel list, i.e. instr.A.temperature() and From c9f81c53eabeefb40bffa3662b298ee1c09f76dd Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 18 May 2024 07:35:26 +0200 Subject: [PATCH 02/12] Add types to Minicircuits instrument kwargs --- .../Minicircuits/Base_SPDT.py | 25 ++++-- .../Minicircuits/USBHIDMixin.py | 78 +++++++++++-------- .../Minicircuits/_minicircuits_rc_sp4t.py | 11 ++- .../Minicircuits/_minicircuits_rc_spdt.py | 11 ++- .../_minicircuits_rudat_13g_90.py | 19 +++-- .../Minicircuits/_minicircuits_usb_spdt.py | 30 +++---- 6 files changed, 113 insertions(+), 61 deletions(-) diff --git a/src/qcodes/instrument_drivers/Minicircuits/Base_SPDT.py b/src/qcodes/instrument_drivers/Minicircuits/Base_SPDT.py index 2d1aced191d..952152e7393 100644 --- a/src/qcodes/instrument_drivers/Minicircuits/Base_SPDT.py +++ b/src/qcodes/instrument_drivers/Minicircuits/Base_SPDT.py @@ -3,24 +3,39 @@ import logging import re import warnings -from typing import Any - -from qcodes.instrument import ChannelList, Instrument, InstrumentChannel +from typing import TYPE_CHECKING, Any + +from qcodes.instrument import ( + ChannelList, + Instrument, + InstrumentBaseKWArgs, + InstrumentChannel, +) from qcodes.validators import Ints +if TYPE_CHECKING: + from typing_extensions import Unpack + log = logging.getLogger(__name__) class SwitchChannelBase(InstrumentChannel): - def __init__(self, parent: Instrument, name: str, channel_letter: str): + def __init__( + self, + parent: Instrument, + name: str, + channel_letter: str, + **kwargs: Unpack[InstrumentBaseKWArgs], + ): """ Args: parent: The instrument the channel is a part of name: the name of the channel channel_letter: channel letter ['a', 'b', 'c' or 'd']) + **kwargs: Forwarded to base class. """ - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.channel_letter = channel_letter.upper() _chanlist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] self.channel_number = _chanlist.index(channel_letter) diff --git a/src/qcodes/instrument_drivers/Minicircuits/USBHIDMixin.py b/src/qcodes/instrument_drivers/Minicircuits/USBHIDMixin.py index 5d35ed64252..4c3af50d3af 100644 --- a/src/qcodes/instrument_drivers/Minicircuits/USBHIDMixin.py +++ b/src/qcodes/instrument_drivers/Minicircuits/USBHIDMixin.py @@ -4,7 +4,7 @@ import os import struct import time -from typing import Any, Optional +from typing import TYPE_CHECKING, Optional try: from pywinusb import hid # pyright: ignore[reportMissingModuleSource] @@ -17,16 +17,14 @@ from qcodes.instrument.base import Instrument +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import InstrumentBaseKWArgs + class USBHIDMixin(Instrument): - """ - Args: - instance_id: The id of the instrument we want to connect to. If - there is only one instrument, then this argument is optional. - If more than one instrument happen to be connected, use - `enumerate_devices` method to query their IDs - timeout: Specify a timeout for this instrument in seconds - """ + # The following class attributes should be set by subclasses vendor_id = 0x0000 product_id = 0x0000 @@ -42,9 +40,23 @@ def _check_hid_import() -> None: "'pip install pywinusb' in a qcodes environment terminal" ) - def __init__(self, name: str, instance_id: Optional[str] = None, - timeout: float = 2, - **kwargs: Any): + def __init__( + self, + name: str, + instance_id: Optional[str] = None, + timeout: float = 2, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): + """ + Args: + name: Name of the instrument. + instance_id: The id of the instrument we want to connect to. If + there is only one instrument, then this argument is optional. + If more than one instrument happen to be connected, use + `enumerate_devices` method to query their IDs + timeout: Specify a timeout for this instrument in seconds + **kwargs: Forwarded to base class. + """ self._check_hid_import() devs = hid.HidDeviceFilter( # pyright: ignore[reportPossiblyUnboundVariable] @@ -153,25 +165,29 @@ def enumerate_devices(cls) -> list[str]: class MiniCircuitsHIDMixin(USBHIDMixin): - """ - The specific implementation for mini circuit human interface devices. - - This implementation allows to use `write`/`ask` methods of the instrument - instance to send SCPI commands to MiniCircuits instruments over USB HID - connection. - - Args: - name: instrument name - instance_id: The id of the instrument we want to connect. If there is - only one instrument then this is an optional argument. If we have - more then one instrument, use the class method - `enumerate_devices` to query their IDs - timeout: Specify a timeout for this instrument in seconds - """ - - def __init__(self, name: str, instance_id: Optional[str] = None, - timeout: float = 2, - **kwargs: Any): + def __init__( + self, + name: str, + instance_id: Optional[str] = None, + timeout: float = 2, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): + """ + The specific implementation for mini circuit human interface devices. + + This implementation allows to use `write`/`ask` methods of the instrument + instance to send SCPI commands to MiniCircuits instruments over USB HID + connection. + + Args: + name: instrument name + instance_id: The id of the instrument we want to connect. If there is + only one instrument then this is an optional argument. If we have + more then one instrument, use the class method + `enumerate_devices` to query their IDs + timeout: Specify a timeout for this instrument in seconds + **kwargs: Forwarded to base class. + """ # USB interrupt code for sending SCPI commands self._sending_scpi_cmds_code = 1 self._usb_endpoint = 0 diff --git a/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rc_sp4t.py b/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rc_sp4t.py index 82df83e07f5..4a96f0d6917 100644 --- a/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rc_sp4t.py +++ b/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rc_sp4t.py @@ -14,15 +14,22 @@ class MiniCircuitsRCSP4TChannel(InstrumentChannel): - def __init__(self, parent: IPInstrument, name: str, channel_letter: str): + def __init__( + self, + parent: IPInstrument, + name: str, + channel_letter: str, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): """ Args: parent: The instrument the channel is a part of name: the name of the channel channel_letter: channel letter ['a', 'b']) + **kwargs: Forwarded to base class. """ - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.channel_letter = channel_letter.upper() chanlist = ["a", "b"] self.channel_number = chanlist.index(channel_letter) diff --git a/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rc_spdt.py b/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rc_spdt.py index f0d2c82c8be..32c4e238e69 100644 --- a/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rc_spdt.py +++ b/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rc_spdt.py @@ -13,15 +13,22 @@ class MiniCircuitsRCSPDTChannel(InstrumentChannel): - def __init__(self, parent: "MiniCircuitsRCSPDT", name: str, channel_letter: str): + def __init__( + self, + parent: "MiniCircuitsRCSPDT", + name: str, + channel_letter: str, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): """ Args: parent: The instrument the channel is a part of name: the name of the channel channel_letter: channel letter ['a', 'b', 'c' or 'd']) + **kwargs: Forwarded to the baseclass """ - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.channel_letter = channel_letter.upper() _chanlist = ["a", "b", "c", "d", "e", "f", "g", "h"] self.channel_number = _chanlist.index(channel_letter) diff --git a/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rudat_13g_90.py b/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rudat_13g_90.py index 2bf6bdc3077..85f02c71fb7 100644 --- a/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rudat_13g_90.py +++ b/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_rudat_13g_90.py @@ -1,17 +1,20 @@ -from typing import Any, Optional +from typing import TYPE_CHECKING, Optional -from qcodes.instrument import Instrument +from qcodes.instrument import Instrument, InstrumentBaseKWArgs from .USBHIDMixin import MiniCircuitsHIDMixin +if TYPE_CHECKING: + from typing_extensions import Unpack -class MiniCircuitsRudat13G90Base(Instrument): - """ - Args: - name (str) - """ - def __init__(self, name: str, **kwargs: Any) -> None: +class MiniCircuitsRudat13G90Base(Instrument): + def __init__(self, name: str, **kwargs: "Unpack[InstrumentBaseKWArgs]") -> None: + """ + Args: + name: Name of the instrument + **kwargs: Forwarded to base class. + """ super().__init__(name, **kwargs) self.add_parameter("model_name", get_cmd=":MN?") diff --git a/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_usb_spdt.py b/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_usb_spdt.py index 8ba5a3c7800..f9bb063c36d 100644 --- a/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_usb_spdt.py +++ b/src/qcodes/instrument_drivers/Minicircuits/_minicircuits_usb_spdt.py @@ -1,5 +1,5 @@ import os -from typing import Any, Optional +from typing import TYPE_CHECKING, Optional # QCoDeS imports from qcodes.instrument_drivers.Minicircuits.Base_SPDT import ( @@ -7,6 +7,11 @@ SwitchChannelBase, ) +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import InstrumentBaseKWArgs + try: import clr # pyright: ignore[reportMissingTypeStubs,reportMissingImports] except ImportError: @@ -27,17 +32,6 @@ def _get_switch(self) -> int: class MiniCircuitsUsbSPDT(SPDT_Base): - """ - Mini-Circuits SPDT RF switch - - Args: - name: the name of the instrument - driver_path: path to the dll - serial_number: the serial number of the device - (printed on the sticker on the back side, without s/n) - kwargs: kwargs to be passed to Instrument class. - """ - CHANNEL_CLASS = MiniCircuitsUsbSPDTSwitchChannel PATH_TO_DRIVER = r"mcl_RF_Switch_Controller64" PATH_TO_DRIVER_45 = r"mcl_RF_Switch_Controller_NET45" @@ -47,8 +41,18 @@ def __init__( name: str, driver_path: Optional[str] = None, serial_number: Optional[str] = None, - **kwargs: Any, + **kwargs: "Unpack[InstrumentBaseKWArgs]", ): + """ + Mini-Circuits SPDT RF switch + + Args: + name: the name of the instrument + driver_path: path to the dll + serial_number: the serial number of the device + (printed on the sticker on the back side, without s/n) + kwargs: kwargs to be passed to Instrument class. + """ # we are eventually overwriting this but since it's called # in __getattr__ of `SPDT_Base` it's important that it's # always set to something to avoid infinite recursion From c78c753201fe0d82273851c2718b8731cc1aa63c Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 18 May 2024 07:36:05 +0200 Subject: [PATCH 03/12] Add types to mock instrument kwargs --- .../mock_instruments/__init__.py | 74 ++++++++++++++----- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/src/qcodes/instrument_drivers/mock_instruments/__init__.py b/src/qcodes/instrument_drivers/mock_instruments/__init__.py index c3e100ff36a..949d626c881 100644 --- a/src/qcodes/instrument_drivers/mock_instruments/__init__.py +++ b/src/qcodes/instrument_drivers/mock_instruments/__init__.py @@ -56,8 +56,8 @@ class MockParabola(DummyBase): testing of numerical optimizations. """ - def __init__(self, name: str, **kw: Any): - super().__init__(name, **kw) + def __init__(self, name: str, **kwargs: Unpack[InstrumentBaseKWArgs]): + super().__init__(name, **kwargs) # Instrument parameters for parname in ['x', 'y', 'z']: @@ -101,11 +101,16 @@ class MockMetaParabola(InstrumentBase): snapshottable in a station. """ - def __init__(self, name: str, mock_parabola_inst: MockParabola, **kw: Any): + def __init__( + self, + name: str, + mock_parabola_inst: MockParabola, + **kwargs: Unpack[InstrumentBaseKWArgs], + ): """ Create a new MockMetaParabola, connected to an existing MockParabola instance. """ - super().__init__(name, **kw) + super().__init__(name, **kwargs) self.mock_parabola_inst = mock_parabola_inst # Instrument parameters @@ -134,7 +139,7 @@ def __init__( self, name: str = "dummy", gates: Sequence[str] = ("dac1", "dac2", "dac3"), - **kwargs: Any, + **kwargs: Unpack[InstrumentBaseKWArgs], ): """ Create a dummy instrument that can be used for testing @@ -162,8 +167,12 @@ def __init__( class DummyFailingInstrument(DummyBase): - def __init__(self, name: str = "dummy", fail: bool = True, **kwargs: Any): - + def __init__( + self, + name: str = "dummy", + fail: bool = True, + **kwargs: Unpack[InstrumentBaseKWArgs], + ): """ Create a dummy instrument that fails on initialization that can be used for testing @@ -180,8 +189,7 @@ def __init__(self, name: str = "dummy", fail: bool = True, **kwargs: Any): class DummyAttrInstrument(DummyBase): - def __init__(self, name: str = "dummy", **kwargs: Any): - + def __init__(self, name: str = "dummy", **kwargs: Unpack[InstrumentBaseKWArgs]): """ Create a dummy instrument that can be used for testing. This instrument has its parameters declared as attributes @@ -287,7 +295,12 @@ def gauss_2d(x: float, y: float) -> np.floating: class DummyInstrumentWithMeasurement(DummyBase): - def __init__(self, name: str, setter_instr: DummyInstrument, **kwargs: Any): + def __init__( + self, + name: str, + setter_instr: DummyInstrument, + **kwargs: Unpack[InstrumentBaseKWArgs], + ): super().__init__(name=name, **kwargs) self._setter_instr = setter_instr self.add_parameter('v1', @@ -311,7 +324,13 @@ class DummyChannel(InstrumentChannel): A single dummy channel implementation """ - def __init__(self, parent: Instrument, name: str, channel: str, **kwargs: Any): + def __init__( + self, + parent: Instrument, + name: str, + channel: str, + **kwargs: Unpack[InstrumentBaseKWArgs], + ): super().__init__(parent, name, **kwargs) self._channel = channel @@ -464,7 +483,10 @@ class DummyChannelInstrument(DummyBase): """ def __init__( - self, name: str, channel_names: Sequence[str] | None = None, **kwargs: Any + self, + name: str, + channel_names: Sequence[str] | None = None, + **kwargs: Unpack[InstrumentBaseKWArgs], ): super().__init__(name, **kwargs) @@ -488,7 +510,7 @@ class DummyChannelOnlyInstrument(DummyBase): Also use module names with _ in them to check that we can handle that. """ - def __init__(self, name: str, **kwargs: Any): + def __init__(self, name: str, **kwargs: Unpack[InstrumentBaseKWArgs]): super().__init__(name, **kwargs) channels = ChannelList(self, "Temp_Sensors", DummyChannel) @@ -945,7 +967,7 @@ def __init__( self, name: str, vals: Numbers = Numbers(min_value=-1.0, max_value=1.0), - **kwargs: Any, + **kwargs: Unpack[InstrumentBaseKWArgs], ): """Mock instrument for emulating a magnetic field axis @@ -1021,7 +1043,7 @@ def _field_ramp(self) -> Generator[float, float, None]: class MockLockin(DummyBase): - def __init__(self, name: str, **kwargs: Any): + def __init__(self, name: str, **kwargs: Unpack[InstrumentBaseKWArgs]): super().__init__(name=name, **kwargs) self.add_parameter("X", parameter_class=Parameter, @@ -1060,8 +1082,14 @@ class MockDACChannel(InstrumentChannel): A single dummy channel implementation """ - def __init__(self, parent: InstrumentBase, name: str, num: str): - super().__init__(parent, name) + def __init__( + self, + parent: InstrumentBase, + name: str, + num: str, + **kwargs: Unpack[InstrumentBaseKWArgs], + ): + super().__init__(parent, name, **kwargs) self._num = num self.add_parameter('voltage', @@ -1097,8 +1125,12 @@ def channel_number(self) -> str: class MockDAC(DummyBase): - def __init__(self, name: str = "mdac", num_channels: int = 10, **kwargs: Any): - + def __init__( + self, + name: str = "mdac", + num_channels: int = 10, + **kwargs: Unpack[InstrumentBaseKWArgs], + ): """ Create a dummy instrument that can be used for testing @@ -1129,6 +1161,7 @@ def __init__( name: str, channel: str | InstrumentChannel, current_valid_range: Sequence[float] | None = None, + **kwargs: Unpack[InstrumentBaseKWArgs], ) -> None: """ A custom instrument channel emulating an existing channel. @@ -1144,6 +1177,7 @@ def __init__( current_valid_range: Voltage range the channel is expected to show interesting features. It's just an example of an additional parameter a regular instrument channel does not have. + **kwargs: Forwarded to base class. """ if isinstance(channel, str): _, channel_name = channel.split(".") @@ -1154,7 +1188,7 @@ def __init__( else: raise ValueError('Unknown input type for "channel".') - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) if current_valid_range is None: current_valid_range = [] From b1ab91bda9f0792bd8426c8d85ade8466bee1d60 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 18 May 2024 07:50:47 +0200 Subject: [PATCH 04/12] Add types to O and Q instrument kwargs --- .../instrument_drivers/QDev/QDac_channels.py | 10 +++++- .../QuantumDesign/DynaCoolPPMS/DynaCool.py | 27 ++++++++++---- .../oxford/MercuryiPS_VISA.py | 35 +++++++++++++------ .../instrument_drivers/oxford/triton.py | 10 ++++-- 4 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/qcodes/instrument_drivers/QDev/QDac_channels.py b/src/qcodes/instrument_drivers/QDev/QDac_channels.py index 5d2d082f9cf..a13353fa00d 100644 --- a/src/qcodes/instrument_drivers/QDev/QDac_channels.py +++ b/src/qcodes/instrument_drivers/QDev/QDac_channels.py @@ -13,6 +13,7 @@ from qcodes.instrument import ( ChannelList, Instrument, + InstrumentBaseKWArgs, InstrumentChannel, VisaInstrument, VisaInstrumentKWArgs, @@ -36,13 +37,20 @@ class QDevQDacChannel(InstrumentChannel): _CHANNEL_VALIDATION = vals.Numbers(1, 48) - def __init__(self, parent: Instrument, name: str, channum: int): + def __init__( + self, + parent: Instrument, + name: str, + channum: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): """ Args: parent: The instrument to which the channel is attached. name: The name of the channel channum: The number of the channel in question (1-48) + **kwargs: Forwarded to base class. """ super().__init__(parent, name) diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index 1d4e9be075a..1a48370caf0 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -1,13 +1,25 @@ import warnings from functools import partial from time import sleep -from typing import Any, Callable, ClassVar, Literal, Optional, Union, cast +from typing import ( + TYPE_CHECKING, + Any, + Callable, + ClassVar, + Literal, + Optional, + Union, + cast, +) import numpy as np from pyvisa import VisaIOError import qcodes.validators as vals -from qcodes.instrument import VisaInstrument +from qcodes.instrument import VisaInstrument, VisaInstrumentKWArgs + +if TYPE_CHECKING: + from typing_extensions import Unpack class DynaCool(VisaInstrument): @@ -40,11 +52,12 @@ class DynaCool(VisaInstrument): 0: lambda: None, } - def __init__(self, name: str, - address: str, - **kwargs: Any) -> None: - super().__init__(name=name, address=address, terminator='\r\n', - **kwargs) + default_terminator = "\r\n" + + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ) -> None: + super().__init__(name=name, address=address, **kwargs) self.add_parameter('temperature', label='Temperature', diff --git a/src/qcodes/instrument_drivers/oxford/MercuryiPS_VISA.py b/src/qcodes/instrument_drivers/oxford/MercuryiPS_VISA.py index e702f4224e4..7ff28dc814f 100644 --- a/src/qcodes/instrument_drivers/oxford/MercuryiPS_VISA.py +++ b/src/qcodes/instrument_drivers/oxford/MercuryiPS_VISA.py @@ -3,16 +3,23 @@ import logging import time from functools import partial -from typing import Any, Callable, cast +from typing import TYPE_CHECKING, Callable, cast import numpy as np import numpy.typing as npt from packaging import version -from qcodes.instrument.channel import InstrumentChannel -from qcodes.instrument.visa import VisaInstrument +from qcodes.instrument import ( + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.math_utils import FieldVector +if TYPE_CHECKING: + from typing_extensions import Unpack + log = logging.getLogger(__name__) visalog = logging.getLogger('qcodes.instrument.visa') @@ -59,19 +66,26 @@ class OxfordMercuryWorkerPS(InstrumentChannel): Class to hold a worker power supply for the Oxford MercuryiPS """ - def __init__(self, parent: VisaInstrument, name: str, UID: str) -> None: + def __init__( + self, + parent: VisaInstrument, + name: str, + UID: str, + **kwargs: Unpack[InstrumentBaseKWArgs], + ) -> None: """ Args: parent: The Instrument instance of the MercuryiPS name: The 'colloquial' name of the PS UID: The UID as used internally by the MercuryiPS, e.g. 'GRPX' + **kwargs: Forwarded to base class. """ if ':' in UID: raise ValueError('Invalid UID. Must be axis group name or device ' 'name, e.g. "GRPX" or "PSU.M1"') - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.uid = UID # The firmware update from 2.5 -> 2.6 changed the command @@ -222,21 +236,21 @@ class OxfordMercuryiPS(VisaInstrument): supply """ + default_terminator = "\n" + def __init__( self, name: str, address: str, - visalib: str | None = None, + *, field_limits: Callable[[float, float, float], bool] | None = None, - **kwargs: Any, + **kwargs: Unpack[VisaInstrumentKWArgs], ) -> None: """ Args: name: The name to give this instrument internally in QCoDeS address: The VISA resource of the instrument. Note that a socket connection to port 7020 must be made - visalib: The VISA library to use. Leave blank if not in simulation - mode. field_limits: A function describing the allowed field range (T). The function shall take (x, y, z) as an input and return a boolean describing whether that field value is @@ -261,8 +275,7 @@ def __init__( "TCPIP0::XXX.XXX.XXX.XXX::7020::SOCKET." ) - super().__init__(name, address, terminator='\n', visalib=visalib, - **kwargs) + super().__init__(name, address, **kwargs) self.firmware = self.IDN()['firmware'] # TODO: Query instrument to ensure which PSUs are actually present diff --git a/src/qcodes/instrument_drivers/oxford/triton.py b/src/qcodes/instrument_drivers/oxford/triton.py index 5fdd62c1042..a5e54555700 100644 --- a/src/qcodes/instrument_drivers/oxford/triton.py +++ b/src/qcodes/instrument_drivers/oxford/triton.py @@ -3,11 +3,14 @@ import re from functools import partial from time import sleep -from typing import Any, Optional, Union +from typing import TYPE_CHECKING, Optional, Union -from qcodes.instrument import IPInstrument +from qcodes.instrument import InstrumentBaseKWArgs, IPInstrument from qcodes.validators import Enum, Ints, Numbers +if TYPE_CHECKING: + from typing_extensions import Unpack + class OxfordTriton(IPInstrument): r""" @@ -25,6 +28,7 @@ class OxfordTriton(IPInstrument): `[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry]` and is used to extract the available temperature channels. timeout: Defaults to 20. + **kwargs: Forwarded to base class. Status: beta-version. @@ -40,7 +44,7 @@ def __init__( terminator: str = "\r\n", tmpfile: Optional[str] = None, timeout: float = 20, - **kwargs: Any, + **kwargs: "Unpack[InstrumentBaseKWArgs]", ): super().__init__( name, From dc04bc6cf1df6635d9985c3ac30d7cca02ecf1dc Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 18 May 2024 08:05:03 +0200 Subject: [PATCH 05/12] Add types to Rigol drivers --- .../instrument_drivers/rigol/Rigol_DG1062.py | 41 +++++++++++++++---- .../instrument_drivers/rigol/Rigol_DG4000.py | 17 ++++++-- .../instrument_drivers/rigol/Rigol_DP821.py | 15 +++++-- .../instrument_drivers/rigol/Rigol_DP831.py | 15 +++++-- .../instrument_drivers/rigol/Rigol_DP832.py | 15 +++++-- .../instrument_drivers/rigol/Rigol_DS1074Z.py | 34 ++++++++++----- .../instrument_drivers/rigol/Rigol_DS4000.py | 38 +++++++++++++---- .../instrument_drivers/rigol/private/DP8xx.py | 21 +++++++--- 8 files changed, 148 insertions(+), 48 deletions(-) diff --git a/src/qcodes/instrument_drivers/rigol/Rigol_DG1062.py b/src/qcodes/instrument_drivers/rigol/Rigol_DG1062.py index d146ab7e0c4..8dfb964af03 100644 --- a/src/qcodes/instrument_drivers/rigol/Rigol_DG1062.py +++ b/src/qcodes/instrument_drivers/rigol/Rigol_DG1062.py @@ -1,11 +1,20 @@ import logging from functools import partial -from typing import Any, ClassVar, Union, cast +from typing import TYPE_CHECKING, Any, ClassVar, Union, cast from qcodes import validators as vals -from qcodes.instrument import ChannelList, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + ChannelList, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.utils import partial_with_docstring +if TYPE_CHECKING: + from typing_extensions import Unpack + log = logging.getLogger(__name__) @@ -15,8 +24,14 @@ class RigolDG1062Burst(InstrumentChannel): group burst commands together. """ - def __init__(self, parent: "RigolDG1062", name: str, channel: int): - super().__init__(parent, name) + def __init__( + self, + parent: "RigolDG1062", + name: str, + channel: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): + super().__init__(parent, name, **kwargs) self.channel = channel self.add_parameter( @@ -131,15 +146,22 @@ class RigolDG1062Channel(InstrumentChannel): waveforms: ClassVar[tuple[str, ...]] = tuple(waveform_params.keys()) - def __init__(self, parent: "RigolDG1062", name: str, channel: int): + def __init__( + self, + parent: "RigolDG1062", + name: str, + channel: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): """ Args: parent: The instrument this channel belongs to name: Name of the channel. channel: Number of the channel. + **kwargs: Forwarded to base class. """ - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.channel = channel for param, unit in [ @@ -361,9 +383,12 @@ class RigolDG1062(VisaInstrument): waveforms = RigolDG1062Channel.waveforms - def __init__(self, name: str, address: str, **kwargs: Any): + default_terminator = "\n" - super().__init__(name, address, terminator="\n", **kwargs) + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ): + super().__init__(name, address, **kwargs) channels = ChannelList(self, "channel", RigolDG1062Channel, snapshotable=False) diff --git a/src/qcodes/instrument_drivers/rigol/Rigol_DG4000.py b/src/qcodes/instrument_drivers/rigol/Rigol_DG4000.py index b84735c77b5..f3b15f6d435 100644 --- a/src/qcodes/instrument_drivers/rigol/Rigol_DG4000.py +++ b/src/qcodes/instrument_drivers/rigol/Rigol_DG4000.py @@ -1,13 +1,14 @@ from functools import partial -from typing import TYPE_CHECKING, Any, Union +from typing import TYPE_CHECKING, Union -from qcodes.instrument import VisaInstrument +from qcodes.instrument import VisaInstrument, VisaInstrumentKWArgs from qcodes.validators import Anything, Enum, Ints, MultiType, Numbers if TYPE_CHECKING: from collections.abc import Sequence import numpy as np + from typing_extensions import Unpack def is_number(s: str) -> bool: @@ -69,8 +70,16 @@ class RigolDG4000(VisaInstrument): This driver works for all four models (DG4202, DG4162, DG4102, DG4062). """ - def __init__(self, name: str, address: str, reset: bool = False, **kwargs: Any): - super().__init__(name, address, terminator="\n", **kwargs) + default_terminator = "\n" + + def __init__( + self, + name: str, + address: str, + reset: bool = False, + **kwargs: "Unpack[VisaInstrumentKWArgs]", + ): + super().__init__(name, address, **kwargs) model = self.get_idn()["model"] diff --git a/src/qcodes/instrument_drivers/rigol/Rigol_DP821.py b/src/qcodes/instrument_drivers/rigol/Rigol_DP821.py index 65e623c50f3..1d197d41bb0 100644 --- a/src/qcodes/instrument_drivers/rigol/Rigol_DP821.py +++ b/src/qcodes/instrument_drivers/rigol/Rigol_DP821.py @@ -1,14 +1,21 @@ -from typing import Any +from typing import TYPE_CHECKING -from .private.DP8xx import _RigolDP8xx +from .private.DP8xx import _RigelDP8xx +if TYPE_CHECKING: + from typing_extensions import Unpack -class RigolDP821(_RigolDP8xx): + from qcodes.instrument import VisaInstrumentKWArgs + + +class RigolDP821(_RigelDP8xx): """ This is the qcodes driver for the Rigol DP821(A) Power Supply """ - def __init__(self, name: str, address: str, **kwargs: Any): + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ): channel_ranges = [ (60.0, 1.0), (8.0, 10.0), diff --git a/src/qcodes/instrument_drivers/rigol/Rigol_DP831.py b/src/qcodes/instrument_drivers/rigol/Rigol_DP831.py index f847a742ab2..c62fd4d5ce5 100644 --- a/src/qcodes/instrument_drivers/rigol/Rigol_DP831.py +++ b/src/qcodes/instrument_drivers/rigol/Rigol_DP831.py @@ -1,14 +1,21 @@ -from typing import Any +from typing import TYPE_CHECKING -from .private.DP8xx import _RigolDP8xx +from .private.DP8xx import _RigelDP8xx +if TYPE_CHECKING: + from typing_extensions import Unpack -class RigolDP831(_RigolDP8xx): + from qcodes.instrument import VisaInstrumentKWArgs + + +class RigolDP831(_RigelDP8xx): """ This is the qcodes driver for the Rigol DP831(A) Power Supply """ - def __init__(self, name: str, address: str, **kwargs: Any): + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ): channel_ranges = [(8.0, 5.0), (30.0, 2.0), (-30.0, 2.0)] ovp_ranges_std = [(0.01, 8.8), (0.01, 33.0), (-0.01, -33.0)] diff --git a/src/qcodes/instrument_drivers/rigol/Rigol_DP832.py b/src/qcodes/instrument_drivers/rigol/Rigol_DP832.py index 190387c580f..4eaf72ea2e2 100644 --- a/src/qcodes/instrument_drivers/rigol/Rigol_DP832.py +++ b/src/qcodes/instrument_drivers/rigol/Rigol_DP832.py @@ -1,14 +1,21 @@ -from typing import Any +from typing import TYPE_CHECKING -from .private.DP8xx import _RigolDP8xx +from .private.DP8xx import _RigelDP8xx +if TYPE_CHECKING: + from typing_extensions import Unpack -class RigolDP832(_RigolDP8xx): + from qcodes.instrument import VisaInstrumentKWArgs + + +class RigolDP832(_RigelDP8xx): """ This is the qcodes driver for the Rigol DP832(A) Power Supply """ - def __init__(self, name: str, address: str, **kwargs: Any): + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ): channel_ranges = [(30.0, 3.0), (30.0, 3.0), (5.0, 3.0)] ovp_ranges_std = [(0.01, 33.0), (0.01, 33.0), (0.01, 5.5)] diff --git a/src/qcodes/instrument_drivers/rigol/Rigol_DS1074Z.py b/src/qcodes/instrument_drivers/rigol/Rigol_DS1074Z.py index 0eb2ae7485b..0f02393082d 100644 --- a/src/qcodes/instrument_drivers/rigol/Rigol_DS1074Z.py +++ b/src/qcodes/instrument_drivers/rigol/Rigol_DS1074Z.py @@ -1,11 +1,20 @@ -from typing import Any +from typing import TYPE_CHECKING import numpy as np -from qcodes.instrument import ChannelList, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + ChannelList, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import ParameterWithSetpoints from qcodes.validators import Arrays, Enum, Numbers +if TYPE_CHECKING: + from typing_extensions import Unpack + class RigolDS1074ZChannel(InstrumentChannel): """ @@ -16,8 +25,14 @@ class RigolDS1074ZChannel(InstrumentChannel): can be obtained using 'trace' parameter. """ - def __init__(self, parent: "RigolDS1074Z", name: str, channel: int): - super().__init__(parent, name) + def __init__( + self, + parent: "RigolDS1074Z", + name: str, + channel: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): + super().__init__(parent, name, **kwargs) self.channel = channel self.add_parameter( @@ -71,17 +86,16 @@ class RigolDS1074Z(VisaInstrument): terminator: terminator for SCPI commands. """ + default_terminator = "\n" + default_timeout = 5 + def __init__( self, name: str, address: str, - terminator: str = "\n", - timeout: float = 5, - **kwargs: Any, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ): - super().__init__( - name, address, terminator=terminator, timeout=timeout, **kwargs - ) + super().__init__(name, address, **kwargs) self.add_parameter( "waveform_xorigin", get_cmd="WAVeform:XORigin?", unit="s", get_parser=float diff --git a/src/qcodes/instrument_drivers/rigol/Rigol_DS4000.py b/src/qcodes/instrument_drivers/rigol/Rigol_DS4000.py index 60f03d4462c..5978baec116 100644 --- a/src/qcodes/instrument_drivers/rigol/Rigol_DS4000.py +++ b/src/qcodes/instrument_drivers/rigol/Rigol_DS4000.py @@ -5,15 +5,24 @@ import time import warnings from collections import namedtuple -from typing import Any +from typing import TYPE_CHECKING import numpy as np from packaging import version from qcodes import validators as vals -from qcodes.instrument import ChannelList, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + ChannelList, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import ArrayParameter, ParamRawDataType +if TYPE_CHECKING: + from typing_extensions import Unpack + log = logging.getLogger(__name__) @@ -190,8 +199,14 @@ def conv(x: str) -> float: class RigolDS4000Channel(InstrumentChannel): - def __init__(self, parent: RigolDS4000, name: str, channel: int): - super().__init__(parent, name) + def __init__( + self, + parent: RigolDS4000, + name: str, + channel: int, + **kwargs: Unpack[InstrumentBaseKWArgs], + ): + super().__init__(parent, name, **kwargs) self.add_parameter( "amplitude", get_cmd=f":MEASure:VAMP? chan{channel}", get_parser=float @@ -219,21 +234,28 @@ class RigolDS4000(VisaInstrument): This is the QCoDeS driver for the Rigol DS4000 series oscilloscopes. """ - def __init__(self, name: str, address: str, timeout: float = 20, **kwargs: Any): + default_timeout = 20 + + def __init__( + self, + name: str, + address: str, + **kwargs: Unpack[VisaInstrumentKWArgs], + ): """ Initialises the DS4000. Args: name: Name of the instrument used by QCoDeS address: Instrument address as used by VISA - timeout: visa timeout, in secs. long default (180) - to accommodate large waveforms **kwargs: kwargs are forwarded to base class. """ # Init VisaInstrument. device_clear MUST NOT be issued, otherwise communications hangs # due a bug in firmware - super().__init__(name, address, device_clear=False, timeout=timeout, **kwargs) + kwargs["device_clear"] = False + + super().__init__(name, address, **kwargs) self.connect_message() self._check_firmware_version() diff --git a/src/qcodes/instrument_drivers/rigol/private/DP8xx.py b/src/qcodes/instrument_drivers/rigol/private/DP8xx.py index cf267f9598b..db488ffff0b 100644 --- a/src/qcodes/instrument_drivers/rigol/private/DP8xx.py +++ b/src/qcodes/instrument_drivers/rigol/private/DP8xx.py @@ -1,23 +1,32 @@ -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from qcodes import validators as vals -from qcodes.instrument import ChannelList, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + ChannelList, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) if TYPE_CHECKING: from collections.abc import Sequence + from typing_extensions import Unpack + class RigolDP8xxChannel(InstrumentChannel): def __init__( self, - parent: "_RigolDP8xx", + parent: "_RigelDP8xx", name: str, channel: int, ch_range: tuple[float, float], ovp_range: tuple[float, float], ocp_range: tuple[float, float], + **kwargs: "Unpack[InstrumentBaseKWArgs]", ): - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.vmax = ch_range[0] self.imax = ch_range[1] @@ -127,7 +136,7 @@ def strstrip(s: str) -> str: ) -class _RigolDP8xx(VisaInstrument): +class _RigelDP8xx(VisaInstrument): """ This is the general DP8xx Power Supply driver class that implements shared parameters and functionality among all similar power supply from Rigole. @@ -146,7 +155,7 @@ def __init__( ocp_ranges: tuple[ "Sequence[tuple[float, float]]", "Sequence[tuple[float, float]]" ], - **kwargs: Any, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ): super().__init__(name, address, **kwargs) From d4fc16e1b5c0ee7c0bfaf7a56e718db238295568 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 18 May 2024 08:22:11 +0200 Subject: [PATCH 06/12] Add types to RS drivers --- .../rohde_schwarz/RTO1000.py | 58 ++++++++++++++----- .../rohde_schwarz/SGS100A.py | 15 +++-- .../instrument_drivers/rohde_schwarz/ZNB.py | 20 +++++-- 3 files changed, 69 insertions(+), 24 deletions(-) diff --git a/src/qcodes/instrument_drivers/rohde_schwarz/RTO1000.py b/src/qcodes/instrument_drivers/rohde_schwarz/RTO1000.py index a51bcab41a6..2055862ef68 100644 --- a/src/qcodes/instrument_drivers/rohde_schwarz/RTO1000.py +++ b/src/qcodes/instrument_drivers/rohde_schwarz/RTO1000.py @@ -4,15 +4,24 @@ import logging import time import warnings -from typing import Any, Optional +from typing import TYPE_CHECKING, Any, Optional import numpy as np from packaging import version import qcodes.validators as vals -from qcodes.instrument import Instrument, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + Instrument, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import ArrayParameter, create_on_off_val_mapping +if TYPE_CHECKING: + from typing_extensions import Unpack + log = logging.getLogger(__name__) @@ -142,20 +151,27 @@ class RohdeSchwarzRTO1000ScopeMeasurement(InstrumentChannel): Class to hold a measurement of the scope. """ - def __init__(self, parent: Instrument, name: str, meas_nr: int) -> None: + def __init__( + self, + parent: Instrument, + name: str, + meas_nr: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ) -> None: """ Args: parent: The instrument to which the channel is attached name: The name of the measurement meas_nr: The number of the measurement in question. Must match the actual number as used by the instrument (1..8) + **kwargs: Forwarded to base class. """ if meas_nr not in range(1, 9): raise ValueError('Invalid measurement number; Min: 1, max 8') self.meas_nr = meas_nr - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.sources = vals.Enum('C1W1', 'C1W2', 'C1W3', 'C2W1', 'C2W2', 'C2W3', @@ -301,13 +317,20 @@ class RohdeSchwarzRTO1000ScopeChannel(InstrumentChannel): invert, bandwidth, impedance, overload. """ - def __init__(self, parent: Instrument, name: str, channum: int) -> None: + def __init__( + self, + parent: Instrument, + name: str, + channum: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ) -> None: """ Args: parent: The instrument to which the channel is attached name: The name of the channel channum: The number of the channel in question. Must match the actual number as used by the instrument (1..4) + **kwargs: Forwarded to base class. """ if channum not in [1, 2, 3, 4]: @@ -315,7 +338,7 @@ def __init__(self, parent: Instrument, name: str, channum: int) -> None: self.channum = channum - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.add_parameter('state', label=f'Channel {channum} state', @@ -445,26 +468,29 @@ class RohdeSchwarzRTO1000(VisaInstrument): """ - def __init__(self, name: str, address: str, - model: Optional[str] = None, timeout: float = 5., - HD: bool = True, - terminator: str = '\n', - **kwargs: Any) -> None: + default_timeout = 5.0 + default_terminator = "\n" + + def __init__( + self, + name: str, + address: str, + *, + model: Optional[str] = None, + HD: bool = True, + **kwargs: "Unpack[VisaInstrumentKWArgs]", + ) -> None: """ Args: name: name of the instrument address: VISA resource address model: The instrument model. For newer firmware versions, this can be auto-detected - timeout: The VISA query timeout HD: Does the unit have the High Definition Option (allowing 16 bit vertical resolution) - terminator: Command termination character to strip from VISA - commands. **kwargs: kwargs are forwarded to base class. """ - super().__init__(name=name, address=address, timeout=timeout, - terminator=terminator, **kwargs) + super().__init__(name=name, address=address, **kwargs) # With firmware versions earlier than 3.65, it seems that the # model number can NOT be queried from the instrument diff --git a/src/qcodes/instrument_drivers/rohde_schwarz/SGS100A.py b/src/qcodes/instrument_drivers/rohde_schwarz/SGS100A.py index 515103a7f0c..f68ca8b56ef 100644 --- a/src/qcodes/instrument_drivers/rohde_schwarz/SGS100A.py +++ b/src/qcodes/instrument_drivers/rohde_schwarz/SGS100A.py @@ -1,9 +1,12 @@ -from typing import Any +from typing import TYPE_CHECKING import qcodes.validators as vals -from qcodes.instrument import VisaInstrument +from qcodes.instrument import VisaInstrument, VisaInstrumentKWArgs from qcodes.parameters import create_on_off_val_mapping +if TYPE_CHECKING: + from typing_extensions import Unpack + class RohdeSchwarzSGS100A(VisaInstrument): """ @@ -30,8 +33,12 @@ class RohdeSchwarzSGS100A(VisaInstrument): only the ones most commonly used. """ - def __init__(self, name: str, address: str, **kwargs: Any) -> None: - super().__init__(name, address, terminator="\n", **kwargs) + default_terminator = "\n" + + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ) -> None: + super().__init__(name, address, **kwargs) self.add_parameter( name="frequency", diff --git a/src/qcodes/instrument_drivers/rohde_schwarz/ZNB.py b/src/qcodes/instrument_drivers/rohde_schwarz/ZNB.py index 24e4d9ee372..b812aa10537 100644 --- a/src/qcodes/instrument_drivers/rohde_schwarz/ZNB.py +++ b/src/qcodes/instrument_drivers/rohde_schwarz/ZNB.py @@ -1,11 +1,18 @@ import logging from functools import partial -from typing import Any, Optional +from typing import TYPE_CHECKING, Any, Optional import numpy as np import qcodes.validators as vals -from qcodes.instrument import ChannelList, Instrument, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + ChannelList, + Instrument, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import ( ArrayParameter, ManualParameter, @@ -14,6 +21,9 @@ create_on_off_val_mapping, ) +if TYPE_CHECKING: + from typing_extensions import Unpack + log = logging.getLogger(__name__) @@ -349,6 +359,7 @@ def __init__( channel: int, vna_parameter: Optional[str] = None, existing_trace_to_bind_to: Optional[str] = None, + **kwargs: "Unpack[InstrumentBaseKWArgs]", ) -> None: """ Args: @@ -361,6 +372,7 @@ def __init__( existing_trace_to_bind_to: Name of an existing trace on the VNA. If supplied try to bind to an existing trace with this name rather than creating a new trace. + **kwargs: Forwarded to base class. """ n = channel self._instrument_channel = channel @@ -368,7 +380,7 @@ def __init__( if vna_parameter is None: vna_parameter = name self._vna_parameter = vna_parameter - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) if existing_trace_to_bind_to is None: self._tracename = f"Trc{channel}" @@ -961,7 +973,7 @@ def __init__( address: str, init_s_params: bool = True, reset_channels: bool = True, - **kwargs: Any, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ) -> None: super().__init__(name=name, address=address, **kwargs) From 292818c3d98aeb300414c675c873939d48e5ec2e Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 18 May 2024 08:24:35 +0200 Subject: [PATCH 07/12] Add types to signalhound drivers --- .../signal_hound/SignalHound_USB_SA124B.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/qcodes/instrument_drivers/signal_hound/SignalHound_USB_SA124B.py b/src/qcodes/instrument_drivers/signal_hound/SignalHound_USB_SA124B.py index 6553541fc8a..dcca1c20234 100644 --- a/src/qcodes/instrument_drivers/signal_hound/SignalHound_USB_SA124B.py +++ b/src/qcodes/instrument_drivers/signal_hound/SignalHound_USB_SA124B.py @@ -2,14 +2,17 @@ import logging from enum import IntEnum from time import sleep -from typing import Any, Optional +from typing import TYPE_CHECKING, Any, Optional import numpy as np import qcodes.validators as vals -from qcodes.instrument import Instrument +from qcodes.instrument import Instrument, InstrumentBaseKWArgs from qcodes.parameters import ArrayParameter, Parameter, ParameterWithSetpoints +if TYPE_CHECKING: + from typing_extensions import Unpack + log = logging.getLogger(__name__) @@ -186,7 +189,12 @@ class SignalHoundUSBSA124B(Instrument): dll_path = "C:\\Program Files\\Signal Hound\\Spike\\sa_api.dll" - def __init__(self, name: str, dll_path: Optional[str] = None, **kwargs: Any): + def __init__( + self, + name: str, + dll_path: Optional[str] = None, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): """ Args: name: Name of the instrument. From c8f991c85ca5a7639efb076f1218f4b0f4207710 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 18 May 2024 08:24:53 +0200 Subject: [PATCH 08/12] Add types to stahl drivers --- src/qcodes/instrument_drivers/stahl/stahl.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/qcodes/instrument_drivers/stahl/stahl.py b/src/qcodes/instrument_drivers/stahl/stahl.py index 8d3aab32a52..b5745774205 100644 --- a/src/qcodes/instrument_drivers/stahl/stahl.py +++ b/src/qcodes/instrument_drivers/stahl/stahl.py @@ -15,6 +15,7 @@ from qcodes.instrument import ( ChannelList, + InstrumentBaseKWArgs, InstrumentChannel, VisaInstrument, VisaInstrumentKWArgs, @@ -65,8 +66,14 @@ class StahlChannel(InstrumentChannel): acknowledge_reply = chr(6) - def __init__(self, parent: VisaInstrument, name: str, channel_number: int): - super().__init__(parent, name) + def __init__( + self, + parent: VisaInstrument, + name: str, + channel_number: int, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ): + super().__init__(parent, name, **kwargs) self._channel_string = f"{channel_number:02d}" self._channel_number = channel_number From a500c2f4a8a6f0c2c2b829574fb89a71af840286 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 18 May 2024 08:44:42 +0200 Subject: [PATCH 09/12] Add types to SRS drivers --- .../stanford_research/SG384.py | 23 ++++++++---- .../stanford_research/SR560.py | 10 ++++-- .../stanford_research/SR830.py | 6 ++-- .../stanford_research/SR860.py | 13 ++++++- .../stanford_research/SR865.py | 13 ++++++- .../stanford_research/SR865A.py | 17 +++++++-- .../stanford_research/SR86x.py | 36 +++++++++++++------ 7 files changed, 92 insertions(+), 26 deletions(-) diff --git a/src/qcodes/instrument_drivers/stanford_research/SG384.py b/src/qcodes/instrument_drivers/stanford_research/SG384.py index 4658f35326b..de32afde8dd 100644 --- a/src/qcodes/instrument_drivers/stanford_research/SG384.py +++ b/src/qcodes/instrument_drivers/stanford_research/SG384.py @@ -1,7 +1,10 @@ -from typing import Any +from typing import TYPE_CHECKING from qcodes import validators as vals -from qcodes.instrument import VisaInstrument +from qcodes.instrument import VisaInstrument, VisaInstrumentKWArgs + +if TYPE_CHECKING: + from typing_extensions import Unpack class SG384(VisaInstrument): @@ -11,10 +14,18 @@ class SG384(VisaInstrument): Status: beta version Includes the essential commands from the manual """ - def __init__(self, name: str, address: str, - reset: bool = False, **kwargs: Any): - super().__init__(name, address, terminator='\n', **kwargs) - # signal synthesis commands + + default_terminator = "\n" + + def __init__( + self, + name: str, + address: str, + reset: bool = False, + **kwargs: "Unpack[VisaInstrumentKWArgs]", + ): + super().__init__(name, address, **kwargs) + # signal synthesis commands self.add_parameter(name='frequency', label='Frequency', unit='Hz', diff --git a/src/qcodes/instrument_drivers/stanford_research/SR560.py b/src/qcodes/instrument_drivers/stanford_research/SR560.py index a3bd19f7b76..bbe3f517c93 100644 --- a/src/qcodes/instrument_drivers/stanford_research/SR560.py +++ b/src/qcodes/instrument_drivers/stanford_research/SR560.py @@ -1,9 +1,12 @@ -from typing import Any, Optional +from typing import TYPE_CHECKING, Optional -from qcodes.instrument import Instrument +from qcodes.instrument import Instrument, InstrumentBaseKWArgs from qcodes.parameters import MultiParameter, Parameter, ParamRawDataType from qcodes.validators import Bool, Enum +if TYPE_CHECKING: + from typing_extensions import Unpack + class VoltageParameter(MultiParameter): """ @@ -75,7 +78,8 @@ class SR560(Instrument): output. We restrict this driver to only the predefined gain values. """ - def __init__(self, name: str, **kwargs: Any): + + def __init__(self, name: str, **kwargs: "Unpack[InstrumentBaseKWArgs]"): super().__init__(name, **kwargs) cutoffs = ['DC', 0.03, 0.1, 0.3, 1, 3, 10, 30, 100, 300, 1000, diff --git a/src/qcodes/instrument_drivers/stanford_research/SR830.py b/src/qcodes/instrument_drivers/stanford_research/SR830.py index 3b2aca0e76d..472fca3c3d2 100644 --- a/src/qcodes/instrument_drivers/stanford_research/SR830.py +++ b/src/qcodes/instrument_drivers/stanford_research/SR830.py @@ -6,7 +6,7 @@ import numpy as np -from qcodes.instrument import VisaInstrument +from qcodes.instrument import VisaInstrument, VisaInstrumentKWArgs from qcodes.parameters import ( ArrayParameter, Parameter, @@ -18,6 +18,8 @@ if TYPE_CHECKING: from collections.abc import Iterable + from typing_extensions import Unpack + class ChannelTrace(ParameterWithSetpoints): """ @@ -274,7 +276,7 @@ class SR830(VisaInstrument): v: k for k, v in _INPUT_CONFIG_TO_N.items() } - def __init__(self, name: str, address: str, **kwargs: Any): + def __init__(self, name: str, address: str, **kwargs: Unpack[VisaInstrumentKWArgs]): super().__init__(name, address, **kwargs) # Reference and phase diff --git a/src/qcodes/instrument_drivers/stanford_research/SR860.py b/src/qcodes/instrument_drivers/stanford_research/SR860.py index 7b66659aeb9..7cbc82171f8 100644 --- a/src/qcodes/instrument_drivers/stanford_research/SR860.py +++ b/src/qcodes/instrument_drivers/stanford_research/SR860.py @@ -1,5 +1,12 @@ +from typing import TYPE_CHECKING + from qcodes.instrument_drivers.stanford_research.SR86x import SR86x +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import VisaInstrumentKWArgs + class SR860(SR86x): """ @@ -9,6 +16,10 @@ class SR860(SR86x): """ def __init__( - self, name: str, address: str, reset: bool = False, **kwargs: str + self, + name: str, + address: str, + reset: bool = False, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ) -> None: super().__init__(name, address, max_frequency=500e3, reset=reset, **kwargs) diff --git a/src/qcodes/instrument_drivers/stanford_research/SR865.py b/src/qcodes/instrument_drivers/stanford_research/SR865.py index 8915e7ab186..1fe7a5a4422 100644 --- a/src/qcodes/instrument_drivers/stanford_research/SR865.py +++ b/src/qcodes/instrument_drivers/stanford_research/SR865.py @@ -1,5 +1,12 @@ +from typing import TYPE_CHECKING + from qcodes.instrument_drivers.stanford_research.SR86x import SR86x +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import VisaInstrumentKWArgs + class SR865(SR86x): """ @@ -9,6 +16,10 @@ class SR865(SR86x): """ def __init__( - self, name: str, address: str, reset: bool = False, **kwargs: str + self, + name: str, + address: str, + reset: bool = False, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ) -> None: super().__init__(name, address, max_frequency=2e6, reset=reset, **kwargs) diff --git a/src/qcodes/instrument_drivers/stanford_research/SR865A.py b/src/qcodes/instrument_drivers/stanford_research/SR865A.py index 1986a1bfdd8..eeaaab12470 100644 --- a/src/qcodes/instrument_drivers/stanford_research/SR865A.py +++ b/src/qcodes/instrument_drivers/stanford_research/SR865A.py @@ -1,5 +1,12 @@ +from typing import TYPE_CHECKING + from qcodes.instrument_drivers.stanford_research.SR86x import SR86x +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import VisaInstrumentKWArgs + class SR865A(SR86x): """ @@ -8,7 +15,13 @@ class SR865A(SR86x): The SR865A instrument is almost equal to the SR865, except for the max frequency """ - def __init__(self, name: str, address: str, - reset: bool = False, **kwargs: str) -> None: + + def __init__( + self, + name: str, + address: str, + reset: bool = False, + **kwargs: "Unpack[VisaInstrumentKWArgs]", + ) -> None: super().__init__(name, address, max_frequency=4E6, reset=reset, **kwargs) diff --git a/src/qcodes/instrument_drivers/stanford_research/SR86x.py b/src/qcodes/instrument_drivers/stanford_research/SR86x.py index ecc4900384c..ea08fa6b5d2 100644 --- a/src/qcodes/instrument_drivers/stanford_research/SR86x.py +++ b/src/qcodes/instrument_drivers/stanford_research/SR86x.py @@ -5,13 +5,21 @@ import numpy as np -from qcodes.instrument import ChannelList, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + ChannelList, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import ArrayParameter from qcodes.validators import ComplexNumbers, Enum, Ints, Numbers if TYPE_CHECKING: from collections.abc import Sequence + from typing_extensions import Unpack + log = logging.getLogger(__name__) @@ -82,8 +90,10 @@ class SR86xBuffer(InstrumentChannel): manual: http://thinksrs.com/downloads/PDFs/Manuals/SR860m.pdf """ - def __init__(self, parent: SR86x, name: str) -> None: - super().__init__(parent, name) + def __init__( + self, parent: SR86x, name: str, **kwargs: Unpack[InstrumentBaseKWArgs] + ) -> None: + super().__init__(parent, name, **kwargs) self.add_parameter( "capture_length_in_kb", @@ -582,8 +592,9 @@ def __init__( cmd_id: str, cmd_id_name: str | None = None, color: str | None = None, + **kwargs: Unpack[InstrumentBaseKWArgs], ) -> None: - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self._cmd_id = cmd_id self._cmd_id_name = cmd_id_name @@ -715,14 +726,17 @@ class SR86x(VisaInstrument): _N_DATA_CHANNELS = 4 + default_terminator = "\n" + def __init__( - self, - name: str, - address: str, - max_frequency: float, - reset: bool = False, - **kwargs: Any): - super().__init__(name, address, terminator='\n', **kwargs) + self, + name: str, + address: str, + max_frequency: float, + reset: bool = False, + **kwargs: Unpack[VisaInstrumentKWArgs], + ): + super().__init__(name, address, **kwargs) self._max_frequency = max_frequency # Reference commands self.add_parameter(name='frequency', From ff26c542b9f45a5d49656adaf7b7f35f29911f4f Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 18 May 2024 08:50:28 +0200 Subject: [PATCH 10/12] Add types to tektronix drivers --- .../instrument_drivers/tektronix/AWG5014.py | 35 ++++-- .../instrument_drivers/tektronix/AWG5208.py | 21 ++-- .../instrument_drivers/tektronix/AWG70000A.py | 32 ++++-- .../instrument_drivers/tektronix/AWG70002A.py | 17 ++- .../instrument_drivers/tektronix/DPO7200xx.py | 100 +++++++++--------- .../instrument_drivers/tektronix/TPS2012.py | 30 ++++-- .../tektronix/Tektronix_70001A.py | 17 ++- .../tektronix/Tektronix_70001B.py | 17 ++- .../tektronix/Tektronix_70002B.py | 17 ++- 9 files changed, 188 insertions(+), 98 deletions(-) diff --git a/src/qcodes/instrument_drivers/tektronix/AWG5014.py b/src/qcodes/instrument_drivers/tektronix/AWG5014.py index ac7ba3e9af8..18daddab6e4 100644 --- a/src/qcodes/instrument_drivers/tektronix/AWG5014.py +++ b/src/qcodes/instrument_drivers/tektronix/AWG5014.py @@ -6,13 +6,25 @@ from collections.abc import Sequence from io import BytesIO from time import localtime, sleep -from typing import Any, ClassVar, Literal, NamedTuple, Optional, Union, cast +from typing import ( + TYPE_CHECKING, + Any, + ClassVar, + Literal, + NamedTuple, + Optional, + Union, + cast, +) import numpy as np from pyvisa.errors import VisaIOError from qcodes import validators as vals -from qcodes.instrument import VisaInstrument +from qcodes.instrument import VisaInstrument, VisaInstrumentKWArgs + +if TYPE_CHECKING: + from typing_extensions import Unpack log = logging.getLogger(__name__) @@ -135,25 +147,26 @@ class TektronixAWG5014(VisaInstrument): 'DC_OUTPUT_LEVEL_N': 'd', # V } + default_timeout = 180 + def __init__( - self, - name: str, - address: str, - timeout: int = 180, - num_channels: int = 4, - **kwargs: Any): + self, + name: str, + address: str, + *, + num_channels: int = 4, + **kwargs: "Unpack[VisaInstrumentKWArgs]", + ): """ Initializes the AWG5014. Args: name: name of the instrument address: GPIB or ethernet address as used by VISA - timeout: visa timeout, in secs. long default (180) - to accommodate large waveforms num_channels: number of channels on the device **kwargs: kwargs are forwarded to base class. """ - super().__init__(name, address, timeout=timeout, **kwargs) + super().__init__(name, address, **kwargs) self._address = address self.num_channels = num_channels diff --git a/src/qcodes/instrument_drivers/tektronix/AWG5208.py b/src/qcodes/instrument_drivers/tektronix/AWG5208.py index 27580d2b405..22d07137723 100644 --- a/src/qcodes/instrument_drivers/tektronix/AWG5208.py +++ b/src/qcodes/instrument_drivers/tektronix/AWG5208.py @@ -1,25 +1,34 @@ -from typing import Any +from typing import TYPE_CHECKING from .AWG70000A import AWG70000A +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import VisaInstrumentKWArgs + class TektronixAWG5208(AWG70000A): """ The QCoDeS driver for Tektronix AWG5208 """ - def __init__(self, name: str, address: str, - timeout: float = 10, **kwargs: Any) -> None: + default_timeout = 10 + + def __init__( + self, + name: str, + address: str, + **kwargs: "Unpack[VisaInstrumentKWArgs]", + ) -> None: """ Args: name: The name used internally by QCoDeS in the DataSet address: The VISA resource name of the instrument - timeout: The VISA timeout time (in seconds). **kwargs: kwargs are forwarded to base class. """ - super().__init__(name, address, num_channels=8, - timeout=timeout, **kwargs) + super().__init__(name, address, num_channels=8, **kwargs) class AWG5208(TektronixAWG5208): diff --git a/src/qcodes/instrument_drivers/tektronix/AWG70000A.py b/src/qcodes/instrument_drivers/tektronix/AWG70000A.py index 73db1d04060..996c8a8175e 100644 --- a/src/qcodes/instrument_drivers/tektronix/AWG70000A.py +++ b/src/qcodes/instrument_drivers/tektronix/AWG70000A.py @@ -14,12 +14,21 @@ from broadbean.sequence import InvalidForgedSequenceError, fs_schema from qcodes import validators as vals -from qcodes.instrument import ChannelList, Instrument, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + ChannelList, + Instrument, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import create_on_off_val_mapping if TYPE_CHECKING: from collections.abc import Mapping, Sequence + from typing_extensions import Unpack + log = logging.getLogger(__name__) ################################################## @@ -157,16 +166,23 @@ class Tektronix70000AWGChannel(InstrumentChannel): Class to hold a channel of the AWG. """ - def __init__(self, parent: Instrument, name: str, channel: int) -> None: + def __init__( + self, + parent: Instrument, + name: str, + channel: int, + **kwargs: Unpack[InstrumentBaseKWArgs], + ) -> None: """ Args: parent: The Instrument instance to which the channel is to be attached. name: The name used in the DataSet channel: The channel number, either 1 or 2. + **kwargs: Forwarded to base class. """ - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.channel = channel @@ -413,27 +429,27 @@ class AWG70000A(VisaInstrument): subclasses of this general class. """ + default_terminator = "\n" + default_timeout = 10 + def __init__( self, name: str, address: str, num_channels: int, - timeout: float = 10, - **kwargs: Any, + **kwargs: Unpack[VisaInstrumentKWArgs], ) -> None: """ Args: name: The name used internally by QCoDeS in the DataSet address: The VISA resource name of the instrument - timeout: The VISA timeout time (in seconds) num_channels: Number of channels on the AWG **kwargs: kwargs are forwarded to base class. """ self.num_channels = num_channels - super().__init__(name, address, timeout=timeout, terminator='\n', - **kwargs) + super().__init__(name, address, **kwargs) # The 'model' value begins with 'AWG' self.model = self.IDN()['model'][3:] diff --git a/src/qcodes/instrument_drivers/tektronix/AWG70002A.py b/src/qcodes/instrument_drivers/tektronix/AWG70002A.py index 18ace056e82..76b7aa658e9 100644 --- a/src/qcodes/instrument_drivers/tektronix/AWG70002A.py +++ b/src/qcodes/instrument_drivers/tektronix/AWG70002A.py @@ -1,7 +1,12 @@ -from typing import Any +from typing import TYPE_CHECKING from .AWG70000A import AWG70000A +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import VisaInstrumentKWArgs + class TektronixAWG70002A(AWG70000A): """ @@ -10,8 +15,13 @@ class TektronixAWG70002A(AWG70000A): All the actual driver meat is in the superclass AWG70000A. """ + default_timeout = 10 + def __init__( - self, name: str, address: str, timeout: float = 10, **kwargs: Any + self, + name: str, + address: str, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ) -> None: """ Args: @@ -21,8 +31,7 @@ def __init__( **kwargs: kwargs are forwarded to base class. """ - super().__init__(name, address, num_channels=2, - timeout=timeout, **kwargs) + super().__init__(name, address, num_channels=2, **kwargs) class AWG70002A(TektronixAWG70002A): diff --git a/src/qcodes/instrument_drivers/tektronix/DPO7200xx.py b/src/qcodes/instrument_drivers/tektronix/DPO7200xx.py index e98c656df3a..0e39d182d8d 100644 --- a/src/qcodes/instrument_drivers/tektronix/DPO7200xx.py +++ b/src/qcodes/instrument_drivers/tektronix/DPO7200xx.py @@ -9,9 +9,17 @@ from typing import Any, Callable, ClassVar, Union, cast import numpy as np -from typing_extensions import deprecated - -from qcodes.instrument import ChannelList, Instrument, InstrumentChannel, VisaInstrument +from typing_extensions import Unpack, deprecated + +from qcodes.instrument import ( + ChannelList, + Instrument, + InstrumentBase, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import ( Parameter, ParameterWithSetpoints, @@ -52,15 +60,12 @@ class TektronixDPO7000xx(VisaInstrument): number_of_channels = 4 number_of_measurements = 8 # The number of available # measurements does not change. + default_terminator = "\n" def __init__( - self, - name: str, - address: str, - **kwargs: Any + self, name: str, address: str, **kwargs: Unpack[VisaInstrumentKWArgs] ) -> None: - - super().__init__(name, address, terminator="\n", **kwargs) + super().__init__(name, address, **kwargs) self.add_submodule( "horizontal", @@ -146,12 +151,9 @@ class TektronixDPOData(InstrumentChannel): """ def __init__( - self, - parent: Union[Instrument, InstrumentChannel], - name: str + self, parent: InstrumentBase, name: str, **kwargs: Unpack[InstrumentBaseKWArgs] ) -> None: - - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) # We can choose to retrieve data from arbitrary # start and stop indices of the buffer. self.add_parameter( @@ -213,13 +215,13 @@ class TektronixDPOWaveform(InstrumentChannel): ] def __init__( - self, - parent: Union[Instrument, InstrumentChannel], - name: str, - identifier: str, + self, + parent: InstrumentBase, + name: str, + identifier: str, + **kwargs: Unpack[InstrumentBaseKWArgs], ) -> None: - - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) if identifier not in self.valid_identifiers: raise ValueError( @@ -376,12 +378,9 @@ class TektronixDPOWaveformFormat(InstrumentChannel): """ def __init__( - self, - parent: Union[Instrument, InstrumentChannel], - name: str + self, parent: InstrumentBase, name: str, **kwargs: Unpack[InstrumentBaseKWArgs] ) -> None: - - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.add_parameter( "data_format", @@ -430,13 +429,13 @@ class TektronixDPOChannel(InstrumentChannel): the instrument display. """ def __init__( - self, - parent: Union[Instrument, InstrumentChannel], - name: str, - channel_number: int, + self, + parent: Union[Instrument, InstrumentChannel], + name: str, + channel_number: int, + **kwargs: Unpack[InstrumentBaseKWArgs], ) -> None: - - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self._identifier = f"CH{channel_number}" self.add_submodule( @@ -526,12 +525,12 @@ class TektronixDPOHorizontal(InstrumentChannel): """ def __init__( - self, - parent: Union[Instrument, InstrumentChannel], - name: str + self, + parent: Union[Instrument, InstrumentChannel], + name: str, + **kwargs: Unpack[InstrumentBaseKWArgs], ) -> None: - - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self.add_parameter( "mode", @@ -643,12 +642,13 @@ class TektronixDPOTrigger(InstrumentChannel): https://download.tek.com/manual/MSO70000C-DX-DPO70000C-DX-MSO-DPO7000C-MSO-DPO5000B-Oscilloscope-Quick-Start-User-Manual-071298006.pdf """ def __init__( - self, - parent: Instrument, - name: str, - delayed_trigger: bool = False + self, + parent: Instrument, + name: str, + delayed_trigger: bool = False, + **kwargs: Unpack[InstrumentBaseKWArgs], ): - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self._identifier = "B" if delayed_trigger else "A" trigger_types = ["edge", "logic", "pulse"] @@ -834,13 +834,13 @@ class TektronixDPOMeasurement(InstrumentChannel): ] def __init__( - self, - parent: Instrument, - name: str, - measurement_number: int + self, + parent: Instrument, + name: str, + measurement_number: int, + **kwargs: Unpack[InstrumentBaseKWArgs], ) -> None: - - super().__init__(parent, name) + super().__init__(parent, name, **kwargs) self._measurement_number = measurement_number self._adjustment_time = time.perf_counter() @@ -909,8 +909,10 @@ def wait_adjustment_time(self) -> None: class TektronixDPOMeasurementStatistics(InstrumentChannel): - def __init__(self, *args: Any, **kwargs: Any): - super().__init__(*args, **kwargs) + def __init__( + self, parent: InstrumentBase, name: str, **kwargs: Unpack[InstrumentBaseKWArgs] + ): + super().__init__(parent=parent, name=name, **kwargs) self.add_parameter( "mode", diff --git a/src/qcodes/instrument_drivers/tektronix/TPS2012.py b/src/qcodes/instrument_drivers/tektronix/TPS2012.py index be6ab92bb44..5ed2bb886eb 100644 --- a/src/qcodes/instrument_drivers/tektronix/TPS2012.py +++ b/src/qcodes/instrument_drivers/tektronix/TPS2012.py @@ -5,10 +5,16 @@ import numpy as np from pyvisa.errors import VisaIOError -from typing_extensions import TypedDict +from typing_extensions import TypedDict, Unpack from qcodes import validators as vals -from qcodes.instrument import ChannelList, InstrumentChannel, VisaInstrument +from qcodes.instrument import ( + ChannelList, + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import ArrayParameter, ParamRawDataType log = logging.getLogger(__name__) @@ -213,7 +219,11 @@ def _curveparameterparser( class TektronixTPS2012Channel(InstrumentChannel): def __init__( - self, parent: "TektronixTPS2012", name: str, channel: int, **kwargs: Any + self, + parent: "TektronixTPS2012", + name: str, + channel: int, + **kwargs: Unpack[InstrumentBaseKWArgs], ): super().__init__(parent, name, **kwargs) @@ -263,20 +273,24 @@ class TektronixTPS2012(VisaInstrument): This is the QCoDeS driver for the Tektronix 2012B oscilloscope. """ - def __init__(self, name: str, address: str, - timeout: float = 20, **kwargs: Any): + default_timeout = 20 + + def __init__( + self, + name: str, + address: str, + **kwargs: Unpack[VisaInstrumentKWArgs], + ): """ Initialises the TPS2012. Args: name: Name of the instrument used by QCoDeS address: Instrument address as used by VISA - timeout: visa timeout, in secs. long default (180) - to accommodate large waveforms **kwargs: kwargs are forwarded to base class. """ - super().__init__(name, address, timeout=timeout, **kwargs) + super().__init__(name, address, **kwargs) self.connect_message() # Scope trace boolean diff --git a/src/qcodes/instrument_drivers/tektronix/Tektronix_70001A.py b/src/qcodes/instrument_drivers/tektronix/Tektronix_70001A.py index 44f38d153ff..404d02110c3 100644 --- a/src/qcodes/instrument_drivers/tektronix/Tektronix_70001A.py +++ b/src/qcodes/instrument_drivers/tektronix/Tektronix_70001A.py @@ -1,7 +1,12 @@ -from typing import Any +from typing import TYPE_CHECKING from .AWG70000A import AWG70000A +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import VisaInstrumentKWArgs + class TektronixAWG70001A(AWG70000A): """ @@ -10,15 +15,19 @@ class TektronixAWG70001A(AWG70000A): All the actual driver meat is in the superclass AWG70000A. """ + default_timeout = 10 + def __init__( - self, name: str, address: str, timeout: float = 10, **kwargs: Any + self, + name: str, + address: str, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ) -> None: """ Args: name: The name used internally by QCoDeS in the DataSet address: The VISA resource name of the instrument - timeout: The VISA timeout time (in seconds). **kwargs: kwargs are forwarded to base class. """ - super().__init__(name, address, num_channels=2, timeout=timeout, **kwargs) + super().__init__(name, address, num_channels=2, **kwargs) diff --git a/src/qcodes/instrument_drivers/tektronix/Tektronix_70001B.py b/src/qcodes/instrument_drivers/tektronix/Tektronix_70001B.py index 8522da80ac8..e7358c24e77 100644 --- a/src/qcodes/instrument_drivers/tektronix/Tektronix_70001B.py +++ b/src/qcodes/instrument_drivers/tektronix/Tektronix_70001B.py @@ -1,7 +1,12 @@ -from typing import Any +from typing import TYPE_CHECKING from .AWG70000A import AWG70000A +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import VisaInstrumentKWArgs + class TektronixAWG70001B(AWG70000A): """ @@ -10,15 +15,19 @@ class TektronixAWG70001B(AWG70000A): All the actual driver meat is in the superclass AWG70000A. """ + default_timeout = 10 + def __init__( - self, name: str, address: str, timeout: float = 10, **kwargs: Any + self, + name: str, + address: str, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ) -> None: """ Args: name: The name used internally by QCoDeS in the DataSet address: The VISA resource name of the instrument - timeout: The VISA timeout time (in seconds). **kwargs: kwargs are forwarded to base class. """ - super().__init__(name, address, num_channels=2, timeout=timeout, **kwargs) + super().__init__(name, address, num_channels=2, **kwargs) diff --git a/src/qcodes/instrument_drivers/tektronix/Tektronix_70002B.py b/src/qcodes/instrument_drivers/tektronix/Tektronix_70002B.py index 4e85795ddcd..fa6b9b5601d 100644 --- a/src/qcodes/instrument_drivers/tektronix/Tektronix_70002B.py +++ b/src/qcodes/instrument_drivers/tektronix/Tektronix_70002B.py @@ -1,7 +1,12 @@ -from typing import Any +from typing import TYPE_CHECKING from .AWG70000A import AWG70000A +if TYPE_CHECKING: + from typing_extensions import Unpack + + from qcodes.instrument import VisaInstrumentKWArgs + class TektronixAWG70002B(AWG70000A): """ @@ -10,15 +15,19 @@ class TektronixAWG70002B(AWG70000A): All the actual driver meat is in the superclass AWG70000A. """ + default_timeout = 10 + def __init__( - self, name: str, address: str, timeout: float = 10, **kwargs: Any + self, + name: str, + address: str, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ) -> None: """ Args: name: The name used internally by QCoDeS in the DataSet address: The VISA resource name of the instrument - timeout: The VISA timeout time (in seconds). **kwargs: kwargs are forwarded to base class. """ - super().__init__(name, address, num_channels=2, timeout=timeout, **kwargs) + super().__init__(name, address, num_channels=2, **kwargs) From ec59423c266d3f3f441a45ed069c6119533ac499 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 18 May 2024 08:55:50 +0200 Subject: [PATCH 11/12] Add types to remaining drivers --- .../weinschel/Weinschel_8320.py | 15 +++++-- .../instrument_drivers/yokogawa/GS200.py | 43 ++++++++++++++----- .../yokogawa/Yokogawa_GS200.py | 20 +++++++-- 3 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/qcodes/instrument_drivers/weinschel/Weinschel_8320.py b/src/qcodes/instrument_drivers/weinschel/Weinschel_8320.py index 4cb7a67bf38..3ff968798b9 100644 --- a/src/qcodes/instrument_drivers/weinschel/Weinschel_8320.py +++ b/src/qcodes/instrument_drivers/weinschel/Weinschel_8320.py @@ -1,11 +1,14 @@ -from typing import Any +from typing import TYPE_CHECKING import numpy as np from qcodes import validators as vals -from qcodes.instrument import VisaInstrument +from qcodes.instrument import VisaInstrument, VisaInstrumentKWArgs from qcodes.parameters import Parameter +if TYPE_CHECKING: + from typing_extensions import Unpack + class Weinschel8320(VisaInstrument): """ @@ -14,8 +17,12 @@ class Weinschel8320(VisaInstrument): Weinschel is formerly known as Aeroflex/Weinschel """ - def __init__(self, name: str, address: str, **kwargs: Any): - super().__init__(name, address, terminator='\r', **kwargs) + default_terminator = "\r" + + def __init__( + self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" + ): + super().__init__(name, address, **kwargs) self.attenuation = Parameter( "attenuation", unit="dB", diff --git a/src/qcodes/instrument_drivers/yokogawa/GS200.py b/src/qcodes/instrument_drivers/yokogawa/GS200.py index d29d1e8456a..700b104c704 100644 --- a/src/qcodes/instrument_drivers/yokogawa/GS200.py +++ b/src/qcodes/instrument_drivers/yokogawa/GS200.py @@ -4,12 +4,20 @@ """ from functools import partial -from typing import Any, Literal, Optional, Union - -from qcodes.instrument import InstrumentChannel, VisaInstrument +from typing import TYPE_CHECKING, Literal, Optional, Union + +from qcodes.instrument import ( + InstrumentBaseKWArgs, + InstrumentChannel, + VisaInstrument, + VisaInstrumentKWArgs, +) from qcodes.parameters import DelegateParameter from qcodes.validators import Bool, Enum, Ints, Numbers +if TYPE_CHECKING: + from typing_extensions import Unpack + ModeType = Literal["CURR", "VOLT"] @@ -46,8 +54,14 @@ class GS200_Monitor(InstrumentChannel): present """ - def __init__(self, parent: "GS200", name: str, present: bool) -> None: - super().__init__(parent, name) + def __init__( + self, + parent: "GS200", + name: str, + present: bool, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ) -> None: + super().__init__(parent, name, **kwargs) self.present = present @@ -186,8 +200,13 @@ def update_measurement_enabled(self, unit: ModeType, output_range: float) -> Non class GS200Program(InstrumentChannel): """ """ - def __init__(self, parent: "GS200", name: str) -> None: - super().__init__(parent, name) + def __init__( + self, + parent: "GS200", + name: str, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ) -> None: + super().__init__(parent, name, **kwargs) self._repeat = 1 self._file_name = None @@ -266,13 +285,17 @@ class GS200(VisaInstrument): name: What this instrument is called locally. address: The GPIB or USB address of this instrument kwargs: kwargs to be passed to VisaInstrument class - terminator: read terminator for reads/writes to the instrument. """ + default_terminator = "\n" + def __init__( - self, name: str, address: str, terminator: str = "\n", **kwargs: Any + self, + name: str, + address: str, + **kwargs: "Unpack[VisaInstrumentKWArgs]", ) -> None: - super().__init__(name, address, terminator=terminator, **kwargs) + super().__init__(name, address, **kwargs) self.add_parameter( "output", diff --git a/src/qcodes/instrument_drivers/yokogawa/Yokogawa_GS200.py b/src/qcodes/instrument_drivers/yokogawa/Yokogawa_GS200.py index 7414025e732..25c82af47c1 100644 --- a/src/qcodes/instrument_drivers/yokogawa/Yokogawa_GS200.py +++ b/src/qcodes/instrument_drivers/yokogawa/Yokogawa_GS200.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Literal, Optional, Union from qcodes.instrument import ( + InstrumentBaseKWArgs, InstrumentChannel, VisaInstrument, VisaInstrumentKWArgs, @@ -48,8 +49,14 @@ class YokogawaGS200Monitor(InstrumentChannel): present """ - def __init__(self, parent: "YokogawaGS200", name: str, present: bool) -> None: - super().__init__(parent, name) + def __init__( + self, + parent: "YokogawaGS200", + name: str, + present: bool, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ) -> None: + super().__init__(parent, name, **kwargs) self.present = present @@ -188,8 +195,13 @@ def update_measurement_enabled(self, unit: ModeType, output_range: float) -> Non class YokogawaGS200Program(InstrumentChannel): """ """ - def __init__(self, parent: "YokogawaGS200", name: str) -> None: - super().__init__(parent, name) + def __init__( + self, + parent: "YokogawaGS200", + name: str, + **kwargs: "Unpack[InstrumentBaseKWArgs]", + ) -> None: + super().__init__(parent, name, **kwargs) self._repeat = 1 self._file_name = None From bf209bd2c00e3c76913a961259e17bada70523d9 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 19 May 2024 11:01:04 +0200 Subject: [PATCH 12/12] Add changelog --- docs/changes/newsfragments/6012.breaking | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changes/newsfragments/6012.breaking b/docs/changes/newsfragments/6012.breaking index 8db0bb5fa7c..ea0daea023f 100644 --- a/docs/changes/newsfragments/6012.breaking +++ b/docs/changes/newsfragments/6012.breaking @@ -6,5 +6,5 @@ This also means that the these arguments **must** be passed as keyword arguments This specifically includeds passing ``label`` and ``metadata`` to direct subclasses of ``Instrument`` as well as ``terminator`` to subclasses of ``VisaInstrument``. -All drivers shipping with qcodes for Vendors from A-K have been updated. -The remaining drivers will be updated in a subsequent pull request. +All drivers shipping with qcodes for Vendors from A-K have been updated in this pr. +The remaining drivers were updated in (:pr:`6087`).