11"""Idea is taken from: https://stackoverflow.com/a/55504010/10975692"""
22import inspect
3+ import sys
34import types
45import typing
56from io import BytesIO , StringIO , BufferedWriter , TextIOWrapper
@@ -220,6 +221,7 @@ def _is_instance(obj: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context:
220221
221222 if hasattr (obj , '_asdict' ):
222223 if hasattr (type_ , '_field_types' ):
224+ raise RuntimeError ('Foo' )
223225 field_types = type_ ._field_types
224226 elif hasattr (type_ , '__annotations__' ):
225227 field_types = type_ .__annotations__
@@ -338,7 +340,8 @@ def _is_generic(cls: Any) -> bool:
338340 return True
339341 elif isinstance (cls , typing ._SpecialForm ):
340342 return cls not in {Any }
341-
343+ elif cls is typing .Union or type (cls ) is typing .Union : # for python >= 3.14 Union is no longer a typing._SpecialForm
344+ return True
342345 return False
343346
344347
@@ -404,8 +407,6 @@ def get_type_arguments(cls: Any) -> Tuple[Any, ...]:
404407 (typing.Tuple[float, str],)
405408 >>> get_type_arguments(List[Tuple[Any, ...]])
406409 (typing.Tuple[typing.Any, ...],)
407- >>> Union[bool, int, float]
408- typing.Union[bool, int, float]
409410 >>> get_type_arguments(Union[str, float, int])
410411 (<class 'str'>, <class 'float'>, <class 'int'>)
411412 >>> get_type_arguments(Union[str, float, List[int], int])
@@ -472,10 +473,10 @@ def get_base_generic(cls: Any) -> Any:
472473 typing.Dict
473474 >>> get_base_generic(Dict[str, str])
474475 typing.Dict
475- >>> get_base_generic(Union)
476- typing.Union
477- >>> get_base_generic(Union[float, int, str])
478- typing.Union
476+ >>> 'typing.Union' in str( get_base_generic(Union)) # 3.13: typing.Union 3.14: <class 'typing.Union'>
477+ True
478+ >>> 'typing.Union' in str( get_base_generic(Union[float, int, str])) # 3.13: typing.Union 3.14: <class 'typing.Union'>
479+ True
479480 >>> get_base_generic(Set)
480481 typing.Set
481482 >>> get_base_generic(Set[int])
@@ -491,7 +492,7 @@ def get_base_generic(cls: Any) -> Any:
491492
492493 if name is not None :
493494 return getattr (typing , name )
494- elif origin is not None :
495+ elif origin is not None and cls is not typing . Union :
495496 return origin
496497 return cls
497498
@@ -537,10 +538,8 @@ def _is_subtype(sub_type: Any, super_type: Any, context: Dict[str, Any] = None)
537538 False
538539 >>> _is_subtype(List[int], List[Union[int, float]])
539540 True
540- >>> _is_subtype(List[Union[int, float]], List[int])
541- Traceback (most recent call last):
542- ...
543- TypeError: issubclass() arg 1 must be a class
541+ >>> _is_subtype(List[Union[int, float]], List[int]) if sys.version_info >= (3, 14) else False
542+ False
544543 >>> class Parent: pass
545544 >>> class Child(Parent): pass
546545 >>> _is_subtype(List[Child], List[Parent])
@@ -741,6 +740,7 @@ def _instancecheck_tuple(tup: Tuple, type_args: Any, type_vars: Dict[TypeVar_, A
741740 return all (_is_instance (obj = val , type_ = type_args [0 ], type_vars = type_vars , context = context ) for val in tup )
742741
743742 if tup == () and type_args == ((),):
743+ raise RuntimeError ('Foo3' )
744744 return True
745745
746746 if len (tup ) != len (type_args ):
@@ -1033,6 +1033,8 @@ def convert_to_typing_types(x: typing.Type) -> typing.Type:
10331033 typing.Tuple[int]
10341034 >>> convert_to_typing_types(type[int])
10351035 typing.Type[int]
1036+ >>> convert_to_typing_types(type[int | float])
1037+ typing.Type[int | float]
10361038 >>> convert_to_typing_types(tuple[int, float])
10371039 typing.Tuple[int, float]
10381040 >>> convert_to_typing_types(dict[int, float])
@@ -1064,6 +1066,8 @@ def convert_to_typing_types(x: typing.Type) -> typing.Type:
10641066 return typing .FrozenSet [tuple (args )]
10651067 elif origin is type :
10661068 return typing .Type [tuple (args )]
1069+ elif origin is typing .Union :
1070+ return x # new since Python 3.14
10671071
10681072 raise RuntimeError (x )
10691073
0 commit comments