From 2f339ffff233e14562495d55d1ec9a8fe9bf205a Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 30 Mar 2025 11:14:30 +0200 Subject: [PATCH 1/7] Make add_submodule return the submodule --- src/qcodes/instrument/instrument_base.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/qcodes/instrument/instrument_base.py b/src/qcodes/instrument/instrument_base.py index 3be971481bb8..9b28e5093da1 100644 --- a/src/qcodes/instrument/instrument_base.py +++ b/src/qcodes/instrument/instrument_base.py @@ -27,7 +27,10 @@ log = logging.getLogger(__name__) -TParameter = TypeVar("TParameter", bound=ParameterBase, default=Parameter) +TParameter = TypeVar("TParameter", bound="ParameterBase", default="Parameter") +TSubmodule = TypeVar( + "TSubmodule", bound="InstrumentModule | ChannelTuple", default="InstrumentModule" +) class InstrumentBaseKWArgs(TypedDict): @@ -158,6 +161,9 @@ def add_parameter( unit of the new parameter is inconsistent with the existing one. + Returns: + The created Parameter. + """ if parameter_class is None: parameter_class = cast("type[TParameter]", Parameter) @@ -262,9 +268,7 @@ def add_function(self, name: str, **kwargs: Any) -> None: func = Function(name=name, instrument=self, **kwargs) self.functions[name] = func - def add_submodule( - self, name: str, submodule: InstrumentModule | ChannelTuple - ) -> None: + def add_submodule(self, name: str, submodule: TSubmodule) -> TSubmodule: """ Bind one submodule to this instrument. @@ -290,6 +294,9 @@ def add_submodule( TypeError: If the submodule that we are trying to add is not an instance of an ``Metadatable`` object. + Returns: + The submodule. + """ if name in self.submodules: raise KeyError(f"Duplicate submodule name {name}") @@ -304,6 +311,7 @@ def add_submodule( self._channel_lists[name] = submodule else: self.instrument_modules[name] = submodule + return submodule def get_component(self, full_name: str) -> MetadatableWithName: """ From ada2e31c9b9cd103c1866e7b95e1f03b458e0340 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 30 Mar 2025 11:41:50 +0200 Subject: [PATCH 2/7] Manually add submodule to Galil driver --- .../instrument_drivers/Galil/dmc_41x3.py | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/qcodes/instrument_drivers/Galil/dmc_41x3.py b/src/qcodes/instrument_drivers/Galil/dmc_41x3.py index 42a4eca1a671..28b09567e064 100644 --- a/src/qcodes/instrument_drivers/Galil/dmc_41x3.py +++ b/src/qcodes/instrument_drivers/Galil/dmc_41x3.py @@ -526,12 +526,30 @@ def __init__( """controller will wait for the amount of time specified before executing the next command""" self._set_default_update_time() - self.add_submodule("motor_a", GalilDMC4133Motor(self, "A")) - self.add_submodule("motor_b", GalilDMC4133Motor(self, "B")) - self.add_submodule("motor_c", GalilDMC4133Motor(self, "C")) - self.add_submodule("plane_ab", GalilDMC4133VectorMode(self, "AB")) - self.add_submodule("plane_bc", GalilDMC4133VectorMode(self, "BC")) - self.add_submodule("plane_ac", GalilDMC4133VectorMode(self, "AC")) + self.motor_a: GalilDMC4133Motor = self.add_submodule( + "motor_a", GalilDMC4133Motor(self, "A") + ) + """Submodule motor_a""" + self.motor_b: GalilDMC4133Motor = self.add_submodule( + "motor_b", GalilDMC4133Motor(self, "B") + ) + """Submodule motor_b""" + self.motor_c: GalilDMC4133Motor = self.add_submodule( + "motor_c", GalilDMC4133Motor(self, "C") + ) + """Submodule motor_c""" + self.plane_ab: GalilDMC4133VectorMode = self.add_submodule( + "plane_ab", GalilDMC4133VectorMode(self, "AB") + ) + """Submodule plane_ab""" + self.plane_bc: GalilDMC4133VectorMode = self.add_submodule( + "plane_bc", GalilDMC4133VectorMode(self, "BC") + ) + """Submodule plane_bc""" + self.plane_ac: GalilDMC4133VectorMode = self.add_submodule( + "plane_ac", GalilDMC4133VectorMode(self, "AC") + ) + """Submodule plane_ac""" def _set_default_update_time(self) -> None: """ @@ -643,7 +661,8 @@ def __init__(self, controller: GalilDMC4133Controller) -> None: controller: an instance of DMC4133Controller """ - self.controller = controller + self.controller: GalilDMC4133Controller = controller + """The controller attached to the arm.""" # initialization (all these points will have values in quadrature # counts) From b851063d3b2515aedc17a6840385ff7632c715bf Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 30 Mar 2025 12:09:40 +0200 Subject: [PATCH 3/7] Add GalilMotionController to public api --- src/qcodes/instrument_drivers/Galil/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qcodes/instrument_drivers/Galil/__init__.py b/src/qcodes/instrument_drivers/Galil/__init__.py index 270096df9b30..1b13cbb37137 100644 --- a/src/qcodes/instrument_drivers/Galil/__init__.py +++ b/src/qcodes/instrument_drivers/Galil/__init__.py @@ -3,6 +3,7 @@ GalilDMC4133Controller, GalilDMC4133Motor, GalilDMC4133VectorMode, + GalilMotionController, ) __all__ = [ @@ -10,4 +11,5 @@ "GalilDMC4133Controller", "GalilDMC4133Motor", "GalilDMC4133VectorMode", + "GalilMotionController", ] From 4a23f7c32dabd8de50186b6c0e667d5f04d63820 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Mon, 31 Mar 2025 08:38:59 +0200 Subject: [PATCH 4/7] Ignore mypy error --- src/qcodes/instrument/instrument_base.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qcodes/instrument/instrument_base.py b/src/qcodes/instrument/instrument_base.py index 9b28e5093da1..847b947094e6 100644 --- a/src/qcodes/instrument/instrument_base.py +++ b/src/qcodes/instrument/instrument_base.py @@ -308,7 +308,9 @@ def add_submodule(self, name: str, submodule: TSubmodule) -> TSubmodule: # this is channel_list like: # We cannot check against ChannelsList itself since that # would introduce a circular dependency. - self._channel_lists[name] = submodule + # ignore since mypy's type narrowing is not smart enough to understand + # that a TSubmodule that is s Sequence must be a ChannelTuple + self._channel_lists[name] = submodule # type: ignore[assignment] else: self.instrument_modules[name] = submodule return submodule From 829c4758cd27763f75f157455923780f9bc92535 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 12 Oct 2024 15:00:53 +0200 Subject: [PATCH 5/7] Use add_submodule in AMI430 --- .../instrument_drivers/american_magnetics/AMI430_visa.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qcodes/instrument_drivers/american_magnetics/AMI430_visa.py b/src/qcodes/instrument_drivers/american_magnetics/AMI430_visa.py index 10cd23a47dfb..8c835dc9d64a 100644 --- a/src/qcodes/instrument_drivers/american_magnetics/AMI430_visa.py +++ b/src/qcodes/instrument_drivers/american_magnetics/AMI430_visa.py @@ -399,7 +399,10 @@ def __init__( # Add persistent switch switch_heater = AMI430SwitchHeater(self) - self.add_submodule("switch_heater", switch_heater) + self.switch_heater: AMI430SwitchHeater = self.add_submodule( + "switch_heater", switch_heater + ) + """Submodule the switch heater submodule.""" # Add interaction functions self.add_function("get_error", call_cmd="SYST:ERR?") From 780a64947be7f6830a4e07c6ba2656893e4c3b84 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Wed, 9 Apr 2025 17:00:27 +0200 Subject: [PATCH 6/7] Update writing driver example --- .../Creating-Instrument-Drivers.ipynb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/examples/writing_drivers/Creating-Instrument-Drivers.ipynb b/docs/examples/writing_drivers/Creating-Instrument-Drivers.ipynb index e9d98218ad48..ed0e65d11955 100644 --- a/docs/examples/writing_drivers/Creating-Instrument-Drivers.ipynb +++ b/docs/examples/writing_drivers/Creating-Instrument-Drivers.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -202,7 +202,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -279,7 +279,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -406,10 +406,10 @@ " raise ValueError(\"Unknown model. Known model are: \" + kmstring)\n", "\n", " # Add the channel to the instrument\n", - " for ch in [\"a\", \"b\"]:\n", - " ch_name = f\"smu{ch}\"\n", - " channel = KeithleyChannel(self, ch_name, ch_name)\n", - " self.add_submodule(ch_name, channel)\n", + " self.smua = self.add_submodule(\"smua\", KeithleyChannel(self, \"smua\", \"smua\"))\n", + " \"smua channel of the instrument\"\n", + " self.smub = self.add_submodule(\"smub\", KeithleyChannel(self, \"smub\", \"smub\"))\n", + " \"smub channel of the instrument\"\n", "\n", " # display parameter\n", " # Parameters NOT specific to a channel still belong on the Instrument object\n", @@ -537,7 +537,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -846,7 +846,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -860,7 +860,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.13.2" }, "toc": { "base_numbering": 1, From 27fecde150f6614f88582a19fa376622ec401246 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Wed, 9 Apr 2025 17:57:45 +0200 Subject: [PATCH 7/7] Add changelog for 7017 --- docs/changes/newsfragments/7017.new | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/changes/newsfragments/7017.new diff --git a/docs/changes/newsfragments/7017.new b/docs/changes/newsfragments/7017.new new file mode 100644 index 000000000000..b8df52880acf --- /dev/null +++ b/docs/changes/newsfragments/7017.new @@ -0,0 +1,5 @@ +``InstrumentBase.add_submodule`` now returns the added submodule. This similar to changes made in ``add_parameter`` earlier. +This makes it possible to assign this to an attribute which enables static code checkers, IDEs and documentation to +discover submodules. The ``Galil`` drivers have been updated to make use of this. Consult the ``Galil`` driver or ``Creating-Instrument-Drivers`` +notebook for examples of how to use this. It is planed that QCoDeS in the future will ship with a tool to automatically perform this refactor +and updates to all included drivers.