33from abc import abstractmethod
44from collections .abc import Awaitable , Callable
55from dataclasses import dataclass
6- from typing import Generic , TypeVar
6+ from typing import Any , Generic , TypeVar
77
88T = TypeVar ("T" , int , float , bool , str )
99ATTRIBUTE_TYPES : tuple [type ] = T .__constraints__ # type: ignore
@@ -21,6 +21,18 @@ class DataType(Generic[T]):
2121 def dtype (self ) -> type [T ]: # Using property due to lack of Generic ClassVars
2222 pass
2323
24+ @abstractmethod
25+ def cast (self , value : T ) -> Any :
26+ """Cast a value to a more primative datatype for `Attribute` push.
27+
28+ Also validate it against fields in the datatype.
29+ """
30+ pass
31+
32+ @property
33+ def initial_value (self ) -> T :
34+ return self .dtype ()
35+
2436
2537T_Numerical = TypeVar ("T_Numerical" , int , float )
2638
@@ -33,6 +45,13 @@ class _Numerical(DataType[T_Numerical]):
3345 min_alarm : int | None = None
3446 max_alarm : int | None = None
3547
48+ def cast (self , value : T_Numerical ) -> T_Numerical :
49+ if self .min is not None and value < self .min :
50+ raise ValueError (f"Value { value } is less than minimum { self .min } " )
51+ if self .max is not None and value > self .max :
52+ raise ValueError (f"Value { value } is greater than maximum { self .max } " )
53+ return value
54+
3655
3756@dataclass (frozen = True )
3857class Int (_Numerical [int ]):
@@ -65,6 +84,9 @@ class Bool(DataType[bool]):
6584 def dtype (self ) -> type [bool ]:
6685 return bool
6786
87+ def cast (self , value : bool ) -> bool :
88+ return value
89+
6890
6991@dataclass (frozen = True )
7092class String (DataType [str ]):
@@ -74,14 +96,5 @@ class String(DataType[str]):
7496 def dtype (self ) -> type [str ]:
7597 return str
7698
77-
78- def validate_value (datatype : DataType [T ], value : T ) -> T :
79- """Validate a value against a datatype."""
80-
81- if isinstance (datatype , (Int | Float )):
82- assert isinstance (value , (int | float )), f"Value { value } is not a number"
83- if datatype .min is not None and value < datatype .min :
84- raise ValueError (f"Value { value } is less than minimum { datatype .min } " )
85- if datatype .max is not None and value > datatype .max :
86- raise ValueError (f"Value { value } is greater than maximum { datatype .max } " )
87- return value
99+ def cast (self , value : str ) -> str :
100+ return value
0 commit comments