Skip to content
Open
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
13 changes: 13 additions & 0 deletions src/qcodes/parameters/delegate_parameter.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from __future__ import annotations

import warnings
from typing import TYPE_CHECKING, Any, Generic

from typing_extensions import TypeVar

from qcodes.utils import QCoDeSDeprecationWarning

from .parameter import Parameter
from .parameter_base import InstrumentTypeVar_co, ParameterDataTypeVar

Expand Down Expand Up @@ -179,6 +182,16 @@ def __init__(
*args: Any,
**kwargs: Any,
):
if args:
# TODO: After QCoDeS 0.57 remove the args argument
# and delete this code block.
warnings.warn(
"Passing extra positional arguments to "
f"{type(self).__name__} is deprecated. "
"Please pass them as keyword arguments.",
QCoDeSDeprecationWarning,
stacklevel=2,
)
if "bind_to_instrument" not in kwargs.keys():
kwargs["bind_to_instrument"] = False

Expand Down
99 changes: 98 additions & 1 deletion src/qcodes/parameters/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@

import logging
import os
import warnings
from types import MethodType
from typing import TYPE_CHECKING, Any, Generic, Literal
from typing import TYPE_CHECKING, Any, ClassVar, Generic, Literal

from qcodes.utils import QCoDeSDeprecationWarning

