]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-132493: Avoid eager import of annotationlib in typing (again) (#132596)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Thu, 17 Apr 2025 16:03:53 +0000 (09:03 -0700)
committerGitHub <noreply@github.com>
Thu, 17 Apr 2025 16:03:53 +0000 (16:03 +0000)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Lib/test/test_typing.py
Lib/typing.py

index 81474a81be645d2f4284a9e744f30c0c60a45c6b..4fd3d53b72c01bb5fd85af3f9f2a7687ac076fbe 100644 (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",
         })
 
 
index 245592b5678957becf0723036a3e6501c7723287..f70dcd0b5b7b5c1ffcf73b2e7d01eef50f9d2000 100644 (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