Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 17, 2025
Merged
17 changes: 16 additions & 1 deletion 17 Lib/test/test_typing.py
Original file line number Diff line number Diff 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):
AlexWaygood marked this conversation as resolved.
Show resolved Hide resolved
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 Down Expand Up @@ -6323,7 +6338,7 @@ def test_lazy_import(self):
"inspect",
"re",
"contextlib",
# "annotationlib", # TODO
"annotationlib",
})


Expand Down
29 changes: 18 additions & 11 deletions 29 Lib/typing.py
Original file line number Diff line number Diff 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 Down Expand 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:
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved
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
Morty Proxy This is a proxified and sanitized view of the page, visit original site.