Skip to content

Commit

Permalink
Merge pull request #6802 from qutech/bugfix/numbers_type
Browse files Browse the repository at this point in the history
Check for numeric type using numbers.Real
  • Loading branch information
jenshnielsen authored Feb 3, 2025
2 parents 89de199 + 7f3c6ca commit b69a96b
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 26 deletions.
6 changes: 3 additions & 3 deletions src/qcodes/instrument_drivers/american_magnetics/AMI430.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import collections.abc
import logging
import numbers
import time
import warnings
from collections import defaultdict
Expand All @@ -20,6 +19,7 @@
from qcodes.math_utils import FieldVector
from qcodes.parameters import Parameter
from qcodes.utils import QCoDeSDeprecationWarning
from qcodes.utils.types import NumberType
from qcodes.validators import Anything, Bool, Enum, Ints, Numbers

if TYPE_CHECKING:
Expand Down Expand Up @@ -635,7 +635,7 @@ def find_ami430_with_name(ami430_name: str) -> AMI430:
self._field_limit: float | Iterable[CartesianFieldLimitFunction]
if isinstance(field_limit, collections.abc.Iterable):
self._field_limit = field_limit
elif isinstance(field_limit, numbers.Real):
elif isinstance(field_limit, NumberType):
# Conversion to float makes related driver logic simpler
self._field_limit = float(field_limit)
else:
Expand Down Expand Up @@ -978,7 +978,7 @@ def _raise_if_not_same_field_and_ramp_rate_units(self) -> tuple[str, str]:
def _verify_safe_setpoint(
self, setpoint_values: tuple[float, float, float]
) -> bool:
if isinstance(self._field_limit, (int, float)):
if isinstance(self._field_limit, NumberType):
return bool(np.linalg.norm(setpoint_values) < self._field_limit)

