@@ -21,8 +21,20 @@ def dtype(self) -> type[T]: # Using property due to lack of Generic ClassVars
2121 pass
2222
2323
24+ T_Numerical = TypeVar ("T_Numerical" , int , float )
25+
26+
27+ @dataclass (frozen = True )
28+ class _Numerical (DataType [T_Numerical ]):
29+ units : str | None = None
30+ min : int | None = None
31+ max : int | None = None
32+ min_alarm : int | None = None
33+ max_alarm : int | None = None
34+
35+
2436@dataclass (frozen = True )
25- class Int (DataType [int ]):
37+ class Int (_Numerical [int ]):
2638 """`DataType` mapping to builtin ``int``."""
2739
2840 @property
@@ -31,7 +43,7 @@ def dtype(self) -> type[int]:
3143
3244
3345@dataclass (frozen = True )
34- class Float (DataType [float ]):
46+ class Float (_Numerical [float ]):
3547 """`DataType` mapping to builtin ``float``."""
3648
3749 prec : int = 2
@@ -60,3 +72,15 @@ class String(DataType[str]):
6072 @property
6173 def dtype (self ) -> type [str ]:
6274 return str
75+
76+
77+ def validate_value (datatype : DataType [T ], value : T ) -> T :
78+ """Validate a value against a datatype."""
79+
80+ if isinstance (datatype , (Int | Float )):
81+ assert isinstance (value , (int | float )), f"Value { value } is not a number"
82+ if datatype .min is not None and value < datatype .min :
83+ raise ValueError (f"Value { value } is less than minimum { datatype .min } " )
84+ if datatype .max is not None and value > datatype .max :
85+ raise ValueError (f"Value { value } is greater than maximum { datatype .max } " )
86+ return value
0 commit comments