From: Alex Waygood Date: Thu, 18 May 2023 23:34:40 +0000 (+0100) Subject: gh-74690: Don't set special protocol attributes on non-protocol subclasses of protoco... X-Git-Tag: v3.12.0b1~65 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f7835fc7e9617cefd87e72002916e258f589c857;p=thirdparty%2FPython%2Fcpython.git gh-74690: Don't set special protocol attributes on non-protocol subclasses of protocols (#104622) Don't set special protocol attributes on non-protocol subclasses of protocols --- diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index bf038bf143a6..450c85967dd7 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -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 diff --git a/Lib/typing.py b/Lib/typing.py index 91b5fe5b87e6..b60eb94351f9 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -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 (