1
1
from dataclasses import InitVar
2
- from typing import (
3
- Type ,
4
- Any ,
5
- Optional ,
6
- Union ,
7
- Collection ,
8
- TypeVar ,
9
- Mapping ,
10
- Tuple ,
11
- get_origin ,
12
- get_type_hints ,
13
- get_args ,
14
- cast as typing_cast ,
15
- _GenericAlias , # Remove import and check for Generic in a different way
16
- )
2
+ from typing import Type , Any , Optional , Union , Collection , TypeVar , Mapping , Tuple , get_type_hints , cast as typing_cast
3
+
4
+ try :
5
+ from typing import get_origin , get_args
6
+ except ImportError :
7
+ from typing_extensions import get_origin , get_args
17
8
from inspect import isclass
18
9
19
10
from dacite .cache import cache
@@ -53,14 +44,9 @@ def is_generic_subclass(type_: Type) -> bool:
53
44
return is_generic (type_ ) and hasattr (type_ , "__args__" )
54
45
55
46
56
- @cache
57
- def is_generic_alias (type_ : Type ) -> bool :
58
- return type (type_ .__args__ ) == _GenericAlias
59
-
60
-
61
47
@cache
62
48
def is_union (type_ : Type ) -> bool :
63
- if is_generic (type_ ) and type_ . __origin__ == Union :
49
+ if is_generic (type_ ) and get_origin ( type_ ) == Union :
64
50
return True
65
51
66
52
try :
@@ -81,7 +67,7 @@ def is_literal(type_: Type) -> bool:
81
67
try :
82
68
from typing import Literal # type: ignore
83
69
84
- return is_generic (type_ ) and type_ . __origin__ == Literal
70
+ return is_generic (type_ ) and get_origin ( type_ ) == Literal
85
71
except ImportError :
86
72
return False
87
73
@@ -101,10 +87,22 @@ def is_init_var(type_: Type) -> bool:
101
87
return isinstance (type_ , InitVar ) or type_ is InitVar
102
88
103
89
90
+ @cache
91
+ def is_generic_alias (type_ : Type ) -> bool :
92
+ """Since `typing._GenericAlias` is not explicitly exported, we instead rely on this check."""
93
+ return str (type_ ) == "<class 'typing._GenericAlias'>"
94
+
95
+
96
+ @cache
97
+ def has_generic_alias_in_args (type_ : Type ) -> bool :
98
+ return is_generic_alias (type (get_args (type_ )))
99
+
100
+
104
101
def is_valid_generic_class (value : Any , type_ : Type ) -> bool :
105
- if not isinstance (value , get_origin (type_ )):
102
+ origin = get_origin (type_ )
103
+ if not (origin and isinstance (value , origin )):
106
104
return False
107
- type_hints = get_type_hints (value )
105
+ type_hints = get_type_hints (type ( value ) )
108
106
for field_name , field_type in type_hints .items ():
109
107
if isinstance (field_type , TypeVar ):
110
108
return (
@@ -165,7 +163,7 @@ def is_instance(value: Any, type_: Type) -> bool:
165
163
return value in extract_generic (type_ )
166
164
elif is_init_var (type_ ):
167
165
return is_instance (value , extract_init_var (type_ ))
168
- elif isclass (type (type_ )) and type (type_ ) == _GenericAlias :
166
+ elif isclass (type (type_ )) and is_generic_alias ( type (type_ )) :
169
167
return is_valid_generic_class (value , type_ )
170
168
elif isinstance (type_ , TypeVar ):
171
169
if hasattr (type_ , "__constraints__" ) and type_ .__constraints__ :
@@ -174,7 +172,7 @@ def is_instance(value: Any, type_: Type) -> bool:
174
172
if isinstance (type_ .__bound__ , tuple ):
175
173
return any (is_instance (value , t ) for t in type_ .__bound__ )
176
174
if type_ .__bound__ is not None and is_generic (type_ .__bound__ ):
177
- return isinstance (value , type_ .__bound__ )
175
+ return isinstance (value , extract_generic ( type_ .__bound__ ) )
178
176
return True
179
177
elif is_type_generic (type_ ):
180
178
return is_subclass (value , extract_generic (type_ )[0 ])
@@ -218,6 +216,6 @@ def is_subclass(sub_type: Type, base_type: Type) -> bool:
218
216
@cache
219
217
def is_type_generic (type_ : Type ) -> bool :
220
218
try :
221
- return type_ . __origin__ in (type , Type )
219
+ return get_origin ( type_ ) in (type , Type )
222
220
except AttributeError :
223
221
return False
0 commit comments