answer = any(
Expand Down
10 changes: 4 additions & 6 deletions src/qcodes/instrument_drivers/american_magnetics/AMI430_visa.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

import logging
import numbers
import time
import warnings
from collections import defaultdict
Expand All @@ -24,6 +23,7 @@
from qcodes.math_utils import FieldVector
from qcodes.parameters import Parameter
from qcodes.utils import QCoDeSDeprecationWarning
from qcodes.utils.types import NumberType
from qcodes.validators import Anything, Bool, Enum, Ints, Numbers

if TYPE_CHECKING:
Expand Down Expand Up @@ -730,7 +730,7 @@ def find_ami430_with_name(ami430_name: str) -> AMIModel430:
self._field_limit: float | Iterable[CartesianFieldLimitFunction]
if isinstance(field_limit, Iterable):
self._field_limit = field_limit
elif isinstance(field_limit, numbers.Real):
elif isinstance(field_limit, NumberType):
# Conversion to float makes related driver logic simpler
self._field_limit = float(field_limit)
else:
Expand Down Expand Up @@ -1073,7 +1073,7 @@ def _raise_if_not_same_field_and_ramp_rate_units(self) -> tuple[str, str]:
def _verify_safe_setpoint(
self, setpoint_values: tuple[float, float, float]
) -> bool:
if isinstance(self._field_limit, (int, float)):
if isinstance(self._field_limit, NumberType):
return bool(np.linalg.norm(setpoint_values) < self._field_limit)

answer = any(
Expand Down Expand Up @@ -1240,9 +1240,7 @@ def pause(self) -> None:
):
axis_instrument.pause()

def _request_field_change(
self, instrument: AMIModel430, value: numbers.Real
) -> None:
def _request_field_change(self, instrument: AMIModel430, value: NumberType) -> None:
"""
This method is called by the child x/y/z magnets if they are set
individually. It results in additional safety checks being
Expand Down
10 changes: 6 additions & 4 deletions src/qcodes/math_utils/field_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import numpy as np

from qcodes.utils.types import NumberType

if TYPE_CHECKING:
from collections.abc import Sequence

Expand Down Expand Up @@ -292,21 +294,21 @@ def __setitem__(self, component: str, value: float) -> None:
self.set_component(**{component: value})

def __mul__(self, other: Any) -> FieldVector:
if not isinstance(other, (float, int)):
if not isinstance(other, NumberType):
return NotImplemented

return FieldVector(
**{component: self[component] * other for component in "xyz"}
**{component: self[component] * float(other) for component in "xyz"}
)

def __rmul__(self, other: Any) -> FieldVector:
if not isinstance(other, (int, float)):
if not isinstance(other, NumberType):
return NotImplemented

return self * other

def __truediv__(self, other: Any) -> FieldVector:
if not isinstance(other, (int, float)):
if not isinstance(other, NumberType):
return NotImplemented

return self * (1.0 / other)
Expand Down
20 changes: 10 additions & 10 deletions src/qcodes/parameters/parameter_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from qcodes.utils import DelegateAttributes, full_class, qcodes_abstractmethod
from qcodes.validators import Enum, Ints, Validator

from ..utils.types import NumberType
from .cache import _Cache, _CacheProtocol
from .named_repr import named_repr
from .permissive_range import permissive_range
Expand Down Expand Up @@ -783,8 +784,8 @@ def set_wrapper(value: ParamDataType, **kwargs: Any) -> None:
return set_wrapper

def get_ramp_values(
self, value: float | Sized, step: float | None = None
) -> Sequence[float | Sized]:
self, value: NumberType | Sized, step: NumberType | None = None
) -> Sequence[NumberType | Sized]:
"""
Return values to sweep from current value to target value.
This method can be overridden to have a custom sweep behaviour.
Expand All @@ -809,8 +810,7 @@ def get_ramp_values(
self.get()
start_value = self.get_latest()
if not (
isinstance(start_value, (int, float))
and isinstance(value, (int, float))
isinstance(start_value, NumberType) and isinstance(value, NumberType)
):
# parameter is numeric but either one of the endpoints
# is not or the starting point is unknown. The later
Expand Down Expand Up @@ -859,7 +859,7 @@ def validate(self, value: ParamDataType) -> None:
validator.validate(value, self._validate_context)

@property
def step(self) -> float | None:
def step(self) -> NumberType | None:
"""
Stepsize that this Parameter uses during set operation.
Stepsize must be a positive number or None.
Expand All @@ -883,12 +883,12 @@ def step(self) -> float | None:
return self._step

@step.setter
def step(self, step: float | None) -> None:
def step(self, step: NumberType | None) -> None:
if step is None:
self._step: float | None = step
self._step: NumberType | None = step
elif not all(getattr(vals, "is_numeric", True) for vals in self._vals):
raise TypeError("you can only step numeric parameters")
elif not isinstance(step, (int, float)):
elif not isinstance(step, NumberType):
raise TypeError("step must be a number")
elif step == 0:
self._step = None
Expand Down Expand Up @@ -928,7 +928,7 @@ def post_delay(self) -> float:

@post_delay.setter
def post_delay(self, post_delay: float) -> None:
if not isinstance(post_delay, (int, float)):
if not isinstance(post_delay, NumberType):
raise TypeError(f"post_delay ({post_delay}) must be a number")
if post_delay < 0:
raise ValueError(f"post_delay ({post_delay}) must not be negative")
Expand Down Expand Up @@ -957,7 +957,7 @@ def inter_delay(self) -> float:

@inter_delay.setter
def inter_delay(self, inter_delay: float) -> None:
if not isinstance(inter_delay, (int, float)):
if not isinstance(inter_delay, NumberType):
raise TypeError(f"inter_delay ({inter_delay}) must be a number")
if inter_delay < 0:
raise ValueError(f"inter_delay ({inter_delay}) must not be negative")
Expand Down
9 changes: 6 additions & 3 deletions src/qcodes/parameters/permissive_range.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from __future__ import annotations

import math
from typing import SupportsAbs
from typing import TYPE_CHECKING, SupportsAbs

if TYPE_CHECKING:
from qcodes.utils.types import NumberType


# could use numpy.arange here, but
# I'd like to be more flexible with the sign of step
def permissive_range(
start: float, stop: float, step: SupportsAbs[float]
) -> list[float]:
start: NumberType, stop: NumberType, step: SupportsAbs[NumberType]
) -> list[NumberType]:
"""
Returns a range (as a list of values) with floating point steps.
Always starts at start and moves toward stop, regardless of the
Expand Down
7 changes: 7 additions & 0 deletions src/qcodes/utils/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from __future__ import annotations

from typing import TypeAlias

import numpy as np

complex_type_union = np.complex64 | np.complex128 | np.complexfloating | complex
Expand Down Expand Up @@ -82,3 +84,8 @@

concrete_complex_types = (*numpy_concrete_complex, complex)
complex_types = (*numpy_concrete_complex, complex)

NumberType: TypeAlias = int | float | np.integer | np.floating
"""
Python or NumPy real number.
"""

0 comments on commit b69a96b

Please sign in to comment.