Skip to content

Commit a522554

Browse files
authored
Fix isinstance() with generic protocol subclasses after subscripting (#669)
Fixes #656 The problem is if a generic class inherits from a protocol, then `GenericMeta.__subclasscheck__()` gets overridden with `_ProtocolMeta.__subclasscheck__()` that calls the former via `super()`, thus causing an extra frame.
1 parent 00522c4 commit a522554

2 files changed

Lines changed: 32 additions & 8 deletions

File tree

‎python2/test_typing.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,27 @@ def __init__(self, x):
749749
self.assertIsInstance(C(1), P)
750750
self.assertIsInstance(C(1), PG)
751751

752+
def test_protocol_checks_after_subscript(self):
753+
class P(Protocol[T]): pass
754+
class C(P[T]): pass
755+
class Old1: pass
756+
class New1(object): pass
757+
class Old2: pass
758+
class New2(object): pass
759+
CA = C[Any] # noqa
760+
761+
self.assertNotIsInstance(Old1(), C)
762+
self.assertNotIsInstance(New1(), C)
763+
self.assertNotIsSubclass(Old2, C)
764+
self.assertNotIsSubclass(New2, C)
765+
766+
class D1(C[Any]): pass
767+
class D2(C[Any]): pass
768+
CI = C[int] # noqa
769+
770+
self.assertIsInstance(D1(), C)
771+
self.assertIsSubclass(D2, C)
772+
752773
def test_protocols_support_register(self):
753774
@runtime_checkable
754775
class P(Protocol):

‎python2/typing.py‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,14 +1393,17 @@ def __getitem__(self, params):
13931393

13941394
def __subclasscheck__(self, cls):
13951395
if self.__origin__ is not None:
1396-
# This should only be modules within the standard
1397-
# library. singledispatch is the only exception, because
1398-
# it's a Python 2 backport of functools.singledispatch.
1399-
if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools',
1400-
'singledispatch']:
1401-
raise TypeError("Parameterized generics cannot be used with class "
1402-
"or instance checks")
1403-
return False
1396+
# These should only be modules within the standard library.
1397+
# singledispatch is an exception, because it's a Python 2 backport
1398+
# of functools.singledispatch.
1399+
whitelist = ['abc', 'functools', 'singledispatch']
1400+
if (sys._getframe(1).f_globals['__name__'] in whitelist or
1401+
# The second frame is needed for the case where we came
1402+
# from _ProtocolMeta.__subclasscheck__.
1403+
sys._getframe(2).f_globals['__name__'] in whitelist):
1404+
return False
1405+
raise TypeError("Parameterized generics cannot be used with class "
1406+
"or instance checks")
14041407
if self is Generic:
14051408
raise TypeError("Class %r cannot be used with class "
14061409
"or instance checks" % self)

0 commit comments

Comments
 (0)