Skip to content

Commit 16ecfca

Browse files
committed
typecheck: maybe if we're more careful with issubclass?
1 parent fb6bf33 commit 16ecfca

File tree

1 file changed

+11
-9
lines changed

1 file changed

+11
-9
lines changed

unpythonic/typecheck.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
class _MyGenericAlias: # unused, but must be a class to support isinstance() check.
3131
pass
3232

33+
from .misc import safeissubclass
34+
3335
__all__ = ["isoftype"]
3436

3537
def isoftype(value, T):
@@ -207,19 +209,19 @@ def get_args(tp):
207209
typing.SupportsAbs,
208210
typing.SupportsRound):
209211
if U is T:
210-
return issubclass(type(value), U)
212+
return safeissubclass(type(value), U)
211213

212214
# We don't have a match yet, so T might still be one of those meta-utilities
213215
# that hate `issubclass` with a passion.
214216
try:
215-
if issubclass(T, typing.Text): # https://docs.python.org/3/library/typing.html#typing.Text
217+
if safeissubclass(T, typing.Text): # https://docs.python.org/3/library/typing.html#typing.Text
216218
return isinstance(value, str) # alias for str
217219

218220
# Subclass test for Python 3.6 only. Python 3.7+ have typing._GenericAlias for the generics.
219-
if issubclass(T, typing.Tuple) or get_origin(T) is tuple:
221+
if safeissubclass(T, typing.Tuple) or get_origin(T) is tuple:
220222
if not isinstance(value, tuple):
221223
return False
222-
# bare `typing.Tuple`, no restrictions on length or element type.
224+
# blare `typing.Tuple`, no restrictions on length or element type.
223225
if T.__args__ is None:
224226
return True
225227
# homogeneous element type, arbitrary length
@@ -249,12 +251,12 @@ def ismapping(statictype, runtimetype):
249251
for statictype, runtimetype in ((typing.Dict, dict),
250252
(typing.MutableMapping, collections.abc.MutableMapping),
251253
(typing.Mapping, collections.abc.Mapping)):
252-
if issubclass(T, statictype) or get_origin(T) is runtimetype:
254+
if safeissubclass(T, statictype) or get_origin(T) is runtimetype:
253255
return ismapping(statictype, runtimetype)
254256

255257
# ItemsView is a special-case mapping in that we must not call
256258
# `.items()` on `value`.
257-
if issubclass(T, typing.ItemsView) or get_origin(T) is collections.abc.ItemsView:
259+
if safeissubclass(T, typing.ItemsView) or get_origin(T) is collections.abc.ItemsView:
258260
if not isinstance(value, collections.abc.ItemsView):
259261
return False
260262
if T.__args__ is None:
@@ -274,7 +276,7 @@ def ismapping(statictype, runtimetype):
274276
def iscollection(statictype, runtimetype):
275277
if not isinstance(value, runtimetype):
276278
return False
277-
if issubclass(statictype, typing.ByteString) or get_origin(statictype) is collections.abc.ByteString:
279+
if safeissubclass(statictype, typing.ByteString) or get_origin(statictype) is collections.abc.ByteString:
278280
# WTF? A ByteString is a Sequence[int], but only statically.
279281
# At run time, the `__args__` are actually empty - it looks
280282
# like a bare Sequence, which is invalid. HACK the special case.
@@ -305,10 +307,10 @@ def iscollection(statictype, runtimetype):
305307
(typing.MutableSequence, collections.abc.MutableSequence),
306308
(typing.MappingView, collections.abc.MappingView),
307309
(typing.Sequence, collections.abc.Sequence)):
308-
if issubclass(T, statictype) or get_origin(T) is runtimetype:
310+
if safeissubclass(T, statictype) or get_origin(T) is runtimetype:
309311
return iscollection(statictype, runtimetype)
310312

311-
if issubclass(T, typing.Callable) or get_origin(T) is collections.abc.Callable:
313+
if safeissubclass(T, typing.Callable) or get_origin(T) is collections.abc.Callable:
312314
if not callable(value):
313315
return False
314316
return True

0 commit comments

Comments
 (0)