Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changes/newsfragments/7017.new
Original file line number Diff line number Diff line change
@@ -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.
20 changes: 10 additions & 10 deletions docs/examples/writing_drivers/Creating-Instrument-Drivers.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -202,7 +202,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -279,7 +279,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -537,7 +537,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -846,7 +846,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"display_name": ".venv",
"language": "python",
"name": "python3"
},
Expand All @@ -860,7 +860,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
"version": "3.13.2"
},
"toc": {
"base_numbering": 1,
Expand Down
20 changes: 15 additions & 5 deletions src/qcodes/instrument/instrument_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@

log = logging.getLogger(__name__)

TParameter = TypeVar("TParameter", bound=ParameterBase, default=Parameter)
TParameter = TypeVar("TParameter", bound="ParameterBase", default="Parameter")
TSubmodule = TypeVar(

Check warning on line 31 in src/qcodes/instrument/instrument_base.py

View check run for this annotation

Codecov / codecov/patch

src/qcodes/instrument/instrument_base.py#L30-L31

Added lines #L30 - L31 were not covered by tests
"TSubmodule", bound="InstrumentModule | ChannelTuple", default="InstrumentModule"
)


class InstrumentBaseKWArgs(TypedDict):
Expand Down Expand Up @@ -158,6 +161,9 @@
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)
Expand Down Expand Up @@ -262,9 +268,7 @@
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:

Check warning on line 271 in src/qcodes/instrument/instrument_base.py

View check run for this annotation

Codecov / codecov/patch

src/qcodes/instrument/instrument_base.py#L271

Added line #L271 was not covered by tests
"""
Bind one submodule to this instrument.

Expand All @@ -290,6 +294,9 @@
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}")
Expand All @@ -301,9 +308,12 @@
# 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

def get_component(self, full_name: str) -> MetadatableWithName:
"""
Expand Down
2 changes: 2 additions & 0 deletions src/qcodes/instrument_drivers/Galil/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
GalilDMC4133Controller,
GalilDMC4133Motor,
GalilDMC4133VectorMode,
GalilMotionController,
)

__all__ = [
"GalilDMC4133Arm",
"GalilDMC4133Controller",
"GalilDMC4133Motor",
"GalilDMC4133VectorMode",
"GalilMotionController",
]
33 changes: 26 additions & 7 deletions src/qcodes/instrument_drivers/Galil/dmc_41x3.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,12 +526,30 @@
"""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(

Check warning on line 529 in src/qcodes/instrument_drivers/Galil/dmc_41x3.py

View check run for this annotation

Codecov / codecov/patch

src/qcodes/instrument_drivers/Galil/dmc_41x3.py#L529

Added line #L529 was not covered by tests
"motor_a", GalilDMC4133Motor(self, "A")
)
"""Submodule motor_a"""
self.motor_b: GalilDMC4133Motor = self.add_submodule(

Check warning on line 533 in src/qcodes/instrument_drivers/Galil/dmc_41x3.py

View check run for this annotation

Codecov / codecov/patch

src/qcodes/instrument_drivers/Galil/dmc_41x3.py#L532-L533

Added lines #L532 - L533 were not covered by tests
"motor_b", GalilDMC4133Motor(self, "B")
)
"""Submodule motor_b"""
self.motor_c: GalilDMC4133Motor = self.add_submodule(

Check warning on line 537 in src/qcodes/instrument_drivers/Galil/dmc_41x3.py

View check run for this annotation

Codecov / codecov/patch

src/qcodes/instrument_drivers/Galil/dmc_41x3.py#L536-L537

Added lines #L536 - L537 were not covered by tests
"motor_c", GalilDMC4133Motor(self, "C")
)
"""Submodule motor_c"""
self.plane_ab: GalilDMC4133VectorMode = self.add_submodule(

Check warning on line 541 in src/qcodes/instrument_drivers/Galil/dmc_41x3.py

View check run for this annotation

Codecov / codecov/patch

src/qcodes/instrument_drivers/Galil/dmc_41x3.py#L540-L541

Added lines #L540 - L541 were not covered by tests
"plane_ab", GalilDMC4133VectorMode(self, "AB")
)
"""Submodule plane_ab"""
self.plane_bc: GalilDMC4133VectorMode = self.add_submodule(

Check warning on line 545 in src/qcodes/instrument_drivers/Galil/dmc_41x3.py

View check run for this annotation

Codecov / codecov/patch

src/qcodes/instrument_drivers/Galil/dmc_41x3.py#L544-L545

Added lines #L544 - L545 were not covered by tests
"plane_bc", GalilDMC4133VectorMode(self, "BC")
)
"""Submodule plane_bc"""
self.plane_ac: GalilDMC4133VectorMode = self.add_submodule(

Check warning on line 549 in src/qcodes/instrument_drivers/Galil/dmc_41x3.py

View check run for this annotation

Codecov / codecov/patch

src/qcodes/instrument_drivers/Galil/dmc_41x3.py#L548-L549

Added lines #L548 - L549 were not covered by tests
"plane_ac", GalilDMC4133VectorMode(self, "AC")
)
"""Submodule plane_ac"""

Check warning on line 552 in src/qcodes/instrument_drivers/Galil/dmc_41x3.py

View check run for this annotation

Codecov / codecov/patch

src/qcodes/instrument_drivers/Galil/dmc_41x3.py#L552

Added line #L552 was not covered by tests

def _set_default_update_time(self) -> None:
"""
Expand Down Expand Up @@ -643,7 +661,8 @@
controller: an instance of DMC4133Controller

"""
self.controller = controller
self.controller: GalilDMC4133Controller = controller
"""The controller attached to the arm."""

Check warning on line 665 in src/qcodes/instrument_drivers/Galil/dmc_41x3.py

View check run for this annotation

Codecov / codecov/patch

src/qcodes/instrument_drivers/Galil/dmc_41x3.py#L664-L665

Added lines #L664 - L665 were not covered by tests

# initialization (all these points will have values in quadrature
# counts)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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?")
Expand Down
Loading