diff --git a/CHANGELOG.md b/CHANGELOG.md index d330a0f5..d4bc0322 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# Unreleased + +- Add `typing_extensions.Buffer`, a marker class for buffer types, as proposed + by PEP 688. Equivalent to `collections.abc.Buffer` in Python 3.12. Patch by + Jelle Zijlstra. + # Release 4.5.0 (February 14, 2023) - Runtime support for PEP 702, adding `typing_extensions.deprecated`. Patch diff --git a/README.md b/README.md index 6da36c37..b29378ba 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,15 @@ This module currently contains the following: - Experimental features - - `override` (see [PEP 698](https://peps.python.org/pep-0698/)) - The `default=` argument to `TypeVar`, `ParamSpec`, and `TypeVarTuple` (see [PEP 696](https://peps.python.org/pep-0696/)) - The `infer_variance=` argument to `TypeVar` (see [PEP 695](https://peps.python.org/pep-0695/)) - The `@deprecated` decorator (see [PEP 702](https://peps.python.org/pep-0702/)) +- In the standard library since Python 3.12 + + - `override` (equivalent to `typing.override`; see [PEP 698](https://peps.python.org/pep-0698/)) + - `Buffer` (equivalent to `collections.abc.Buffer`; see [PEP 688](https://peps.python.org/pep-0688/)) + - In `typing` since Python 3.11 - `assert_never` @@ -159,4 +163,4 @@ These types are only guaranteed to work for static type checking. ## Running tests To run tests, navigate into the appropriate source directory and run -`test_typing_extensions.py`. \ No newline at end of file +`test_typing_extensions.py`. diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index 7f9e59ae..b4e21d63 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -29,7 +29,7 @@ from typing_extensions import assert_type, get_type_hints, get_origin, get_args from typing_extensions import clear_overloads, get_overloads, overload from typing_extensions import NamedTuple -from typing_extensions import override, deprecated +from typing_extensions import override, deprecated, Buffer from _typed_dict_test_helper import Foo, FooGeneric import warnings @@ -3677,5 +3677,35 @@ def test_pickle(self): self.assertEqual(z.__infer_variance__, typevar.__infer_variance__) +class BufferTests(BaseTestCase): + def test(self): + self.assertIsInstance(memoryview(b''), Buffer) + self.assertIsInstance(bytearray(), Buffer) + self.assertIsInstance(b"x", Buffer) + self.assertNotIsInstance(1, Buffer) + + self.assertIsSubclass(bytearray, Buffer) + self.assertIsSubclass(memoryview, Buffer) + self.assertIsSubclass(bytes, Buffer) + self.assertNotIsSubclass(int, Buffer) + + class MyRegisteredBuffer: + def __buffer__(self, flags: int) -> memoryview: + return memoryview(b'') + + self.assertNotIsInstance(MyRegisteredBuffer(), Buffer) + self.assertNotIsSubclass(MyRegisteredBuffer, Buffer) + Buffer.register(MyRegisteredBuffer) + self.assertIsInstance(MyRegisteredBuffer(), Buffer) + self.assertIsSubclass(MyRegisteredBuffer, Buffer) + + class MySubclassedBuffer(Buffer): + def __buffer__(self, flags: int) -> memoryview: + return memoryview(b'') + + self.assertIsInstance(MySubclassedBuffer(), Buffer) + self.assertIsSubclass(MySubclassedBuffer, Buffer) + + if __name__ == '__main__': main() diff --git a/src/typing_extensions.py b/src/typing_extensions.py index 6ae0c34c..7704bc95 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -33,6 +33,7 @@ 'Coroutine', 'AsyncGenerator', 'AsyncContextManager', + 'Buffer', 'ChainMap', # Concrete collection types. @@ -2310,3 +2311,32 @@ def _namedtuple_mro_entries(bases): return (_NamedTuple,) NamedTuple.__mro_entries__ = _namedtuple_mro_entries + + +if hasattr(collections.abc, "Buffer"): + Buffer = collections.abc.Buffer +else: + class Buffer(abc.ABC): + """Base class for classes that implement the buffer protocol. + + The buffer protocol allows Python objects to expose a low-level + memory buffer interface. Before Python 3.12, it is not possible + to implement the buffer protocol in pure Python code, or even + to check whether a class implements the buffer protocol. In + Python 3.12 and higher, the ``__buffer__`` method allows access + to the buffer protocol from Python code, and the + ``collections.abc.Buffer`` ABC allows checking whether a class + implements the buffer protocol. + + To indicate support for the buffer protocol in earlier versions, + inherit from this ABC, either in a stub file or at runtime, + or use ABC registration. This ABC provides no methods, because + there is no Python-accessible methods shared by pre-3.12 buffer + classes. It is useful primarily for static checks. + + """ + + # As a courtesy, register the most common stdlib buffer classes. + Buffer.register(memoryview) + Buffer.register(bytearray) + Buffer.register(bytes)