Skip to content
Merged
Changes from 7 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
138 changes: 98 additions & 40 deletions src/nitypes/scalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,61 @@ class Scalar(Generic[TScalar_co]):
>>> Scalar("value", "volts")
nitypes.scalar.Scalar(value='value', units='volts')

Comparing Scalars
^^^^^^^^^^^^^^^^^

You can compare scalar objects using the standard comparison operators as long as their units
are the same and their value types are compatible:

>>> s1 = Scalar(5.0, 'V')
>>> s2 = Scalar(10.0, 'V')
>>> s1 < s2
True
>>> s1 <= s2
True
>>> s1 > s2
False
>>> s1 >= s2
False
>>> s1 == s2
False
>>> s3 = Scalar(5.0, 'V')
>>> s1 == s3
True
>>> s4 = Scalar("apple", "quantity")
>>> s5 = Scalar("banana", "quantity")
>>> s4 < s5
True
>>> s4 <= s5
True
>>> s4 > s5
False
>>> s4 >= s5
False
>>> s4 == s5
False
>>> s6 = Scalar("apple", "quantity")
>>> s4 == s6
True

Attempting to compare Scalar objects with different units raises a ValueError:

>>> s1 = Scalar(0.5, 'V')
>>> s2 = Scalar(500, 'mV')
>>> s1 < s2
Traceback (most recent call last):
...
ValueError: Comparing Scalar objects with different units is not permitted.

Attempting to compare Scalar objects of numeric and string types raises a TypeError:

>>> s1 = Scalar(5.0, 'meters')
>>> s2 = Scalar("value", 'meters')
>>> s1 < s2
Traceback (most recent call last):
...
TypeError: Comparing Scalar objects of numeric and string types is not permitted.

Class members
^^^^^^^^^^^^^
"""
Expand Down Expand Up @@ -128,59 +183,59 @@ def extended_properties(self) -> ExtendedPropertyDictionary:
"""
return self._extended_properties

def __eq__(self, value: object, /) -> bool:
"""Return self==value."""
if not isinstance(value, self.__class__):
def __eq__(self, other: object, /) -> bool:
"""Return self==other."""
if not isinstance(other, self.__class__):
return NotImplemented
return self.value == value.value and self.units == value.units
return self.value == other.value and self.units == other.units

def __gt__(self, value: Scalar[TScalar_co]) -> bool:
"""Return self > value."""
if not isinstance(value, self.__class__):
def __gt__(self, other: Scalar[TScalar_co], /) -> bool:
"""Return self > other."""
if not isinstance(other, self.__class__):
return NotImplemented
self._check_units_equal_for_comparison(value.units)
if isinstance(self.value, _NUMERIC) and isinstance(value.value, _NUMERIC):
return self.value > value.value # type: ignore[no-any-return,operator] # https://github.com/python/mypy/issues/19454
elif isinstance(self.value, str) and isinstance(value.value, str):
return self.value > value.value
self._check_units_equal_for_comparison(other.units)
if isinstance(self.value, _NUMERIC) and isinstance(other.value, _NUMERIC):
return self.value > other.value # type: ignore[no-any-return,operator] # https://github.com/python/mypy/issues/19454
elif isinstance(self.value, str) and isinstance(other.value, str):
return self.value > other.value
else:
raise TypeError("Comparing Scalar objects of numeric and string types is not permitted")
raise self._comparing_numeric_and_string_not_permitted()

def __ge__(self, value: Scalar[TScalar_co]) -> bool:
"""Return self >= value."""
if not isinstance(value, self.__class__):
def __ge__(self, other: Scalar[TScalar_co], /) -> bool:
"""Return self >= other."""
if not isinstance(other, self.__class__):
return NotImplemented
self._check_units_equal_for_comparison(value.units)
if isinstance(self.value, _NUMERIC) and isinstance(value.value, _NUMERIC):
return self.value >= value.value # type: ignore[no-any-return,operator] # https://github.com/python/mypy/issues/19454
elif isinstance(self.value, str) and isinstance(value.value, str):
return self.value >= value.value
self._check_units_equal_for_comparison(other.units)
if isinstance(self.value, _NUMERIC) and isinstance(other.value, _NUMERIC):
return self.value >= other.value # type: ignore[no-any-return,operator] # https://github.com/python/mypy/issues/19454
elif isinstance(self.value, str) and isinstance(other.value, str):
return self.value >= other.value
else:
raise TypeError("Comparing Scalar objects of numeric and string types is not permitted")
raise self._comparing_numeric_and_string_not_permitted()

def __lt__(self, value: Scalar[TScalar_co]) -> bool:
"""Return self < value."""
if not isinstance(value, self.__class__):
def __lt__(self, other: Scalar[TScalar_co], /) -> bool:
"""Return self < other."""
if not isinstance(other, self.__class__):
return NotImplemented
self._check_units_equal_for_comparison(value.units)
if isinstance(self.value, _NUMERIC) and isinstance(value.value, _NUMERIC):
return self.value < value.value # type: ignore[no-any-return,operator] # https://github.com/python/mypy/issues/19454
elif isinstance(self.value, str) and isinstance(value.value, str):
return self.value < value.value
self._check_units_equal_for_comparison(other.units)
if isinstance(self.value, _NUMERIC) and isinstance(other.value, _NUMERIC):
return self.value < other.value # type: ignore[no-any-return,operator] # https://github.com/python/mypy/issues/19454
elif isinstance(self.value, str) and isinstance(other.value, str):
return self.value < other.value
else:
raise TypeError("Comparing Scalar objects of numeric and string types is not permitted")
raise self._comparing_numeric_and_string_not_permitted()

def __le__(self, value: Scalar[TScalar_co]) -> bool:
"""Return self <= value."""
if not isinstance(value, self.__class__):
def __le__(self, other: Scalar[TScalar_co], /) -> bool:
"""Return self <= other."""
if not isinstance(other, self.__class__):
return NotImplemented
self._check_units_equal_for_comparison(value.units)
if isinstance(self.value, _NUMERIC) and isinstance(value.value, _NUMERIC):
return self.value <= value.value # type: ignore[no-any-return,operator] # https://github.com/python/mypy/issues/19454
elif isinstance(self.value, str) and isinstance(value.value, str):
return self.value <= value.value
self._check_units_equal_for_comparison(other.units)
if isinstance(self.value, _NUMERIC) and isinstance(other.value, _NUMERIC):
return self.value <= other.value # type: ignore[no-any-return,operator] # https://github.com/python/mypy/issues/19454
elif isinstance(self.value, str) and isinstance(other.value, str):
return self.value <= other.value
else:
raise TypeError("Comparing Scalar objects of numeric and string types is not permitted")
raise self._comparing_numeric_and_string_not_permitted()

def __reduce__(self) -> tuple[Any, ...]:
"""Return object state for pickling."""
Expand Down Expand Up @@ -220,3 +275,6 @@ def _check_units_equal_for_comparison(self, other_units: str) -> None:
"""Raise a ValueError if other_units != self.units."""
if self.units != other_units:
raise ValueError("Comparing Scalar objects with different units is not permitted.")

def _comparing_numeric_and_string_not_permitted(self) -> TypeError:
return TypeError("Comparing Scalar objects of numeric and string types is not permitted.")