Skip to content

Commit afabbbd

Browse files
authored
Allow Protocols to inherit from typing_extensions.Buffer or collections.abc.Buffer (#220)
1 parent ed09c9f commit afabbbd

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
- Fix tests on Python 3.13, which removes support for creating
55
`TypedDict` classes through the keyword-argument syntax. Patch by
66
Jelle Zijlstra.
7+
- Allow `Protocol` classes to inherit from `typing_extensions.Buffer` or
8+
`collections.abc.Buffer`. Patch by Alex Waygood (backporting
9+
https://github.com/python/cpython/pull/104827, by Jelle Zijlstra).
710

811
# Release 4.6.3 (June 1, 2023)
912

src/test_typing_extensions.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2737,6 +2737,28 @@ def close(self):
27372737
self.assertIsSubclass(B, Custom)
27382738
self.assertNotIsSubclass(A, Custom)
27392739

2740+
@skipUnless(
2741+
hasattr(collections.abc, "Buffer"),
2742+
"needs collections.abc.Buffer to exist"
2743+
)
2744+
@skip_if_py312b1
2745+
def test_collections_abc_buffer_protocol_allowed(self):
2746+
@runtime_checkable
2747+
class ReleasableBuffer(collections.abc.Buffer, Protocol):
2748+
def __release_buffer__(self, mv: memoryview) -> None: ...
2749+
2750+
class C: pass
2751+
class D:
2752+
def __buffer__(self, flags: int) -> memoryview:
2753+
return memoryview(b'')
2754+
def __release_buffer__(self, mv: memoryview) -> None:
2755+
pass
2756+
2757+
self.assertIsSubclass(D, ReleasableBuffer)
2758+
self.assertIsInstance(D(), ReleasableBuffer)
2759+
self.assertNotIsSubclass(C, ReleasableBuffer)
2760+
self.assertNotIsInstance(C(), ReleasableBuffer)
2761+
27402762
def test_builtin_protocol_allowlist(self):
27412763
with self.assertRaises(TypeError):
27422764
class CustomProtocol(TestCase, Protocol):
@@ -2745,6 +2767,24 @@ class CustomProtocol(TestCase, Protocol):
27452767
class CustomContextManager(typing.ContextManager, Protocol):
27462768
pass
27472769

2770+
@skip_if_py312b1
2771+
def test_typing_extensions_protocol_allowlist(self):
2772+
@runtime_checkable
2773+
class ReleasableBuffer(Buffer, Protocol):
2774+
def __release_buffer__(self, mv: memoryview) -> None: ...
2775+
2776+
class C: pass
2777+
class D:
2778+
def __buffer__(self, flags: int) -> memoryview:
2779+
return memoryview(b'')
2780+
def __release_buffer__(self, mv: memoryview) -> None:
2781+
pass
2782+
2783+
self.assertIsSubclass(D, ReleasableBuffer)
2784+
self.assertIsInstance(D(), ReleasableBuffer)
2785+
self.assertNotIsSubclass(C, ReleasableBuffer)
2786+
self.assertNotIsInstance(C(), ReleasableBuffer)
2787+
27482788
def test_non_runtime_protocol_isinstance_check(self):
27492789
class P(Protocol):
27502790
x: int

src/typing_extensions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,9 +453,10 @@ def clear_overloads():
453453
_PROTO_ALLOWLIST = {
454454
'collections.abc': [
455455
'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable',
456-
'Hashable', 'Sized', 'Container', 'Collection', 'Reversible',
456+
'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer',
457457
],
458458
'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'],
459+
'typing_extensions': ['Buffer'],
459460
}
460461

461462

0 commit comments

Comments
 (0)