Skip to content

Commit e5eac77

Browse files
authored
Merge pull request #7880 from jenshnielsen/parameter_deprecate_args
Deprecate positional args to parameter classes
2 parents 14e6483 + 58181a4 commit e5eac77

19 files changed

Lines changed: 1408 additions & 75 deletions
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Passing arguments as positional arguments is deprecated for ``ParameterBase``, ``Parameter``,
2+
``ArrayParameter``, ``DelegateParameter``, ``GroupParameter``, ``GroupedParameter``,
3+
``MultiParameter``, ``MultiChannelInstrumentParameter``, ``ElapsedTimeParameter``,
4+
and ``InstrumentRefParameter``. Please pass all arguments except ``name`` as keyword arguments.

src/qcodes/instrument/channel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ def _construct_multiparam(self, name: str) -> MultiChannelInstrumentParameter:
608608
else:
609609
shapes = tuple(() for _ in self._channels)
610610
param = self._paramclass(
611-
self._channels,
611+
channels=self._channels,
612612
param_name=name,
613613
name=f"Multi_{name}",
614614
names=names,

src/qcodes/instrument_drivers/QDev/QDac_channels.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,9 @@ def __init__(
182182
self,
183183
channels: "Sequence[InstrumentChannel]",
184184
param_name: str,
185-
*args: Any,
186185
**kwargs: Any,
187186
):
188-
super().__init__(channels, param_name, *args, **kwargs)
187+
super().__init__(channels=channels, param_name=param_name, **kwargs)
189188

190189
def get_raw(self) -> tuple[ParamRawDataType, ...]:
191190
"""

src/qcodes/instrument_drivers/mock_instruments/__init__.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -675,8 +675,8 @@ def __init__(
675675
setpoint_units = (("this setpointunit",), ("this setpointunit",))
676676
super().__init__(
677677
name,
678-
names,
679-
shapes,
678+
names=names,
679+
shapes=shapes,
680680
instrument=instrument,
681681
labels=labels,
682682
units=units,
@@ -732,8 +732,8 @@ def __init__(
732732
)
733733
super().__init__(
734734
name,
735-
names,
736-
shapes,
735+
names=names,
736+
shapes=shapes,
737737
instrument=instrument,
738738
labels=labels,
739739
units=units,
@@ -792,8 +792,8 @@ def __init__(
792792
)
793793
super().__init__(
794794
name,
795-
names,
796-
shapes,
795+
names=names,
796+
shapes=shapes,
797797
instrument=instrument,
798798
labels=labels,
799799
units=units,
@@ -828,8 +828,8 @@ def __init__(
828828
setpoints = ((), ())
829829
super().__init__(
830830
name,
831-
names,
832-
shapes,
831+
names=names,
832+
shapes=shapes,
833833
instrument=instrument,
834834
labels=labels,
835835
units=units,
@@ -864,8 +864,8 @@ def __init__(
864864
setpoint_units = ("this setpointunit",)
865865
super().__init__(
866866
name,
867-
shape,
868-
instrument,
867+
shape=shape,
868+
instrument=instrument,
869869
label=label,
870870
unit=unit,
871871
setpoints=setpoints,
@@ -901,8 +901,8 @@ def __init__(
901901
setpoint_units = ("this setpointunit",)
902902
super().__init__(
903903
name,
904-
shape,
905-
instrument,
904+
shape=shape,
905+
instrument=instrument,
906906
label=label,
907907
unit=unit,
908908
setpoints=setpoints,

src/qcodes/parameters/array_parameter.py

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
import collections.abc
44
import os
5-
from typing import TYPE_CHECKING, Any
5+
import warnings
6+
from typing import TYPE_CHECKING, Any, ClassVar
67

78
import numpy as np
89

@@ -14,6 +15,8 @@
1415
has_loop = False
1516
from typing import Generic
1617

18+
from qcodes.utils import QCoDeSDeprecationWarning
19+
1720
from .parameter_base import InstrumentTypeVar_co, ParameterBase, ParameterDataTypeVar
1821
from .sequence_helpers import is_sequence_of
1922

@@ -40,6 +43,9 @@
4043
)
4144

4245

46+
_SHAPE_UNSET: Any = object()
47+
48+
4349
class ArrayParameter(
4450
ParameterBase[ParameterDataTypeVar, InstrumentTypeVar_co],
4551
Generic[ParameterDataTypeVar, InstrumentTypeVar_co],
@@ -129,10 +135,27 @@ class ArrayParameter(
129135
130136
"""
131137

138+
_DEPRECATED_POSITIONAL_ARGS: ClassVar[tuple[str, ...]] = (
139+
"shape",
140+
"instrument",
141+
"label",
142+
"unit",
143+
"setpoints",
144+
"setpoint_names",
145+
"setpoint_labels",
146+
"setpoint_units",
147+
"docstring",
148+
"snapshot_get",
149+
"snapshot_value",
150+
"snapshot_exclude",
151+
"metadata",
152+
)
153+
132154
def __init__(
133155
self,
134156
name: str,
135-
shape: Sequence[int],
157+
*args: Any,
158+
shape: Sequence[int] = _SHAPE_UNSET,
136159
# mypy seems to be confused here. The bound and default for InstrumentTypeVar_co
137160
# contains None but mypy will not allow it as a default as of v 1.19.0
138161
instrument: InstrumentTypeVar_co = None, # type: ignore[assignment]
@@ -149,6 +172,90 @@ def __init__(
149172
metadata: Mapping[Any, Any] | None = None,
150173
**kwargs: Any,
151174
) -> None:
175+
if args:
176+
# TODO: After QCoDeS 0.57 remove the args argument and delete this code block.
177+
# we hardcode the class since mypy does not support __class__ and
178+
# self / self.__class__ / type(self) in class bodies does not give
179+
# exactly this class but the type of a subclass
180+
positional_names = ArrayParameter._DEPRECATED_POSITIONAL_ARGS
181+
if len(args) > len(positional_names):
182+
raise TypeError(
183+
f"{type(self).__name__}.__init__() takes at most "
184+
f"{len(positional_names) + 2} positional arguments "
185+
f"({len(args) + 2} given)"
186+
)
187+
188+
_defaults: dict[str, Any] = {
189+
"shape": _SHAPE_UNSET,
190+
"instrument": None,
191+
"label": None,
192+
"unit": None,
193+
"setpoints": None,
194+
"setpoint_names": None,
195+
"setpoint_labels": None,
196+
"setpoint_units": None,
197+
"docstring": None,
198+
"snapshot_get": True,
199+
"snapshot_value": False,
200+
"snapshot_exclude": False,
201+
"metadata": None,
202+
}
203+
204+
_kwarg_vals: dict[str, Any] = {
205+
"shape": shape,
206+
"instrument": instrument,
207+
"label": label,
208+
"unit": unit,
209+
"setpoints": setpoints,
210+
"setpoint_names": setpoint_names,
211+
"setpoint_labels": setpoint_labels,
212+
"setpoint_units": setpoint_units,
213+
"docstring": docstring,
214+
"snapshot_get": snapshot_get,
215+
"snapshot_value": snapshot_value,
216+
"snapshot_exclude": snapshot_exclude,
217+
"metadata": metadata,
218+
}
219+
220+
for i in range(len(args)):
221+
arg_name = positional_names[i]
222+
if _kwarg_vals[arg_name] is not _defaults[arg_name]:
223+
raise TypeError(
224+
f"{type(self).__name__}.__init__() got multiple "
225+
f"values for argument '{arg_name}'"
226+
)
227+
228+
positional_arg_names = positional_names[: len(args)]
229+
names_str = ", ".join(f"'{n}'" for n in positional_arg_names)
230+
warnings.warn(
231+
f"Passing {names_str} as positional argument(s) to "
232+
f"{type(self).__name__} is deprecated. "
233+
f"Please pass them as keyword arguments.",
234+
QCoDeSDeprecationWarning,
235+
stacklevel=2,
236+
)
237+
238+
_pos = dict(zip(positional_names, args))
239+
shape = _pos.get("shape", shape)
240+
instrument = _pos.get("instrument", instrument)
241+
label = _pos.get("label", label)
242+
unit = _pos.get("unit", unit)
243+
setpoints = _pos.get("setpoints", setpoints)
244+
setpoint_names = _pos.get("setpoint_names", setpoint_names)
245+
setpoint_labels = _pos.get("setpoint_labels", setpoint_labels)
246+
setpoint_units = _pos.get("setpoint_units", setpoint_units)
247+
docstring = _pos.get("docstring", docstring)
248+
snapshot_get = _pos.get("snapshot_get", snapshot_get)
249+
snapshot_value = _pos.get("snapshot_value", snapshot_value)
250+
snapshot_exclude = _pos.get("snapshot_exclude", snapshot_exclude)
251+
metadata = _pos.get("metadata", metadata)
252+
253+
if shape is _SHAPE_UNSET:
254+
raise TypeError(
255+
f"{type(self).__name__}.__init__() missing required "
256+
f"keyword argument: 'shape'"
257+
)
258+
152259
super().__init__(
153260
name,
154261
instrument=instrument,

src/qcodes/parameters/delegate_parameter.py

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
from __future__ import annotations
22

3-
from typing import TYPE_CHECKING, Any, Generic
3+
import warnings
4+
from typing import TYPE_CHECKING, Any, ClassVar, Generic
45

56
from typing_extensions import TypeVar
67

8+
from qcodes.utils import QCoDeSDeprecationWarning
9+
710
from .parameter import Parameter
811
from .parameter_base import InstrumentTypeVar_co, ParameterDataTypeVar
912

@@ -28,6 +31,7 @@
2831
default="InstrumentBase | None",
2932
covariant=True,
3033
)
34+
_SOURCE_UNSET: Any = object()
3135

3236

3337
class DelegateParameter(
@@ -71,6 +75,11 @@ class DelegateParameter(
7175
7276
"""
7377

78+
_DEPRECATED_POSITIONAL_ARGS: ClassVar[tuple[str, ...]] = (
79+
"source",
80+
*Parameter._DEPRECATED_POSITIONAL_ARGS,
81+
)
82+
7483
class _DelegateCache(
7584
Generic[_local_ParameterDataTypeVar, _local_InstrumentTypeVar_co]
7685
):
@@ -175,10 +184,58 @@ def __call__(self) -> _local_ParameterDataTypeVar:
175184
def __init__(
176185
self,
177186
name: str,
178-
source: Parameter | None,
179187
*args: Any,
188+
source: Parameter | None = _SOURCE_UNSET,
180189
**kwargs: Any,
181190
):
191+
if args:
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)
217+
warnings.warn(
218+
f"Passing {names_str} as positional argument(s) to "
219+
f"{type(self).__name__} is deprecated. "
220+
"Please pass them as keyword arguments.",
221+
QCoDeSDeprecationWarning,
222+
stacklevel=2,
223+
)
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+
182239
if "bind_to_instrument" not in kwargs.keys():
183240
kwargs["bind_to_instrument"] = False
184241

@@ -200,7 +257,7 @@ def __init__(
200257

201258
initial_cache_value = kwargs.pop("initial_cache_value", None)
202259
self.source = source
203-
super().__init__(name, *args, **kwargs)
260+
super().__init__(name, **kwargs)
204261
self.label = kwargs.get("label", None)
205262
self.unit = kwargs.get("unit", None)
206263

0 commit comments

Comments
 (0)