@@ -37,6 +37,21 @@ def register(cls: Union[type, str], converter: type):
3737register (dict , Dictionary )
3838
3939
40+ def _convert_union (args : tuple [type , ...]) -> type | None :
41+ """Return converter for currently supported unions."""
42+ if len (args ) != 2 :
43+ return None
44+ none_type = type (None )
45+ if args [0 ] is none_type or args [1 ] is none_type :
46+ value_type = args [1 ] if args [0 ] is none_type else args [0 ]
47+ return map_type (value_type ).as_optional ()
48+ if str in args :
49+ return map_type (str )
50+ if args in {(int , float ), (float , int )}:
51+ return Number
52+ return None
53+
54+
4055@cached
4156def map_type (cls , * , name : str = "" , item_cls : Optional [type ] = None ):
4257 """Infer the converter type from a dataclass, type, or annotation."""
@@ -59,11 +74,10 @@ def map_type(cls, *, name: str = "", item_cls: Optional[type] = None):
5974 return converter
6075
6176 if hasattr (types , "UnionType" ) and isinstance (cls , types .UnionType ): # type: ignore
62- # Python 3.10 behavior
63- converter = map_type (cls .__args__ [0 ])
64- assert len (cls .__args__ ) == 2
65- assert cls .__args__ [1 ] == type (None )
66- converter = converter .as_optional ()
77+ args = tuple (getattr (cls , "__args__" , ()))
78+ converter = _convert_union (args )
79+ if converter is None :
80+ raise TypeError (f"Unsupported union type: { cls } " )
6781 return converter
6882
6983 if hasattr (cls , "__origin__" ):
@@ -114,16 +128,16 @@ def map_type(cls, *, name: str = "", item_cls: Optional[type] = None):
114128 converter = Dictionary .of_mapping (key , value )
115129
116130 elif cls .__origin__ == Union :
117- if str in cls .__args__ :
118- converter = map_type (str )
119- if type (None ) in cls .__args__ :
120- converter = converter .as_optional ()
121- elif cls .__args__ in {(int , float ), (float , int )}:
122- converter = Number
131+ args = tuple (cls .__args__ )
132+ if len (args ) == 2 :
133+ converter = _convert_union (args )
123134 else :
124- assert len (cls .__args__ ) == 2
125- assert cls .__args__ [1 ] == type (None )
126- converter = map_type (cls .__args__ [0 ]).as_optional ()
135+ if str in cls .__args__ :
136+ converter = map_type (str )
137+ if type (None ) in cls .__args__ :
138+ converter = converter .as_optional ()
139+ if converter is None :
140+ raise TypeError (f"Unsupported union type: { cls } " )
127141
128142 elif issubclass (cls .__origin__ , Converter ):
129143 subtypes = [map_type (t ) for t in cls .__args__ ]
0 commit comments