from .command import Command
from .parameter_base import (
Expand Down Expand Up @@ -177,9 +180,27 @@ class Parameter(

"""

# Ordered list of keyword argument names (after 'name') for
# backwards-compatible positional argument handling.
# TODO: remove with handling of args below after QCoDeS 0.57
_DEPRECATED_POSITIONAL_ARGS: ClassVar[tuple[str, ...]] = (
"instrument",
"label",
"unit",
"get_cmd",
"set_cmd",
"initial_value",
"max_val_age",
"vals",
"docstring",
"initial_cache_value",
"bind_to_instrument",
)

def __init__(
self,
name: str,
*args: Any,
# mypy seems to be confused here. The bound and default for InstrumentTypeVar_co
# contains None but mypy will not allow None as a default as of v 1.19.0
instrument: InstrumentTypeVar_co = None, # type: ignore[assignment]
Expand All @@ -195,6 +216,82 @@ def __init__(
bind_to_instrument: bool = True,
**kwargs: Any,
) -> None:
if args:
# TODO: After QCoDeS 0.57 remove the args argument and delete this code block.
positional_names = self._DEPRECATED_POSITIONAL_ARGS
if len(args) > len(positional_names):
raise TypeError(
f"{type(self).__name__}.__init__() takes at most "
f"{len(positional_names) + 2} positional arguments "
f"({len(args) + 2} given)"
)

_defaults: dict[str, Any] = {
"instrument": None,
"label": None,
"unit": None,
"get_cmd": None,
"set_cmd": False,
"initial_value": None,
"max_val_age": None,
"vals": None,
"docstring": None,
"initial_cache_value": None,
"bind_to_instrument": True,
}

# Snapshot keyword values before any reassignment so we can
# detect duplicates (keyword value differs from its default).
_kwarg_vals: dict[str, Any] = {
"instrument": instrument,
"label": label,
"unit": unit,
"get_cmd": get_cmd,
"set_cmd": set_cmd,
"initial_value": initial_value,
"max_val_age": max_val_age,
"vals": vals,
"docstring": docstring,
"initial_cache_value": initial_cache_value,
"bind_to_instrument": bind_to_instrument,
}

# Check for duplicate arguments (passed both positionally and
# as keyword). We detect this by checking whether the keyword
# value differs from its default for each positionally-supplied
# argument.
for i in range(len(args)):
arg_name = positional_names[i]
if _kwarg_vals[arg_name] is not _defaults[arg_name]:
raise TypeError(
f"{type(self).__name__}.__init__() got multiple "
f"values for argument '{arg_name}'"
)

positional_arg_names = positional_names[: len(args)]
names_str = ", ".join(f"'{n}'" for n in positional_arg_names)
warnings.warn(
f"Passing {names_str} as positional argument(s) to "
f"{type(self).__name__} is deprecated. "
f"Please pass them as keyword arguments.",
QCoDeSDeprecationWarning,
stacklevel=2,
)

# Apply positional values to the keyword parameter variables.
_pos = dict(zip(positional_names, args))
instrument = _pos.get("instrument", instrument)
label = _pos.get("label", label)
unit = _pos.get("unit", unit)
get_cmd = _pos.get("get_cmd", get_cmd)
set_cmd = _pos.get("set_cmd", set_cmd)
initial_value = _pos.get("initial_value", initial_value)
max_val_age = _pos.get("max_val_age", max_val_age)
vals = _pos.get("vals", vals)
docstring = _pos.get("docstring", docstring)
initial_cache_value = _pos.get("initial_cache_value", initial_cache_value)
bind_to_instrument = _pos.get("bind_to_instrument", bind_to_instrument)

def _get_manual_parameter(self: Parameter) -> ParamRawDataType:
if self.root_instrument is not None:
mylogger: InstrumentLoggerAdapter | logging.Logger = (
Expand Down
137 changes: 135 additions & 2 deletions src/qcodes/parameters/parameter_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@

from qcodes.metadatable import Metadatable, MetadatableWithName
from qcodes.parameters import ParamSpecBase
from qcodes.utils import DelegateAttributes, full_class, qcodes_abstractmethod
from qcodes.utils import (
DelegateAttributes,
QCoDeSDeprecationWarning,
full_class,
qcodes_abstractmethod,
)
from qcodes.validators import (
Arrays,
ComplexNumbers,
Expand Down Expand Up @@ -226,10 +231,38 @@ class ParameterBase(
Callable[[ParameterBase, ParamDataType], None] | None
] = None

# Ordered list of keyword argument names (after 'name') for
# backwards-compatible positional argument handling.
# TODO: remove with handling of args below after QCoDeS 0.57
_DEPRECATED_POSITIONAL_ARGS: ClassVar[tuple[str, ...]] = (
"instrument",
"snapshot_get",
"metadata",
"step",
"scale",
"offset",
"inter_delay",
"post_delay",
"val_mapping",
"get_parser",
"set_parser",
"snapshot_value",
"snapshot_exclude",
"max_val_age",
"vals",
"abstract",
"bind_to_instrument",
"register_name",
"on_set_callback",
)

def __init__(
self,
name: str,
instrument: InstrumentTypeVar_co,
*args: Any,
# mypy seems to be confused here. The bound and default for InstrumentTypeVar_co
# contains None but mypy will not allow None as a default as of v 1.19.0
instrument: InstrumentTypeVar_co = None, # type: ignore[assignment]
snapshot_get: bool = True,
metadata: Mapping[Any, Any] | None = None,
step: float | None = None,
Expand All @@ -250,6 +283,106 @@ def __init__(
on_set_callback: Callable[[ParameterBase, ParameterDataTypeVar], None]
| None = None,
) -> None:
if args:
# TODO: After QCoDeS 0.57 remove the args argument and delete this code block.
positional_names = self._DEPRECATED_POSITIONAL_ARGS
if len(args) > len(positional_names):
raise TypeError(
f"{type(self).__name__}.__init__() takes at most "
f"{len(positional_names) + 2} positional arguments "
f"({len(args) + 2} given)"
)

_defaults: dict[str, Any] = {
"instrument": None,
"snapshot_get": True,
"metadata": None,
"step": None,
"scale": None,
"offset": None,
"inter_delay": 0,
"post_delay": 0,
"val_mapping": None,
"get_parser": None,
"set_parser": None,
"snapshot_value": True,
"snapshot_exclude": False,
"max_val_age": None,
"vals": None,
"abstract": False,
"bind_to_instrument": True,
"register_name": None,
"on_set_callback": None,
}

# Snapshot keyword values before any reassignment so we can
# detect duplicates (keyword value differs from its default).
_kwarg_vals: dict[str, Any] = {
"instrument": instrument,
"snapshot_get": snapshot_get,
"metadata": metadata,
"step": step,
"scale": scale,
"offset": offset,
"inter_delay": inter_delay,
"post_delay": post_delay,
"val_mapping": val_mapping,
"get_parser": get_parser,
"set_parser": set_parser,
"snapshot_value": snapshot_value,
"snapshot_exclude": snapshot_exclude,
"max_val_age": max_val_age,
"vals": vals,
"abstract": abstract,
"bind_to_instrument": bind_to_instrument,
"register_name": register_name,
"on_set_callback": on_set_callback,
}

# Check for duplicate arguments (passed both positionally and
# as keyword). We detect this by checking whether the keyword
# value differs from its default for each positionally-supplied
# argument.
for i in range(len(args)):
arg_name = positional_names[i]
if _kwarg_vals[arg_name] is not _defaults[arg_name]:
raise TypeError(
f"{type(self).__name__}.__init__() got multiple "
f"values for argument '{arg_name}'"
)

positional_arg_names = positional_names[: len(args)]
names_str = ", ".join(f"'{n}'" for n in positional_arg_names)
warnings.warn(
f"Passing {names_str} as positional argument(s) to "
f"{type(self).__name__} is deprecated. "
f"Please pass them as keyword arguments.",
QCoDeSDeprecationWarning,
stacklevel=2,
)

# Apply positional values to the keyword parameter variables.
_pos = dict(zip(positional_names, args))
instrument = _pos.get("instrument", instrument)
snapshot_get = _pos.get("snapshot_get", snapshot_get)
metadata = _pos.get("metadata", metadata)
step = _pos.get("step", step)
scale = _pos.get("scale", scale)
offset = _pos.get("offset", offset)
inter_delay = _pos.get("inter_delay", inter_delay)
post_delay = _pos.get("post_delay", post_delay)
val_mapping = _pos.get("val_mapping", val_mapping)
get_parser = _pos.get("get_parser", get_parser)
set_parser = _pos.get("set_parser", set_parser)
snapshot_value = _pos.get("snapshot_value", snapshot_value)
snapshot_exclude = _pos.get("snapshot_exclude", snapshot_exclude)
max_val_age = _pos.get("max_val_age", max_val_age)
vals = _pos.get("vals", vals)
abstract = _pos.get("abstract", abstract)
bind_to_instrument = _pos.get("bind_to_instrument", bind_to_instrument)
register_name = _pos.get("register_name", register_name)
on_set_callback = _pos.get("on_set_callback", on_set_callback)

super().__init__(metadata)
if not str(name).isidentifier():
raise ValueError(
Expand Down
Loading
Loading