From 0e124fcf5946cdfd979889bde9ab62f611200197 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 7 Jun 2023 23:25:17 +0100 Subject: [PATCH] gh-103171: Forward-port new tests for runtime-checkable protocols dec orated with `@final` (GH-105473) Forward-port of the tests that were added to the 3.11 branch in GH-105445 (cherry picked from commit f5df347fcf5fe029edbe6bf274da0f4880401852) Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 65 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ef1db06109eca3..74480891fb50d4 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3800,6 +3800,71 @@ class Foo(typing.Sized, Protocol): pass # before any isinstance() checks against Sized self.assertNotIsInstance(1, typing.Sized) + 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):