Yes, I think that’s better for starting with the Python behaviour.
It is challenging to follow what exactly is happening with wrapping in amemoryview. However, these specifications always need careful reading, and one’s interpretation to be checked with the reference implementation.
What I expect to see in a hypothetical referenceslot_bf_buffer, for example, is code that begins likevectorcall_method(&_Py_ID(__buffer__), ...) and discards thememoryview wrapper it gets back. And inslot_bf_buffer_release I expect code that synthesises a newmemoryview wrapper around the passedPy_buffer.
This doesn’t seem quite what is implied by:
When this method is invoked through the buffer API (for example, throughmemoryview.release), the passedmemoryview is the same object as was returned by__buffer__.
The signatures ofslot_bf_buffer andslot_bf_buffer_release are:
typedef int (*getbufferproc)(PyObject *, Py_buffer *, int);typedef void (*releasebufferproc)(PyObject *, Py_buffer *);
so there is no opportunity to guarantee as you have inMyBuffer.__realease_buffer__ that:
def __release_buffer__(self, view: memoryview) -> None: assert self.view is view # guaranteed to be true ...
If I use thePython API, calling__buffer__and__release_buffer__ myself, then I have to pass exactly thememoryview I received, since I have no other way to be sure I an returning the samePy_buffer. But whenmemoryview.release does this to a buffer object defined in Python, it will call the slot containingslot_bf_buffer_release and the buffer object in Python will receive the new ephemeralmemoryview.