From c429caa178de3dfae3a1d5a0983f5bc20771b955 Mon Sep 17 00:00:00 2001 From: Divij Rajkumar Date: Mon, 2 Sep 2019 07:55:19 -0700 Subject: [PATCH 1/3] Move builtin protocol whitelist to mapping instead of list --- Lib/typing.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py index 5f1a0ad3d63743..cff0f19f9e1484 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -989,10 +989,21 @@ def _allow_reckless_class_cheks(): return True -_PROTO_WHITELIST = ['Callable', 'Awaitable', - 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', - 'ContextManager', 'AsyncContextManager'] +_PROTO_WHITELIST = { + 'Callable': 'collections.abc', + 'Awaitable': 'collections.abc', + 'Iterable': 'collections.abc', + 'Iterator': 'collections.abc', + 'AsyncIterable': 'collections.abc', + 'AsyncIterator': 'collections.abc', + 'Hashable': 'collections.abc', + 'Sized': 'collections.abc', + 'Container': 'collections.abc', + 'Collection': 'collections.abc', + 'Reversible': 'collections.abc', + 'AbstractContextManager': 'contextlib', + 'AbstractAsyncContextManager': 'contextlib', +} class _ProtocolMeta(ABCMeta): @@ -1105,7 +1116,8 @@ def _proto_hook(other): # ... otherwise check consistency of bases, and prohibit instantiation. for base in cls.__bases__: if not (base in (object, Generic) or - base.__module__ == 'collections.abc' and base.__name__ in _PROTO_WHITELIST or + base.__name__ in _PROTO_WHITELIST and + base.__module__ == _PROTO_WHITELIST[base.__name__] or issubclass(base, Generic) and base._is_protocol): raise TypeError('Protocols can only inherit from other' ' protocols, got %r' % base) From b9acc9886d29bec53d4a527f6d16044ce5aeba51 Mon Sep 17 00:00:00 2001 From: Divij Rajkumar Date: Thu, 12 Sep 2019 02:43:30 -0700 Subject: [PATCH 2/3] Add test, news entry, switch whitelist key to be module --- Lib/test/test_typing.py | 8 +++++++ Lib/typing.py | 22 ++++++------------- .../2019-09-12-10-28.bpo-38008.sH74Iy.rst | 3 +++ 3 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-09-12-10-28.bpo-38008.sH74Iy.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ba0800fae90e30..3402996b2d2e0a 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1381,6 +1381,14 @@ def close(self): self.assertIsSubclass(B, Custom) self.assertNotIsSubclass(A, Custom) + def test_builtin_protocol_whitelist(self): + with self.assertRaises(TypeError): + class CustomProtocol(TestCase, Protocol): + pass + + class CustomContextManager(typing.ContextManager, Protocol): + pass + class GenericTests(BaseTestCase): def test_basics(self): diff --git a/Lib/typing.py b/Lib/typing.py index cff0f19f9e1484..7b07112c3abf84 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -990,19 +990,11 @@ def _allow_reckless_class_cheks(): _PROTO_WHITELIST = { - 'Callable': 'collections.abc', - 'Awaitable': 'collections.abc', - 'Iterable': 'collections.abc', - 'Iterator': 'collections.abc', - 'AsyncIterable': 'collections.abc', - 'AsyncIterator': 'collections.abc', - 'Hashable': 'collections.abc', - 'Sized': 'collections.abc', - 'Container': 'collections.abc', - 'Collection': 'collections.abc', - 'Reversible': 'collections.abc', - 'AbstractContextManager': 'contextlib', - 'AbstractAsyncContextManager': 'contextlib', + 'collections.abc': [ + 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', + ], + 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], } @@ -1116,8 +1108,8 @@ def _proto_hook(other): # ... otherwise check consistency of bases, and prohibit instantiation. for base in cls.__bases__: if not (base in (object, Generic) or - base.__name__ in _PROTO_WHITELIST and - base.__module__ == _PROTO_WHITELIST[base.__name__] or + base.__module__ in _PROTO_WHITELIST and + base.__name__ in _PROTO_WHITELIST[base.__module__] or issubclass(base, Generic) and base._is_protocol): raise TypeError('Protocols can only inherit from other' ' protocols, got %r' % base) diff --git a/Misc/NEWS.d/next/Library/2019-09-12-10-28.bpo-38008.sH74Iy.rst b/Misc/NEWS.d/next/Library/2019-09-12-10-28.bpo-38008.sH74Iy.rst new file mode 100644 index 00000000000000..f696707eadf74e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-09-12-10-28.bpo-38008.sH74Iy.rst @@ -0,0 +1,3 @@ +Fix parent class check in protocols to correctly identify the module that +provides a builtin protocol, instead of assuming they all come from the +:mod:`collections.abc` module From ee6f4494cffdfdabe8e468787b0e556e94cdcf3d Mon Sep 17 00:00:00 2001 From: Divij Rajkumar Date: Thu, 12 Sep 2019 02:47:58 -0700 Subject: [PATCH 3/3] Correctly format news file name --- ...-38008.sH74Iy.rst => 2019-09-12-10-47-34.bpo-38008.sH74Iy.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Misc/NEWS.d/next/Library/{2019-09-12-10-28.bpo-38008.sH74Iy.rst => 2019-09-12-10-47-34.bpo-38008.sH74Iy.rst} (100%) diff --git a/Misc/NEWS.d/next/Library/2019-09-12-10-28.bpo-38008.sH74Iy.rst b/Misc/NEWS.d/next/Library/2019-09-12-10-47-34.bpo-38008.sH74Iy.rst similarity index 100% rename from Misc/NEWS.d/next/Library/2019-09-12-10-28.bpo-38008.sH74Iy.rst rename to Misc/NEWS.d/next/Library/2019-09-12-10-47-34.bpo-38008.sH74Iy.rst