Skip to content

Commit 69ebb2e

Browse files
authored
Merge pull request #7919 from jenshnielsen/driver_improvments
Avoid dynamic attribute lookup in several drivers
2 parents 0a3b7aa + ecb5273 commit 69ebb2e

8 files changed

Lines changed: 101 additions & 61 deletions

File tree

src/qcodes/instrument_drivers/Galil/dmc_41x3.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ def clear_sequence(self, coord_sys: str) -> None:
254254
"""
255255

256256

257-
class GalilDMC4133Motor(InstrumentChannel):
257+
class GalilDMC4133Motor(InstrumentChannel["GalilDMC4133Controller"]):
258258
"""
259259
Class to control a single motor (independent of possible other motors)
260260
"""
@@ -458,7 +458,7 @@ def wait_till_motor_motion_complete(self) -> None:
458458
while self.is_in_motion():
459459
pass
460460
except KeyboardInterrupt:
461-
self.root_instrument.abort()
461+
self.parent.abort()
462462
self.off()
463463

464464
def error_magnitude(self) -> float:

src/qcodes/instrument_drivers/Keithley/Keithley_s46.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from typing import TYPE_CHECKING, Any, ClassVar
88

99
from qcodes.instrument import (
10-
Instrument,
1110
VisaInstrument,
1211
VisaInstrumentKWArgs,
1312
)
@@ -56,7 +55,7 @@ def release(self, channel_number: int) -> None:
5655
self._locked_by = None
5756

5857

59-
class S46Parameter(Parameter):
58+
class S46Parameter(Parameter[ParamRawDataType, "KeithleyS46"]):
6059
"""
6160
A parameter class for S46 channels. We do not use the QCoDeS
6261
InstrumentChannel class because our channel has one state parameter,
@@ -73,7 +72,7 @@ class S46Parameter(Parameter):
7372
def __init__(
7473
self,
7574
name: str,
76-
instrument: Instrument | None,
75+
instrument: "KeithleyS46",
7776
channel_number: int,
7877
lock: KeithleyS46RelayLock,
7978
**kwargs: Any,
@@ -95,7 +94,6 @@ def __init__(
9594
) from e
9695

9796
def _get(self, get_cached: bool) -> str:
98-
assert isinstance(self.instrument, KeithleyS46)
9997
closed_channels = self.instrument.closed_channels.get_latest()
10098

10199
if not get_cached or closed_channels is None:

src/qcodes/instrument_drivers/QDev/QDac_channels.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from qcodes import validators as vals
1212
from qcodes.instrument import (
1313
ChannelList,
14-
Instrument,
14+
ChannelTuple,
1515
InstrumentBaseKWArgs,
1616
InstrumentChannel,
1717
VisaInstrument,
@@ -29,7 +29,7 @@
2929
log = logging.getLogger(__name__)
3030

3131

32-
class QDevQDacChannel(InstrumentChannel):
32+
class QDevQDacChannel(InstrumentChannel["QDevQDac"]):
3333
"""
3434
A single output channel of the QDac.
3535
@@ -40,7 +40,7 @@ class QDevQDacChannel(InstrumentChannel):
4040

4141
def __init__(
4242
self,
43-
parent: Instrument,
43+
parent: "QDevQDac",
4444
name: str,
4545
channum: int,
4646
**kwargs: "Unpack[InstrumentBaseKWArgs]",
@@ -143,9 +143,20 @@ def snapshot_base(
143143
update: bool | None = False,
144144
params_to_skip_update: "Sequence[str] | None" = None,
145145
) -> dict[Any, Any]:
146-
update_currents = self._parent._update_currents and update
147-
if update and not self._parent._get_status_performed:
148-
self._parent._update_cache(readcurrents=update_currents)
146+
# setting update not None will override parent setting
147+
# otherwise we use parent setting
148+
# parent._update | update | do update
149+
# True | True | True
150+
# True | None | True
151+
# True | False | False
152+
# False | True | True
153+
# False | None | False
154+
# False | False | False
155+
update_currents = (
156+
self.parent._update_currents and update is not False
157+
) or update is True
158+
if update and not self.parent._get_status_performed:
159+
self.parent._update_cache(readcurrents=update_currents)
149160
# call get_status rather than getting the status individually for
150161
# each parameter. This is only done if _get_status_performed is False
151162
# this is used to signal that the parent has already called it and
@@ -287,7 +298,10 @@ def __init__(
287298
channels.append(channel)
288299
# Should raise valueerror if name is invalid (silently fails now)
289300
self.add_submodule(f"ch{i:02}", channel)
290-
self.add_submodule("channels", channels.to_channel_tuple())
301+
self.channels: ChannelTuple[QDevQDacChannel] = self.add_submodule(
302+
"channels", channels.to_channel_tuple()
303+
)
304+
"""ChannelTuple containing all QDevQDacChannel instances"""
291305

292306
for board in range(6):
293307
for sensor in range(3):

src/qcodes/instrument_drivers/oxford/MercuryiPS_VISA.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,14 @@ def _temp_parser(response: str) -> float:
7676
return float(response.rsplit(":", maxsplit=1)[-1][:-1])
7777

7878

79-
class OxfordMercuryWorkerPS(InstrumentChannel):
79+
class OxfordMercuryWorkerPS(InstrumentChannel["OxfordMercuryiPS"]):
8080
"""
8181
Class to hold a worker power supply for the Oxford MercuryiPS
8282
"""
8383

8484
def __init__(
8585
self,
86-
parent: VisaInstrument,
86+
parent: OxfordMercuryiPS,
8787
name: str,
8888
UID: str,
8989
**kwargs: Unpack[InstrumentBaseKWArgs],
@@ -108,7 +108,7 @@ def __init__(
108108

109109
# The firmware update from 2.5 -> 2.6 changed the command
110110
# syntax slightly
111-
if version.parse(self.root_instrument.firmware) >= version.parse("2.6"):
111+
if version.parse(self.parent.firmware) >= version.parse("2.6"):
112112
self.psu_string = "SPSU"
113113
else:
114114
self.psu_string = "PSU"
@@ -348,10 +348,14 @@ def __init__(
348348
self.firmware = self.IDN()["firmware"]
349349

350350
# TODO: Query instrument to ensure which PSUs are actually present
351-
for grp in ["GRPX", "GRPY", "GRPZ"]:
352-
psu_name = grp
353-
psu = OxfordMercuryWorkerPS(self, psu_name, grp)
354-
self.add_submodule(psu_name, psu)
351+
GRPX = OxfordMercuryWorkerPS(self, "GRPX", "GRPX")
352+
self.GRPX: OxfordMercuryWorkerPS = self.add_submodule("GRPX", GRPX)
353+
354+
GRPY = OxfordMercuryWorkerPS(self, "GRPY", "GRPY")
355+
self.GRPY: OxfordMercuryWorkerPS = self.add_submodule("GRPY", GRPY)
356+
357+
GRPZ = OxfordMercuryWorkerPS(self, "GRPZ", "GRPZ")
358+
self.GRPZ: OxfordMercuryWorkerPS = self.add_submodule("GRPZ", GRPZ)
355359

356360
self._field_limits = field_limits if field_limits else lambda x, y, z: True
357361

src/qcodes/instrument_drivers/stanford_research/SR86x.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def get_raw(self) -> npt.NDArray:
8989
return self._capture_data
9090

9191

92-
class SR86xBuffer(InstrumentChannel):
92+
class SR86xBuffer(InstrumentChannel["SR86x"]):
9393
"""
9494
Buffer module for the SR86x drivers.
9595
@@ -529,7 +529,7 @@ def _get_raw_capture_data_block(
529529
f"({size_of_currently_captured_data}kB)"
530530
)
531531

532-
values = self._parent.visa_handle.query_binary_values(
532+
values = self.parent.visa_handle.query_binary_values(
533533
f"CAPTUREGET? {offset_in_kb}, {size_in_kb}",
534534
datatype="f",
535535
is_big_endian=False,
@@ -621,7 +621,7 @@ def capture_samples(self, sample_count: int) -> dict[str, npt.NDArray]:
621621
return self.get_capture_data(sample_count)
622622

623623

624-
class SR86xDataChannel(InstrumentChannel):
624+
class SR86xDataChannel(InstrumentChannel["SR86x"]):
625625
"""
626626
Implements a data channel of SR86x lock-in amplifier. Parameters that are
627627
assigned to these channels get plotted on the display of the instrument.

src/qcodes/instrument_drivers/tektronix/AWG70000A.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
from qcodes import validators as vals
1818
from qcodes.instrument import (
1919
ChannelList,
20-
Instrument,
2120
InstrumentBaseKWArgs,
2221
InstrumentChannel,
2322
VisaInstrument,
@@ -157,14 +156,14 @@ def validate(self, value: float, context: str = "") -> None:
157156
validator.validate(value)
158157

159158

160-
class Tektronix70000AWGChannel(InstrumentChannel):
159+
class Tektronix70000AWGChannel(InstrumentChannel["TektronixAWG70000Base"]):
161160
"""
162161
Class to hold a channel of the AWG.
163162
"""
164163

165164
def __init__(
166165
self,
167-
parent: Instrument,
166+
parent: TektronixAWG70000Base,
168167
name: str,
169168
channel: int,
170169
**kwargs: Unpack[InstrumentBaseKWArgs],
@@ -183,8 +182,8 @@ def __init__(
183182

184183
self.channel = channel
185184

186-
num_channels = self.root_instrument.num_channels
187-
self.model = self.root_instrument.model
185+
num_channels = self.parent.num_channels
186+
self.model = self.parent.model
188187

189188
fg = "function generator"
190189

@@ -264,7 +263,7 @@ def __init__(
264263
label=f"Channel {channel} {fg} signal path",
265264
set_cmd=f"FGEN:CHANnel{channel}:PATH {{}}",
266265
get_cmd=f"FGEN:CHANnel{channel}:PATH?",
267-
val_mapping=_fg_path_val_map[self.root_instrument.model],
266+
val_mapping=_fg_path_val_map[self.parent.model],
268267
)
269268
"""Parameter fgen_signalpath"""
270269

@@ -441,7 +440,7 @@ def _set_fgfreq(self, channel: int, frequency: float) -> None:
441440
"Hz, minimum is 1 Hz"
442441
)
443442
else:
444-
self.root_instrument.write(f"FGEN:CHANnel{channel}:FREQuency {frequency}")
443+
self.parent.write(f"FGEN:CHANnel{channel}:FREQuency {frequency}")
445444

446445
def setWaveform(self, name: str) -> None:
447446
"""
@@ -451,10 +450,10 @@ def setWaveform(self, name: str) -> None:
451450
name: The name of the waveform
452451
453452
"""
454-
if name not in self.root_instrument.waveformList:
453+
if name not in self.parent.waveformList:
455454
raise ValueError("No such waveform in the waveform list")
456455

457-
self.root_instrument.write(f'SOURce{self.channel}:CASSet:WAVeform "{name}"')
456+
self.parent.write(f'SOURce{self.channel}:CASSet:WAVeform "{name}"')
458457

459458
def setSequenceTrack(self, seqname: str, tracknr: int) -> None:
460459
"""
@@ -465,8 +464,7 @@ def setSequenceTrack(self, seqname: str, tracknr: int) -> None:
465464
tracknr: Which track to use (1 or 2)
466465
467466
"""
468-
469-
self.root_instrument.write(
467+
self.parent.write(
470468
f'SOURCE{self.channel}:CASSet:SEQuence "{seqname}", {tracknr}'
471469
)
472470

@@ -475,7 +473,7 @@ def clear_asset(self) -> None:
475473
Clear assigned assets on this channel
476474
"""
477475

478-
self.root_instrument.write(f"SOURce{self.channel}:CASSet:CLEAR")
476+
self.parent.write(f"SOURce{self.channel}:CASSet:CLEAR")
479477

480478

481479
AWGChannel = Tektronix70000AWGChannel

0 commit comments

Comments
 (0)