@@ -102,14 +102,13 @@ def is_valid_generic_class(value: Any, type_: Type) -> bool:
102
102
origin = get_origin (type_ )
103
103
if not (origin and isinstance (value , origin )):
104
104
return False
105
- type_hints = get_type_hints (type (value ))
105
+ type_hints = cache ( get_type_hints ) (type (value ))
106
106
for field_name , field_type in type_hints .items ():
107
107
if isinstance (field_type , TypeVar ):
108
- return (
109
- any (isinstance (getattr (value , field_name ), arg ) for arg in get_args (type_ )) if get_args (type_ ) else True
110
- )
108
+ args = get_args (type_ )
109
+ return True if not args else any (isinstance (getattr (value , field_name , None ), arg ) for arg in args )
111
110
else :
112
- return is_instance (value , type_ )
111
+ return isinstance (value , type_ )
113
112
return True
114
113
115
114
@@ -121,6 +120,31 @@ def extract_init_var(type_: Type) -> Union[Type, Any]:
121
120
return Any
122
121
123
122
123
+ @cache
124
+ def get_constraints (type_ : TypeVar ) -> Optional [Any ]:
125
+ return type_ .__constraints__
126
+
127
+
128
+ @cache
129
+ def is_constrained (type_ : TypeVar ) -> bool :
130
+ return hasattr (type_ , "__constraints__" ) and get_constraints (type_ )
131
+
132
+
133
+ @cache
134
+ def get_bound (type_ : TypeVar ) -> Optional [Any ]:
135
+ return type_ .__bound__
136
+
137
+
138
+ @cache
139
+ def is_bound (type_ : TypeVar ) -> bool :
140
+ return hasattr (type_ , "__bound__" ) and get_bound (type_ )
141
+
142
+
143
+ @cache
144
+ def is_generic_bound (type_ : TypeVar ) -> bool :
145
+ return is_bound (type_ ) and get_bound (type_ ) is not None and is_generic (get_bound (type_ ))
146
+
147
+
124
148
def is_instance (value : Any , type_ : Type ) -> bool :
125
149
try :
126
150
# As described in PEP 484 - section: "The numeric tower"
@@ -164,13 +188,13 @@ def is_instance(value: Any, type_: Type) -> bool:
164
188
elif isclass (type (type_ )) and is_generic_alias (type (type_ )):
165
189
return is_valid_generic_class (value , type_ )
166
190
elif isinstance (type_ , TypeVar ):
167
- if hasattr (type_ , "__constraints__" ) and type_ . __constraints__ :
191
+ if is_constrained (type_ ) :
168
192
return any (is_instance (value , t ) for t in type_ .__constraints__ )
169
- if hasattr (type_ , "__bound__" ) and type_ . __bound__ :
170
- if isinstance (type_ . __bound__ , tuple ):
171
- return any (is_instance (value , t ) for t in type_ . __bound__ )
172
- if type_ . __bound__ is not None and is_generic (type_ . __bound__ ):
173
- return isinstance (value , extract_generic (type_ . __bound__ ))
193
+ if is_bound (type_ ) :
194
+ if isinstance (get_bound ( type_ ) , tuple ):
195
+ return any (isinstance (value , t ) for t in get_bound ( type_ ) )
196
+ if is_generic_bound (type_ ):
197
+ return isinstance (value , extract_generic (get_bound ( type_ ) ))
174
198
return True
175
199
elif is_type_generic (type_ ):
176
200
return is_subclass (value , extract_generic (type_ )[0 ])
0 commit comments