Source code for fastcs.datatypes.datatype
import enum
from abc import abstractmethod
from collections.abc import Sequence
from dataclasses import dataclass
from typing import Any, Generic, TypeVar
import numpy as np
DType = (
int # Int
| float # Float
| bool # Bool
| str # String
| enum.Enum # Enum
| np.ndarray # Waveform / Table
)
"""A builtin (or numpy) type supported by a corresponding FastCS Attribute DataType"""
DType_T = TypeVar("DType_T", bound=DType)
"""A TypeVar of `DType` for use in generic classes and functions"""
[docs]
@dataclass(frozen=True)
class DataType(Generic[DType_T]):
"""Generic datatype mapping to a python type, with additional metadata."""
@property
@abstractmethod
def dtype(self) -> type[DType_T]: # Using property due to lack of Generic ClassVars
raise NotImplementedError()
@property
@abstractmethod
def initial_value(self) -> DType_T:
raise NotImplementedError()
[docs]
def validate(self, value: Any) -> DType_T:
"""Validate a value against the datatype.
The base implementation is to try the cast and raise a useful error if it fails.
Child classes can implement logic before calling ``super.validate(value)`` to
modify the value passed in and help the cast succeed or after to perform further
validation of the coerced type.
Args:
value: The value to validate
Returns:
The validated value
Raises:
ValueError: If the value cannot be coerced
"""
if isinstance(value, self.dtype):
return value
try:
return self.dtype(value)
except (ValueError, TypeError) as e:
raise ValueError(f"Failed to cast {value} to type {self.dtype}") from e
[docs]
@staticmethod
def equal(value1: DType_T, value2: DType_T) -> bool:
"""Compare two values for equality
Child classes can override this if the underlying type does not implement
``__eq__`` or to define custom logic.
Args:
value1: The first value to compare
value2: The second value to compare
Returns:
`True` if the values are equal
"""
return value1 == value2
[docs]
@classmethod
def all_equal(cls, values: Sequence[DType_T]) -> bool:
"""Compare a sequence of values for equality
Args:
values: Values to compare
Returns:
`True` if all values are equal, else `False`
"""
return all(cls.equal(values[0], value) for value in values[1:])