Skip to content

Commit 58181a4

Browse files
committed
eprecate source as positional arg
1 parent 1b15ebd commit 58181a4

3 files changed

Lines changed: 109 additions & 30 deletions

File tree

src/qcodes/parameters/delegate_parameter.py

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
import warnings
4-
from typing import TYPE_CHECKING, Any, Generic
4+
from typing import TYPE_CHECKING, Any, ClassVar, Generic
55

66
from typing_extensions import TypeVar
77

@@ -31,6 +31,7 @@
3131
default="InstrumentBase | None",
3232
covariant=True,
3333
)
34+
_SOURCE_UNSET: Any = object()
3435

3536

3637
class DelegateParameter(
@@ -74,6 +75,11 @@ class DelegateParameter(
7475
7576
"""
7677

78+
_DEPRECATED_POSITIONAL_ARGS: ClassVar[tuple[str, ...]] = (
79+
"source",
80+
*Parameter._DEPRECATED_POSITIONAL_ARGS,
81+
)
82+
7783
class _DelegateCache(
7884
Generic[_local_ParameterDataTypeVar, _local_InstrumentTypeVar_co]
7985
):
@@ -178,20 +184,58 @@ def __call__(self) -> _local_ParameterDataTypeVar:
178184
def __init__(
179185
self,
180186
name: str,
181-
source: Parameter | None,
182187
*args: Any,
188+
source: Parameter | None = _SOURCE_UNSET,
183189
**kwargs: Any,
184190
):
185191
if args:
186-
# TODO: After QCoDeS 0.57 remove the args argument
187-
# and delete this code block.
192+
# TODO: After QCoDeS 0.57 remove the args argument and delete this code block.
193+
positional_names = DelegateParameter._DEPRECATED_POSITIONAL_ARGS
194+
if len(args) > len(positional_names):
195+
raise TypeError(
196+
f"{type(self).__name__}.__init__() takes at most "
197+
f"{len(positional_names) + 2} positional arguments "
198+
f"({len(args) + 2} given)"
199+
)
200+
201+
for i in range(len(args)):
202+
arg_name = positional_names[i]
203+
if arg_name == "source":
204+
if source is not _SOURCE_UNSET:
205+
raise TypeError(
206+
f"{type(self).__name__}.__init__() got multiple "
207+
f"values for argument '{arg_name}'"
208+
)
209+
elif arg_name in kwargs:
210+
raise TypeError(
211+
f"{type(self).__name__}.__init__() got multiple "
212+
f"values for argument '{arg_name}'"
213+
)
214+
215+
positional_arg_names = positional_names[: len(args)]
216+
names_str = ", ".join(f"'{n}'" for n in positional_arg_names)
188217
warnings.warn(
189-
"Passing extra positional arguments to "
218+
f"Passing {names_str} as positional argument(s) to "
190219
f"{type(self).__name__} is deprecated. "
191220
"Please pass them as keyword arguments.",
192221
QCoDeSDeprecationWarning,
193222
stacklevel=2,
194223
)
224+
225+
positional_values = dict(zip(positional_names, args))
226+
if "source" in positional_values:
227+
source = positional_values["source"]
228+
229+
for arg_name in positional_names[1:]:
230+
if arg_name in positional_values:
231+
kwargs[arg_name] = positional_values[arg_name]
232+
233+
if source is _SOURCE_UNSET:
234+
raise TypeError(
235+
f"{type(self).__name__}.__init__() missing required keyword "
236+
"argument: 'source'"
237+
)
238+
195239
if "bind_to_instrument" not in kwargs.keys():
196240
kwargs["bind_to_instrument"] = False
197241

@@ -213,7 +257,7 @@ def __init__(
213257

214258
initial_cache_value = kwargs.pop("initial_cache_value", None)
215259
self.source = source
216-
super().__init__(name, *args, **kwargs)
260+
super().__init__(name, **kwargs)
217261
self.label = kwargs.get("label", None)
218262
self.unit = kwargs.get("unit", None)
219263

tests/parameter/test_args_deprecated.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,18 +127,49 @@ def test_too_many_positional_args_raises(self) -> None:
127127

128128

129129
class TestDelegateParameterPositionalArgs:
130-
"""DelegateParameter should warn when extra positional args are passed."""
130+
"""DelegateParameter should warn when arguments after ``name`` are positional."""
131131

132-
def test_positional_args_warn(self) -> None:
132+
def test_single_positional_arg_warns(self) -> None:
133+
source = Parameter("source", set_cmd=None)
134+
with pytest.warns(
135+
QCoDeSDeprecationWarning,
136+
match="Passing 'source' as positional argument",
137+
):
138+
DelegateParameter("test", source)
139+
140+
def test_multiple_positional_args_warn(self) -> None:
133141
source = Parameter("source", set_cmd=None)
134-
with pytest.warns(QCoDeSDeprecationWarning):
142+
with pytest.warns(
143+
QCoDeSDeprecationWarning,
144+
match="'source', 'instrument'",
145+
):
135146
DelegateParameter("test", source, None)
136147

137148
def test_keyword_args_do_not_warn(self) -> None:
138149
source = Parameter("source", set_cmd=None)
139-
p = DelegateParameter("test", source, instrument=None)
150+
p = DelegateParameter("test", source=source, instrument=None)
140151
assert p.name == "test"
141152

153+
def test_duplicate_positional_and_keyword_raises(self) -> None:
154+
source = Parameter("source", set_cmd=None)
155+
with pytest.raises(
156+
TypeError,
157+
match="got multiple values for argument 'source'",
158+
):
159+
DelegateParameter("test", source, source=source)
160+
161+
def test_too_many_positional_args_raises(self) -> None:
162+
too_many = (None,) * 20
163+
with pytest.raises(TypeError, match="takes at most"):
164+
DelegateParameter("test", *too_many)
165+
166+
def test_missing_source_raises(self) -> None:
167+
with pytest.raises(
168+
TypeError,
169+
match="missing required keyword argument: 'source'",
170+
):
171+
DelegateParameter("test")
172+
142173

143174
# Minimal concrete subclass of ArrayParameter for testing
144175
class _ConcreteArrayParameter(ArrayParameter):

tests/parameter/test_delegate_parameter.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def test_observable_parameter_initial_value(
104104

105105

106106
def test_same_value(simple_param: Parameter) -> None:
107-
d = DelegateParameter("test_delegate_parameter", simple_param)
107+
d = DelegateParameter("test_delegate_parameter", source=simple_param)
108108
assert d() == simple_param()
109109

110110

@@ -113,21 +113,21 @@ def test_same_label_and_unit_on_init(simple_param: Parameter) -> None:
113113
Test that the label and unit get used from source parameter if not
114114
specified otherwise.
115115
"""
116-
d = DelegateParameter("test_delegate_parameter", simple_param)
116+
d = DelegateParameter("test_delegate_parameter", source=simple_param)
117117
assert d.label == simple_param.label
118118
assert d.unit == simple_param.unit
119119

120120

121121
def test_overwritten_unit_on_init(simple_param: Parameter) -> None:
122-
d = DelegateParameter("test_delegate_parameter", simple_param, unit="Ohm")
122+
d = DelegateParameter("test_delegate_parameter", source=simple_param, unit="Ohm")
123123
assert d.label == simple_param.label
124124
assert not d.unit == simple_param.unit
125125
assert d.unit == "Ohm"
126126

127127

128128
def test_overwritten_label_on_init(simple_param: Parameter) -> None:
129129
d = DelegateParameter(
130-
"test_delegate_parameter", simple_param, label="Physical parameter"
130+
"test_delegate_parameter", source=simple_param, label="Physical parameter"
131131
)
132132
assert d.unit == simple_param.unit
133133
assert not d.label == simple_param.label
@@ -140,15 +140,15 @@ def test_get_set_raises(simple_param: Parameter) -> None:
140140
"""
141141
for kwargs in ({"set_cmd": None}, {"get_cmd": None}):
142142
with pytest.raises(KeyError) as e:
143-
DelegateParameter("test_delegate_parameter", simple_param, **kwargs)
143+
DelegateParameter("test_delegate_parameter", source=simple_param, **kwargs)
144144
assert str(e.value).startswith("'It is not allowed to set")
145145

146146

147147
def test_scaling(simple_param: Parameter, numeric_val: int) -> None:
148148
scale = 5
149149
offset = 3
150150
d = DelegateParameter(
151-
"test_delegate_parameter", simple_param, offset=offset, scale=scale
151+
"test_delegate_parameter", source=simple_param, offset=offset, scale=scale
152152
)
153153

154154
simple_param(numeric_val)
@@ -165,7 +165,7 @@ def test_scaling_delegate_initial_value(
165165
offset = 3
166166
DelegateParameter(
167167
"test_delegate_parameter",
168-
simple_param,
168+
source=simple_param,
169169
offset=offset,
170170
scale=scale,
171171
initial_value=numeric_val,
@@ -178,7 +178,7 @@ def test_scaling_initial_value(simple_param: Parameter) -> None:
178178
scale = 5
179179
offset = 3
180180
d = DelegateParameter(
181-
"test_delegate_parameter", simple_param, offset=offset, scale=scale
181+
"test_delegate_parameter", source=simple_param, offset=offset, scale=scale
182182
)
183183
assert d() == (simple_param() - offset) / scale
184184

@@ -188,7 +188,7 @@ def test_snapshot() -> None:
188188
"testparam", set_cmd=None, get_cmd=None, offset=1, scale=2, initial_value=1
189189
)
190190
d = DelegateParameter(
191-
"test_delegate_parameter", p, offset=3, scale=5, initial_value=2
191+
"test_delegate_parameter", source=p, offset=3, scale=5, initial_value=2
192192
)
193193

194194
delegate_snapshot = d.snapshot()
@@ -205,7 +205,7 @@ def test_set_source_cache_changes_delegate_cache(simple_param: Parameter) -> Non
205205
"""
206206
offset = 4
207207
scale = 5
208-
d = DelegateParameter("d", simple_param, offset=offset, scale=scale)
208+
d = DelegateParameter("d", source=simple_param, offset=offset, scale=scale)
209209
new_source_value = 3
210210
simple_param.cache.set(new_source_value)
211211

@@ -219,7 +219,7 @@ def test_set_source_cache_changes_delegate_get(simple_param: Parameter) -> None:
219219
"""
220220
offset = 4
221221
scale = 5
222-
d = DelegateParameter("d", simple_param, offset=offset, scale=scale)
222+
d = DelegateParameter("d", source=simple_param, offset=offset, scale=scale)
223223
new_source_value = 3
224224

225225
simple_param.cache.set(new_source_value)
@@ -230,7 +230,7 @@ def test_set_source_cache_changes_delegate_get(simple_param: Parameter) -> None:
230230
def test_set_delegate_cache_changes_source_cache(simple_param: Parameter) -> None:
231231
offset = 4
232232
scale = 5
233-
d = DelegateParameter("d", simple_param, offset=offset, scale=scale)
233+
d = DelegateParameter("d", source=simple_param, offset=offset, scale=scale)
234234

235235
new_delegate_value = 2
236236
d.cache.set(new_delegate_value)
@@ -241,7 +241,7 @@ def test_set_delegate_cache_changes_source_cache(simple_param: Parameter) -> Non
241241
def test_set_delegate_cache_with_raw_value(simple_param: Parameter) -> None:
242242
offset = 4
243243
scale = 5
244-
d = DelegateParameter("d", simple_param, offset=offset, scale=scale)
244+
d = DelegateParameter("d", source=simple_param, offset=offset, scale=scale)
245245

246246
new_delegate_value = 2
247247
d.cache._set_from_raw_value(new_delegate_value * scale + offset)
@@ -266,7 +266,7 @@ def test_instrument_val_invariant_under_delegate_cache_set(
266266

267267
def test_delegate_cache_pristine_if_not_set() -> None:
268268
p = Parameter("test")
269-
d = DelegateParameter("delegate", p)
269+
d = DelegateParameter("delegate", source=p)
270270
gotten_delegate_cache = d.cache.get(get_if_invalid=False)
271271
assert gotten_delegate_cache is None
272272

@@ -293,7 +293,7 @@ def test_delegate_get_updates_cache(
293293
) -> None:
294294
initial_value = numeric_val
295295
t = make_observable_parameter("observable_parameter", initial_value=initial_value)
296-
d = DelegateParameter("delegate", t)
296+
d = DelegateParameter("delegate", source=t)
297297

298298
assert d() == initial_value
299299
assert d.cache.get() == initial_value
@@ -333,7 +333,7 @@ def test_raw_value_scaling() -> None:
333333
"""
334334

335335
p = Parameter("testparam", set_cmd=None, get_cmd=None, offset=1, scale=2)
336-
d = DelegateParameter("test_delegate_parameter", p, offset=3, scale=5)
336+
d = DelegateParameter("test_delegate_parameter", source=p, offset=3, scale=5)
337337

338338
val = 1
339339
p(val)
@@ -347,15 +347,17 @@ def test_raw_value_scaling() -> None:
347347
def test_setting_initial_value_delegate_parameter() -> None:
348348
value = 10
349349
p = Parameter("testparam", set_cmd=None, get_cmd=None)
350-
d = DelegateParameter("test_delegate_parameter", p, initial_value=value)
350+
d = DelegateParameter("test_delegate_parameter", source=p, initial_value=value)
351351
assert p.cache.get(get_if_invalid=False) == value
352352
assert d.cache.get(get_if_invalid=False) == value
353353

354354

355355
def test_setting_initial_cache_delegate_parameter() -> None:
356356
value = 10
357357
p = Parameter("testparam", set_cmd=None, get_cmd=None)
358-
d = DelegateParameter("test_delegate_parameter", p, initial_cache_value=value)
358+
d = DelegateParameter(
359+
"test_delegate_parameter", source=p, initial_cache_value=value
360+
)
359361
assert p.cache.get(get_if_invalid=False) == value
360362
assert d.cache.get(get_if_invalid=False) == value
361363

@@ -524,7 +526,9 @@ def test_delegate_parameter_fixed_label_unit_unchanged() -> None:
524526
def test_cache_invalidation() -> None:
525527
value = 10
526528
p = BetterGettableParam("testparam", set_cmd=None, get_cmd=None)
527-
d = DelegateParameter("test_delegate_parameter", p, initial_cache_value=value)
529+
d = DelegateParameter(
530+
"test_delegate_parameter", source=p, initial_cache_value=value
531+
)
528532
assert p._get_count == 0
529533
assert d.cache.get() == value
530534
assert p._get_count == 0
@@ -562,7 +566,7 @@ def test_cache_no_source() -> None:
562566

563567
def test_underlying_instrument_property_for_delegate_parameter() -> None:
564568
p = BetterGettableParam("testparam", set_cmd=None, get_cmd=None)
565-
d = DelegateParameter("delegate_parameter_with_source", p)
569+
d = DelegateParameter("delegate_parameter_with_source", source=p)
566570

567571
assert d.underlying_instrument is p.root_instrument
568572

0 commit comments

Comments
 (0)