diff --git a/pep-0688.rst b/pep-0688.rst index 779d33b12..38c3fc05a 100644 --- a/pep-0688.rst +++ b/pep-0688.rst @@ -122,14 +122,16 @@ object, for example by the ``memoryview()`` constructor. It corresponds to the ``bf_getbuffer`` C slot. The Python signature for this method is ``def __buffer__(self, flags: int, /) -> memoryview: ...``. The method -must return a ``memoryview`` object. If the method is called from C -code, the interpreter extracts the underlying ``Py_buffer`` from the -``memoryview`` and returns it to the C caller. Similarly, if the -``__buffer__`` method is called on an instance of a C class that +must return a ``memoryview`` object. If the ``bf_getbuffer`` slot +is invoked on a Python class with a ``__buffer__`` method, +the interpreter extracts the underlying ``Py_buffer`` from the +``memoryview`` returned by the method +and returns it to the C caller. Similarly, if Python code calls the +``__buffer__`` method on an instance of a C class that implements ``bf_getbuffer``, the returned buffer is wrapped in a ``memoryview`` for consumption by Python code. -The ``__release_buffer__`` method is called when a caller no +The ``__release_buffer__`` method should be called when a caller no longer needs the buffer returned by ``__buffer__``. It corresponds to the ``bf_releasebuffer`` C slot. This is an optional part of the buffer protocol. @@ -137,11 +139,30 @@ The Python signature for this method is ``def __release_buffer__(self, buffer: memoryview, /) -> None: ...``. The buffer to be released is wrapped in a ``memoryview``. When this method is invoked through CPython's buffer API (for example, through -``memoryview.release``), the passed ``memoryview`` is the same object +calling ``memoryview.release`` on a ``memoryview`` returned by +``__buffer__``), the passed ``memoryview`` is the same object as was returned by ``__buffer__``. It is also possible to call ``__release_buffer__`` on a C class that implements ``bf_releasebuffer``. +If ``__release_buffer__`` exists on an object, +Python code that calls ``__buffer__`` directly on the object must +call ``__release_buffer__`` on the same object when it is done +with the buffer. Otherwise, resources used by the object may +not be reclaimed. Similarly, it is a programming error +to call ``__release_buffer__`` without a previous call to +``__buffer__``, or to call it multiple times for a single call +to ``__buffer__``. For objects that implement the C buffer protocol, +calls to ``__release_buffer__`` where the argument is not a +``memoryview`` wrapping the same object will raise an exception. +After a valid call to ``__release_buffer__``, the ``memoryview`` +is invalidated (as if its ``release()`` method had been called), +and any subsequent calls to ``__release_buffer__`` with the same +``memoryview`` will raise an exception. +The interpreter will ensure that misuse +of the Python API will not break invariants at the C level -- for +example, it will not cause memory safety violations. + ``inspect.BufferFlags`` -----------------------