summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Waygood <Alex.Waygood@Gmail.com>2023-06-07 21:18:21 (GMT)
committerGitHub <noreply@github.com>2023-06-07 21:18:21 (GMT)
commit18e9fd80d956fd39ded581f91a9448aeff74b913 (patch)
treec257290237ab66f8f18031dcad797897177ee6da
parent2ffeb0ecc78499b52b8337073c70b569413295e0 (diff)
downloadcpython-18e9fd80d956fd39ded581f91a9448aeff74b913.zip
cpython-18e9fd80d956fd39ded581f91a9448aeff74b913.tar.gz
cpython-18e9fd80d956fd39ded581f91a9448aeff74b913.tar.bz2
[3.11] gh-103171: Revert undocumented behaviour change for runtime-checkable protocols decorated with `@final` (#105445)
-rw-r--r--Lib/test/test_typing.py65
-rw-r--r--Lib/typing.py2
-rw-r--r--Misc/NEWS.d/next/Library/2023-06-07-14-24-39.gh-issue-103171.b3VJMD.rst4
3 files changed, 70 insertions, 1 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 4dfe453..316b300 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -3349,6 +3349,71 @@ class ProtocolTests(BaseTestCase):
Foo() # Previously triggered RecursionError
+ def test_empty_protocol_decorated_with_final(self):
+ @final
+ @runtime_checkable
+ class EmptyProtocol(Protocol): ...
+
+ self.assertIsSubclass(object, EmptyProtocol)
+ self.assertIsInstance(object(), EmptyProtocol)
+
+ def test_protocol_decorated_with_final_callable_members(self):
+ @final
+ @runtime_checkable
+ class ProtocolWithMethod(Protocol):
+ def startswith(self, string: str) -> bool: ...
+
+ self.assertIsSubclass(str, ProtocolWithMethod)
+ self.assertNotIsSubclass(int, ProtocolWithMethod)
+ self.assertIsInstance('foo', ProtocolWithMethod)
+ self.assertNotIsInstance(42, ProtocolWithMethod)
+
+ def test_protocol_decorated_with_final_noncallable_members(self):
+ @final
+ @runtime_checkable
+ class ProtocolWithNonCallableMember(Protocol):
+ x: int
+
+ class Foo:
+ x = 42
+
+ only_callable_members_please = (
+ r"Protocols with non-method members don't support issubclass()"
+ )
+
+ with self.assertRaisesRegex(TypeError, only_callable_members_please):
+ issubclass(Foo, ProtocolWithNonCallableMember)
+
+ with self.assertRaisesRegex(TypeError, only_callable_members_please):
+ issubclass(int, ProtocolWithNonCallableMember)
+
+ self.assertIsInstance(Foo(), ProtocolWithNonCallableMember)
+ self.assertNotIsInstance(42, ProtocolWithNonCallableMember)
+
+ def test_protocol_decorated_with_final_mixed_members(self):
+ @final
+ @runtime_checkable
+ class ProtocolWithMixedMembers(Protocol):
+ x: int
+ def method(self) -> None: ...
+
+ class Foo:
+ x = 42
+ def method(self) -> None: ...
+
+ only_callable_members_please = (
+ r"Protocols with non-method members don't support issubclass()"
+ )
+
+ with self.assertRaisesRegex(TypeError, only_callable_members_please):
+ issubclass(Foo, ProtocolWithMixedMembers)
+
+ with self.assertRaisesRegex(TypeError, only_callable_members_please):
+ issubclass(int, ProtocolWithMixedMembers)
+
+ self.assertIsInstance(Foo(), ProtocolWithMixedMembers)
+ self.assertNotIsInstance(42, ProtocolWithMixedMembers)
+
class GenericTests(BaseTestCase):
diff --git a/Lib/typing.py b/Lib/typing.py
index e6ef344..f01b8c3 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1883,7 +1883,7 @@ class _TypingEllipsis:
_TYPING_INTERNALS = ['__parameters__', '__orig_bases__', '__orig_class__',
- '_is_protocol', '_is_runtime_protocol']
+ '_is_protocol', '_is_runtime_protocol', '__final__']
_SPECIAL_NAMES = ['__abstractmethods__', '__annotations__', '__dict__', '__doc__',
'__init__', '__module__', '__new__', '__slots__',
diff --git a/Misc/NEWS.d/next/Library/2023-06-07-14-24-39.gh-issue-103171.b3VJMD.rst b/Misc/NEWS.d/next/Library/2023-06-07-14-24-39.gh-issue-103171.b3VJMD.rst
new file mode 100644
index 0000000..8c424d4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-06-07-14-24-39.gh-issue-103171.b3VJMD.rst
@@ -0,0 +1,4 @@
+Revert undocumented behaviour change with runtime-checkable protocols
+decorated with :func:`typing.final` in Python 3.11. The behaviour change had
+meant that objects would not be considered instances of these protocols at
+runtime unless they had a ``__final__`` attribute. Patch by Alex Waygood.