From 485f9617fd208f8cd48630911acc888a0394be91 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Sun, 4 Jun 2023 17:36:26 +0100 Subject: [PATCH 1/3] Allow Protocols to inherit from typing_extensions.Buffer --- CHANGELOG.md | 3 +++ src/test_typing_extensions.py | 17 +++++++++++++++++ src/typing_extensions.py | 1 + 3 files changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39bf2b53..0d42632a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ - Fix tests on Python 3.13, which removes support for creating `TypedDict` classes through the keyword-argument syntax. Patch by Jelle Zijlstra. +- Allow `Protocol` classes to inherit from `typing_extensions.Buffer`. Patch by + Alex Waygood (backporting https://github.com/python/cpython/pull/104827, by + Jelle Zijlstra). # Release 4.6.3 (June 1, 2023) diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index a9fdcc0f..ac3f58fd 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -2745,6 +2745,23 @@ class CustomProtocol(TestCase, Protocol): class CustomContextManager(typing.ContextManager, Protocol): pass + def test_typing_extensions_protocol_allowlist(self): + @runtime_checkable + class ReleasableBuffer(Buffer, Protocol): + def __release_buffer__(self, mv: memoryview) -> None: ... + + class C: pass + class D: + def __buffer__(self, flags: int) -> memoryview: + return memoryview(b'') + def __release_buffer__(self, mv: memoryview) -> None: + pass + + self.assertIsSubclass(D, ReleasableBuffer) + self.assertIsInstance(D(), ReleasableBuffer) + self.assertNotIsSubclass(C, ReleasableBuffer) + self.assertNotIsInstance(C(), ReleasableBuffer) + def test_non_runtime_protocol_isinstance_check(self): class P(Protocol): x: int diff --git a/src/typing_extensions.py b/src/typing_extensions.py index 1b92c396..5092f13f 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -456,6 +456,7 @@ def clear_overloads(): 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', ], 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], + 'typing_extensions': ['Buffer'], } From f916c86779fc65c003e7bbe70aa68e7429bc40e8 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sun, 4 Jun 2023 17:38:09 +0100 Subject: [PATCH 2/3] Update src/test_typing_extensions.py --- src/test_typing_extensions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index ac3f58fd..3e6c2a7d 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -2745,6 +2745,7 @@ class CustomProtocol(TestCase, Protocol): class CustomContextManager(typing.ContextManager, Protocol): pass + @skip_if_py312b1 def test_typing_extensions_protocol_allowlist(self): @runtime_checkable class ReleasableBuffer(Buffer, Protocol): From b5fdf5f0703705763bc207cad047f7d4aad961ac Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Sun, 4 Jun 2023 17:47:30 +0100 Subject: [PATCH 3/3] Also allow collections.abc.Buffer if it exists --- CHANGELOG.md | 6 +++--- src/test_typing_extensions.py | 22 ++++++++++++++++++++++ src/typing_extensions.py | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d42632a..13a9c3fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,9 @@ - Fix tests on Python 3.13, which removes support for creating `TypedDict` classes through the keyword-argument syntax. Patch by Jelle Zijlstra. -- Allow `Protocol` classes to inherit from `typing_extensions.Buffer`. Patch by - Alex Waygood (backporting https://github.com/python/cpython/pull/104827, by - Jelle Zijlstra). +- Allow `Protocol` classes to inherit from `typing_extensions.Buffer` or + `collections.abc.Buffer`. Patch by Alex Waygood (backporting + https://github.com/python/cpython/pull/104827, by Jelle Zijlstra). # Release 4.6.3 (June 1, 2023) diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index ac3f58fd..944adf21 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -2737,6 +2737,28 @@ def close(self): self.assertIsSubclass(B, Custom) self.assertNotIsSubclass(A, Custom) + @skipUnless( + hasattr(collections.abc, "Buffer"), + "needs collections.abc.Buffer to exist" + ) + @skip_if_py312b1 + def test_collections_abc_buffer_protocol_allowed(self): + @runtime_checkable + class ReleasableBuffer(collections.abc.Buffer, Protocol): + def __release_buffer__(self, mv: memoryview) -> None: ... + + class C: pass + class D: + def __buffer__(self, flags: int) -> memoryview: + return memoryview(b'') + def __release_buffer__(self, mv: memoryview) -> None: + pass + + self.assertIsSubclass(D, ReleasableBuffer) + self.assertIsInstance(D(), ReleasableBuffer) + self.assertNotIsSubclass(C, ReleasableBuffer) + self.assertNotIsInstance(C(), ReleasableBuffer) + def test_builtin_protocol_allowlist(self): with self.assertRaises(TypeError): class CustomProtocol(TestCase, Protocol): diff --git a/src/typing_extensions.py b/src/typing_extensions.py index 5092f13f..5ac6dcf2 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -453,7 +453,7 @@ def clear_overloads(): _PROTO_ALLOWLIST = { 'collections.abc': [ 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer', ], 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], 'typing_extensions': ['Buffer'],