]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-74690: Don't set special protocol attributes on non-protocol subclasses of protoco...
authorAlex Waygood <Alex.Waygood@Gmail.com>
Thu, 18 May 2023 23:34:40 +0000 (00:34 +0100)
committerGitHub <noreply@github.com>
Thu, 18 May 2023 23:34:40 +0000 (00:34 +0100)
Don't set special protocol attributes on non-protocol subclasses of protocols

Lib/test/test_typing.py
Lib/typing.py

index bf038bf143a6c8075d57513723ef9c1f12d05eca..450c85967dd75a872bfd65d76ba9731eb944dc52 100644 (file)
@@ -3167,6 +3167,21 @@ class ProtocolTests(BaseTestCase):
         self.assertIsInstance(NonPR(), PR)
         self.assertIsSubclass(NonPR, PR)
 
+        self.assertNotIn("__protocol_attrs__", vars(NonP))
+        self.assertNotIn("__protocol_attrs__", vars(NonPR))
+        self.assertNotIn("__callable_proto_members_only__", vars(NonP))
+        self.assertNotIn("__callable_proto_members_only__", vars(NonPR))
+
+        acceptable_extra_attrs = {
+            '_is_protocol', '_is_runtime_protocol', '__parameters__',
+            '__subclasshook__', '__abstractmethods__', '_abc_impl',
+            '__init__', '__annotations__',
+        }
+        self.assertLessEqual(vars(NonP).keys(), vars(C).keys() | acceptable_extra_attrs)
+        self.assertLessEqual(
+            vars(NonPR).keys(), vars(D).keys() | acceptable_extra_attrs
+        )
+
     def test_custom_subclasshook(self):
         class P(Protocol):
             x = 1
index 91b5fe5b87e6691ddfdb4af78e0d6a964b184a4e..b60eb94351f9bb29e19cb89f3095e97dc40ff539 100644 (file)
@@ -1779,12 +1779,13 @@ class _ProtocolMeta(ABCMeta):
     # but is necessary for several reasons...
     def __init__(cls, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        cls.__protocol_attrs__ = _get_protocol_attrs(cls)
-        # PEP 544 prohibits using issubclass()
-        # with protocols that have non-method members.
-        cls.__callable_proto_members_only__ = all(
-            callable(getattr(cls, attr, None)) for attr in cls.__protocol_attrs__
-        )
+        if getattr(cls, "_is_protocol", False):
+            cls.__protocol_attrs__ = _get_protocol_attrs(cls)
+            # PEP 544 prohibits using issubclass()
+            # with protocols that have non-method members.
+            cls.__callable_proto_members_only__ = all(
+                callable(getattr(cls, attr, None)) for attr in cls.__protocol_attrs__
+            )
 
     def __subclasscheck__(cls, other):
         if (