11"""Idea is taken from: https://stackoverflow.com/a/55504010/10975692"""
22import inspect
3+ import logging
4+ import sys
35import types
46import typing
57from io import BytesIO , StringIO , BufferedWriter , TextIOWrapper
@@ -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])
@@ -1033,6 +1032,8 @@ def convert_to_typing_types(x: typing.Type) -> typing.Type:
10331032 typing.Tuple[int]
10341033 >>> convert_to_typing_types(type[int])
10351034 typing.Type[int]
1035+ >>> convert_to_typing_types(type[int | float])
1036+ typing.Type[int | float]
10361037 >>> convert_to_typing_types(tuple[int, float])
10371038 typing.Tuple[int, float]
10381039 >>> convert_to_typing_types(dict[int, float])
@@ -1064,6 +1065,8 @@ def convert_to_typing_types(x: typing.Type) -> typing.Type:
10641065 return typing .FrozenSet [tuple (args )]
10651066 elif origin is type :
10661067 return typing .Type [tuple (args )]
1068+ elif origin is typing .Union :
1069+ return x
10671070
10681071 raise RuntimeError (x )
10691072
0 commit comments