8000 gh-132493: Avoid eager import of annotationlib in typing (again) (#13… · python/cpython@5707837 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5707837

Browse files
gh-132493: Avoid eager import of annotationlib in typing (again) (#132596)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
1 parent e42bda9 commit 5707837

File tree

2 files changed

+34
-12
lines changed

2 files changed

+34
-12
lines changed

Lib/test/test_typing.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3149,6 +3149,21 @@ def x(self): ...
31493149
with self.assertRaisesRegex(TypeError, only_classes_allowed):
31503150
issubclass(1, BadPG)
31513151

3152+
def test_isinstance_against_superproto_doesnt_affect_subproto_instance(self):
3153+
@runtime_checkable
3154+
class Base(Protocol):
3155+
x: int
3156+
3157+
@runtime_checkable
3158+
class Child(Base, Protocol):
3159+
y: str
3160+
3161+
class Capybara:
3162+
x = 43
3163+
3164+
self.assertIsInstance(Capybara(), Base)
3165+
self.assertNotIsInstance(Capybara(), Child)
3166+
31523167
def test_implicit_issubclass_between_two_protocols(self):
31533168
@runtime_checkable
31543169
class CallableMembersProto(Protocol):
@@ -6323,7 +6338,7 @@ def test_lazy_import(self):
63236338
"inspect",
63246339
"re",
63256340
"contextlib",
6326-
# "annotationlib", # TODO
6341+
"annotationlib",
63276342
})
63286343

63296344

Lib/typing.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,9 +1801,13 @@ def _get_protocol_attrs(cls):
18011801
for base in cls.__mro__[:-1]: # without object
18021802
if base.__name__ in {'Protocol', 'Generic'}:
18031803
continue
1804-
annotations = _lazy_annotationlib.get_annotations(
1805-
base, format=_lazy_annotationlib.Format.FORWARDREF
1806-
)
1804+
try:
1805+
annotations = base.__annotations__
1806+
except Exception:
1807+
# Only go through annotationlib to handle deferred annotations if we need to
1808+
annotations = _lazy_annotationlib.get_annotations(
1809+
base, format=_lazy_annotationlib.Format.FORWARDREF
1810+
)
18071811
for attr in (*base.__dict__, *annotations):
18081812
if not attr.startswith('_abc_') and attr not in EXCLUDED_ATTRIBUTES:
18091813
attrs.add(attr)
@@ -2020,14 +2024,17 @@ def _proto_hook(cls, other):
20202024
break
20212025

20222026
# ...or in annotations, if it is a sub-protocol.
2023-
if (
2024-
issubclass(other, Generic)
2025-
and getattr(other, "_is_protocol", False)
2026-
and attr in _lazy_annotationlib.get_annotations(
2027-
base, format=_lazy_annotationlib.Format.FORWARDREF
2028-
)
2029-
):
2030-
break
2027+
if issubclass(other, Generic) and getattr(other, "_is_protocol", False):
2028+
# We avoid the slower path through annotationlib here because in most
2029+
# cases it should be unnecessary.
2030+
try:
2031+
annos = base.__annotations__
2032+
except Exception:
2033+
annos = _lazy_annotationlib.get_annotations(
2034+
base, format=_lazy_annotationlib.Format.FORWARDREF
2035+
)
2036+
if attr in annos:
2037+
break
20312038
else:
20322039
return NotImplemented
20332040
return True

0 commit comments

Comments
 (0)
0