Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion Lib/test/test_typing.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -3149,6 +3149,21 @@ def x(self): ...
with self.assertRaisesRegex(TypeError, only_classes_allowed):
issubclass(1, BadPG)

def test_isinstance_against_superproto_doesnt_affect_subproto_instance(self):
@runtime_checkable
class Base(Protocol):
x: int

@runtime_checkable
class Child(Base, Protocol):
y: str

class Capybara:
x = 43

self.assertIsInstance(Capybara(), Base)
self.assertNotIsInstance(Capybara(), Child)

def test_implicit_issubclass_between_two_protocols(self):
@runtime_checkable
class CallableMembersProto(Protocol):
Expand DownExpand Up@@ -6323,7 +6338,7 @@ def test_lazy_import(self):
"inspect",
"re",
"contextlib",
# "annotationlib", # TODO
"annotationlib",
})


Expand Down
29 changes: 18 additions & 11 deletions Lib/typing.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1801,9 +1801,13 @@ def _get_protocol_attrs(cls):
for base in cls.__mro__[:-1]: # without object
if base.__name__ in{'Protocol', 'Generic'}:
continue
annotations = _lazy_annotationlib.get_annotations(
base, format=_lazy_annotationlib.Format.FORWARDREF
)
try:
annotations = base.__annotations__
except Exception:
# Only go through annotationlib to handle deferred annotations if we need to
annotations = _lazy_annotationlib.get_annotations(
base, format=_lazy_annotationlib.Format.FORWARDREF
)
for attr in (*base.__dict__, *annotations):
if not attr.startswith('_abc_') and attr not in EXCLUDED_ATTRIBUTES:
attrs.add(attr)
Expand DownExpand Up@@ -2020,14 +2024,17 @@ def _proto_hook(cls, other):
break

# ...or in annotations, if it is a sub-protocol.
if (
issubclass(other, Generic)
and getattr(other, "_is_protocol", False)
and attr in _lazy_annotationlib.get_annotations(
base, format=_lazy_annotationlib.Format.FORWARDREF
)
):
break
if issubclass(other, Generic) and getattr(other, "_is_protocol", False):
# We avoid the slower path through annotationlib here because in most
# cases it should be unnecessary.
try:
annos = base.__annotations__
except Exception:
annos = _lazy_annotationlib.get_annotations(
base, format=_lazy_annotationlib.Format.FORWARDREF
)
if attr in annos:
break
else:
return NotImplemented
return True
Expand Down
Loading