@@ -102,7 +102,7 @@ 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
108
return (
@@ -121,6 +121,31 @@ def extract_init_var(type_: Type) -> Union[Type, Any]:
121
121
return Any
122
122
123
123
124
+ @cache
125
+ def get_constraints (type_ : TypeVar ) -> Optional [Any ]:
126
+ return type_ .__constraints__
127
+
128
+
129
+ @cache
130
+ def is_constrained (type_ : TypeVar ) -> bool :
131
+ return hasattr (type_ , "__constraints__" ) and get_constraints (type_ )
132
+
133
+
134
+ @cache
135
+ def get_bound (type_ : TypeVar ) -> Optional [Any ]:
136
+ return type_ .__bound__
137
+
138
+
139
+ @cache
140
+ def is_bound (type_ : TypeVar ) -> bool :
141
+ return hasattr (type_ , "__bound__" ) and get_bound (type_ )
142
+
143
+
144
+ @cache
145
+ def is_generic_bound (type_ : TypeVar ) -> bool :
146
+ return is_bound (type_ ) and get_bound (type_ ) is not None and is_generic (get_bound (type_ ))
147
+
148
+
124
149
def is_instance (value : Any , type_ : Type ) -> bool :
125
150
try :
126
151
# As described in PEP 484 - section: "The numeric tower"
@@ -164,13 +189,13 @@ def is_instance(value: Any, type_: Type) -> bool:
164
189
elif isclass (type (type_ )) and is_generic_alias (type (type_ )):
165
190
return is_valid_generic_class (value , type_ )
166
191
elif isinstance (type_ , TypeVar ):
167
- if hasattr (type_ , "__constraints__" ) and type_ . __constraints__ :
192
+ if is_constrained (type_ ) :
168
193
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__ ))
194
+ if is_bound (type_ ) :
195
+ if isinstance (get_bound ( type_ ) , tuple ):
196
+ return any (is_instance (value , t ) for t in get_bound ( type_ ) )
197
+ if is_generic_bound (type_ ):
198
+ return isinstance (value , extract_generic (get_bound ( type_ ) ))
174
199
return True
175
200
elif is_type_generic (type_ ):
176
201
return is_subclass (value , extract_generic (type_ )[0 ])
0 commit comments