gh-132493: Avoid eager import of annotationlib in typing (again) (#132596)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Jelle Zijlstra 2025-04-17 09:03:53 -07:00 committed by GitHub
parent e42bda9441
commit 5707837049
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 34 additions and 12 deletions

View file

@ -3149,6 +3149,21 @@ class ProtocolTests(BaseTestCase):
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):
@ -6323,7 +6338,7 @@ class InternalsTests(BaseTestCase):
"inspect",
"re",
"contextlib",
# "annotationlib", # TODO
"annotationlib",
})

View file

@ -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)
@ -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