44
55import ruamel .yaml
66from deprecated import deprecated
7+ from pydantic import TypeAdapter
78
89import csp
910from csp .impl .__csptypesimpl import _csptypesimpl
@@ -35,7 +36,11 @@ def __new__(cls, name, bases, dct):
3536 # Lists need to be normalized too as potentially we need to add a boolean flag to use FastList
3637 if v == FastList :
3738 raise TypeError (f"{ v } annotation is not supported without args" )
38- if CspTypingUtils .is_generic_container (v ) or CspTypingUtils .is_union_type (v ):
39+ if (
40+ CspTypingUtils .is_generic_container (v )
41+ or CspTypingUtils .is_union_type (v )
42+ or CspTypingUtils .is_literal_type (v )
43+ ):
3944 actual_type = ContainerTypeNormalizer .normalized_type_to_actual_python_type (v )
4045 if CspTypingUtils .is_generic_container (actual_type ):
4146 raise TypeError (f"{ v } annotation is not supported as a struct field [{ actual_type } ]" )
@@ -147,6 +152,14 @@ def serializer(val, handler):
147152
148153
149154class Struct (_csptypesimpl .PyStruct , metaclass = StructMeta ):
155+ @classmethod
156+ def type_adapter (cls ) -> TypeAdapter :
157+ internal_type_adapter = getattr (cls , "_pydantic_type_adapter" , None )
158+ if internal_type_adapter :
159+ return internal_type_adapter
160+ cls ._pydantic_type_adapter = TypeAdapter (cls )
161+ return cls ._pydantic_type_adapter
162+
150163 @classmethod
151164 def metadata (cls , typed = False ):
152165 if typed :
@@ -191,7 +204,8 @@ def _obj_from_python(cls, json, obj_type):
191204 if CspTypingUtils .is_generic_container (obj_type ):
192205 if CspTypingUtils .get_origin (obj_type ) in (typing .List , typing .Set , typing .Tuple , FastList ):
193206 return_type = ContainerTypeNormalizer .normalized_type_to_actual_python_type (obj_type )
194- (expected_item_type ,) = obj_type .__args__
207+ # We only take the first item, so like for a Tuple, we would ignore arguments after
208+ expected_item_type = obj_type .__args__ [0 ]
195209 return_type = list if isinstance (return_type , list ) else return_type
196210 return return_type (cls ._obj_from_python (v , expected_item_type ) for v in json )
197211 elif CspTypingUtils .get_origin (obj_type ) is typing .Dict :
@@ -206,6 +220,13 @@ def _obj_from_python(cls, json, obj_type):
206220 return json
207221 else :
208222 raise NotImplementedError (f"Can not deserialize { obj_type } from json" )
223+ elif CspTypingUtils .is_union_type (obj_type ):
224+ return json ## no checks, just let it through
225+ elif CspTypingUtils .is_literal_type (obj_type ):
226+ return_type = ContainerTypeNormalizer .normalized_type_to_actual_python_type (obj_type )
227+ if isinstance (json , return_type ):
228+ return json
229+ raise ValueError (f"Expected type { return_type } received { json .__class__ } " )
209230 elif issubclass (obj_type , Struct ):
210231 if not isinstance (json , dict ):
211232 raise TypeError ("Representation of struct as json is expected to be of dict type" )
@@ -223,7 +244,9 @@ def _obj_from_python(cls, json, obj_type):
223244 return obj_type (json )
224245
225246 @classmethod
226- def from_dict (cls , json : dict ):
247+ def from_dict (cls , json : dict , use_pydantic : bool = False ):
248+ if use_pydantic :
249+ return cls .type_adapter ().validate_python (json )
227250 return cls ._obj_from_python (json , cls )
228251
229252 def to_dict_depr (self ):
0 commit comments