Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2759,6 +2759,54 @@ def x(self): ...
with self.assertRaisesRegex(TypeError, only_classes_allowed):
issubclass(1, BadPG)

def test_implicit_issubclass_between_two_protocols(self):
@runtime_checkable
class CallableMembersProto(Protocol):
def meth(self): ...

# All the below protocols should be considered "subclasses"
# of CallableMembersProto at runtime,
# even though none of them explicitly subclass CallableMembersProto

class IdenticalProto(Protocol):
def meth(self): ...

class SupersetProto(Protocol):
def meth(self): ...
def meth2(self): ...

class NonCallableMembersProto(Protocol):
meth: Callable[[], None]

class NonCallableMembersSupersetProto(Protocol):
meth: Callable[[], None]
meth2: Callable[[str, int], bool]

class MixedMembersProto1(Protocol):
meth: Callable[[], None]
def meth2(self): ...

class MixedMembersProto2(Protocol):
def meth(self): ...
meth2: Callable[[str, int], bool]

for proto in (
IdenticalProto, SupersetProto, NonCallableMembersProto,
NonCallableMembersSupersetProto, MixedMembersProto1, MixedMembersProto2
):
with self.subTest(proto=proto.__name__):
self.assertIsSubclass(proto, CallableMembersProto)

# These two shouldn't be considered subclasses of CallableMembersProto, however,
# since they don't have the `meth` protocol member

class EmptyProtocol(Protocol): ...
class UnrelatedProtocol(Protocol):
def wut(self): ...

self.assertNotIsSubclass(EmptyProtocol, CallableMembersProto)
self.assertNotIsSubclass(UnrelatedProtocol, CallableMembersProto)

def test_isinstance_checks_not_at_whim_of_gc(self):
self.addCleanup(gc.enable)
gc.disable()
Expand Down