Thanks to visit codestin.com
Credit goes to github.com

Skip to content

bpo-41103: Resurrect the old buffer protocol. #27437

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Doc/c-api/abstract.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ but whose items have not been set to some non-\ ``NULL`` value yet.
mapping.rst
iter.rst
buffer.rst
objbuffer.rst
55 changes: 55 additions & 0 deletions Doc/c-api/objbuffer.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.. highlight:: c

Old Buffer Protocol
-------------------

.. deprecated:: 3.0

These functions were part of the "old buffer protocol" API in Python 2.
In Python 3, this protocol doesn't exist anymore but the functions are still
exposed to ease porting 2.x code. They act as a compatibility wrapper
around the :ref:`new buffer protocol <bufferobjects>`, but they don't give
you control over the lifetime of the resources acquired when a buffer is
exported.

Therefore, it is recommended that you call :c:func:`PyObject_GetBuffer`
(or the ``y*`` or ``w*`` :ref:`format codes <arg-parsing>` with the
:c:func:`PyArg_ParseTuple` family of functions) to get a buffer view over
an object, and :c:func:`PyBuffer_Release` when the buffer view can be released.


.. c:function:: int PyObject_AsCharBuffer(PyObject *obj, const char **buffer, Py_ssize_t *buffer_len)

Returns a pointer to a read-only memory location usable as character-based
input. The *obj* argument must support the single-segment character buffer
interface. On success, returns ``0``, sets *buffer* to the memory location
and *buffer_len* to the buffer length. Returns ``-1`` and sets a
:exc:`TypeError` on error.


.. c:function:: int PyObject_AsReadBuffer(PyObject *obj, const void **buffer, Py_ssize_t *buffer_len)

Returns a pointer to a read-only memory location containing arbitrary data.
The *obj* argument must support the single-segment readable buffer
interface. On success, returns ``0``, sets *buffer* to the memory location
and *buffer_len* to the buffer length. Returns ``-1`` and sets a
:exc:`TypeError` on error.


.. c:function:: int PyObject_CheckReadBuffer(PyObject *o)

Returns ``1`` if *o* supports the single-segment readable buffer interface.
Otherwise returns ``0``. This function always succeeds.

Note that this function tries to get and release a buffer, and exceptions
which occur while calling corresponding functions will get suppressed.
To get error reporting use :c:func:`PyObject_GetBuffer()` instead.


.. c:function:: int PyObject_AsWriteBuffer(PyObject *obj, void **buffer, Py_ssize_t *buffer_len)

Returns a pointer to a writable memory location. The *obj* argument must
support the single-segment, character buffer interface. On success,
returns ``0``, sets *buffer* to the memory location and *buffer_len* to the
buffer length. Returns ``-1`` and sets a :exc:`TypeError` on error.

18 changes: 18 additions & 0 deletions Doc/data/refcounts.dat
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,21 @@ PyOS_FSPath:PyObject*:path:0:
PyObject_ASCII:PyObject*::+1:
PyObject_ASCII:PyObject*:o:0:

PyObject_AsCharBuffer:int:::
PyObject_AsCharBuffer:PyObject*:obj:0:
PyObject_AsCharBuffer:const char**:buffer::
PyObject_AsCharBuffer:Py_ssize_t*:buffer_len::

PyObject_AsReadBuffer:int:::
PyObject_AsReadBuffer:PyObject*:obj:0:
PyObject_AsReadBuffer:const void**:buffer::
PyObject_AsReadBuffer:Py_ssize_t*:buffer_len::

PyObject_AsWriteBuffer:int:::
PyObject_AsWriteBuffer:PyObject*:obj:0:
PyObject_AsWriteBuffer:void**:buffer::
PyObject_AsWriteBuffer:Py_ssize_t*:buffer_len::

PyObject_Bytes:PyObject*::+1:
PyObject_Bytes:PyObject*:o:0:

Expand Down Expand Up @@ -1606,6 +1621,9 @@ PyObject_CallObject:PyObject*:args:0:
PyObject_CheckBuffer:int:::
PyObject_CheckBuffer:PyObject*:obj:0:

PyObject_CheckReadBuffer:int:::
PyObject_CheckReadBuffer:PyObject*:o:0:

PyObject_DelAttr:int:::
PyObject_DelAttr:PyObject*:o:0:
PyObject_DelAttr:PyObject*:attr_name:0:
Expand Down
4 changes: 4 additions & 0 deletions Doc/data/stable_abi.dat
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,10 @@ function,PyOS_strtoul,3.2,
function,PyOS_vsnprintf,3.2,
type,PyObject,3.2,
function,PyObject_ASCII,3.2,
function,PyObject_AsCharBuffer,3.2,
function,PyObject_AsFileDescriptor,3.2,
function,PyObject_AsReadBuffer,3.2,
function,PyObject_AsWriteBuffer,3.2,
function,PyObject_Bytes,3.2,
function,PyObject_Call,3.2,
function,PyObject_CallFunction,3.2,
Expand All @@ -472,6 +475,7 @@ function,PyObject_CallMethodObjArgs,3.2,
function,PyObject_CallNoArgs,3.10,
function,PyObject_CallObject,3.2,
function,PyObject_Calloc,3.7,
function,PyObject_CheckReadBuffer,3.2,
function,PyObject_ClearWeakRefs,3.2,
function,PyObject_DelItem,3.2,
function,PyObject_DelItemString,3.2,
Expand Down
5 changes: 0 additions & 5 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2113,11 +2113,6 @@ Deprecated
Removed
-------

* ``PyObject_AsCharBuffer()``, ``PyObject_AsReadBuffer()``, ``PyObject_CheckReadBuffer()``,
and ``PyObject_AsWriteBuffer()`` are removed. Please migrate to new buffer protocol;
:c:func:`PyObject_GetBuffer` and :c:func:`PyBuffer_Release`.
(Contributed by Inada Naoki in :issue:`41103`.)

* Removed ``Py_UNICODE_str*`` functions manipulating ``Py_UNICODE*`` strings.
(Contributed by Inada Naoki in :issue:`41123`.)

Expand Down
47 changes: 47 additions & 0 deletions Include/abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,53 @@ PyAPI_FUNC(int) PyObject_DelItemString(PyObject *o, const char *key);
PyAPI_FUNC(int) PyObject_DelItem(PyObject *o, PyObject *key);


/* === Old Buffer API ============================================ */

/* FIXME: usage of these should all be replaced in Python itself
but for backwards compatibility we will implement them.
Their usage without a corresponding "unlock" mechanism
may create issues (but they would already be there). */

/* Takes an arbitrary object which must support the (character, single segment)
buffer interface and returns a pointer to a read-only memory location
useable as character based input for subsequent processing.

Return 0 on success. buffer and buffer_len are only set in case no error
occurs. Otherwise, -1 is returned and an exception set. */
Py_DEPRECATED(3.0)
PyAPI_FUNC(int) PyObject_AsCharBuffer(PyObject *obj,
const char **buffer,
Py_ssize_t *buffer_len);

/* Checks whether an arbitrary object supports the (character, single segment)
buffer interface.

Returns 1 on success, 0 on failure. */
Py_DEPRECATED(3.0) PyAPI_FUNC(int) PyObject_CheckReadBuffer(PyObject *obj);

/* Same as PyObject_AsCharBuffer() except that this API expects (readable,
single segment) buffer interface and returns a pointer to a read-only memory
location which can contain arbitrary data.

0 is returned on success. buffer and buffer_len are only set in case no
error occurs. Otherwise, -1 is returned and an exception set. */
Py_DEPRECATED(3.0)
PyAPI_FUNC(int) PyObject_AsReadBuffer(PyObject *obj,
const void **buffer,
Py_ssize_t *buffer_len);

/* Takes an arbitrary object which must support the (writable, single segment)
buffer interface and returns a pointer to a writable memory location in
buffer of size 'buffer_len'.

Return 0 on success. buffer and buffer_len are only set in case no error
occurs. Otherwise, -1 is returned and an exception set. */
Py_DEPRECATED(3.0)
PyAPI_FUNC(int) PyObject_AsWriteBuffer(PyObject *obj,
void **buffer,
Py_ssize_t *buffer_len);


/* === New Buffer API ============================================ */

/* Takes an arbitrary object and returns the result of calling
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Reverts removal of the old buffer protocol because they are part of stable
ABI.
11 changes: 11 additions & 0 deletions Misc/stable_abi.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1642,6 +1642,17 @@ function _Py_VaBuildValue_SizeT
added 3.2
abi_only

# Old buffer protocol support (deprecated)

function PyObject_AsCharBuffer
added 3.2
function PyObject_AsReadBuffer
added 3.2
function PyObject_AsWriteBuffer
added 3.2
function PyObject_CheckReadBuffer
added 3.2

# Flags are implicitly part of the ABI:

const Py_TPFLAGS_DEFAULT
Expand Down
79 changes: 79 additions & 0 deletions Objects/abstract.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,85 @@ PyObject_CheckBuffer(PyObject *obj)
}


/* We release the buffer right after use of this function which could
cause issues later on. Don't use these functions in new code.
*/
int
PyObject_CheckReadBuffer(PyObject *obj)
{
PyBufferProcs *pb = Py_TYPE(obj)->tp_as_buffer;
Py_buffer view;

if (pb == NULL ||
pb->bf_getbuffer == NULL)
return 0;
if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE) == -1) {
PyErr_Clear();
return 0;
}
PyBuffer_Release(&view);
return 1;
}

static int
as_read_buffer(PyObject *obj, const void **buffer, Py_ssize_t *buffer_len)
{
Py_buffer view;

if (obj == NULL || buffer == NULL || buffer_len == NULL) {
null_error();
return -1;
}
if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0)
return -1;

*buffer = view.buf;
*buffer_len = view.len;
PyBuffer_Release(&view);
return 0;
}

int
PyObject_AsCharBuffer(PyObject *obj,
const char **buffer,
Py_ssize_t *buffer_len)
{
return as_read_buffer(obj, (const void **)buffer, buffer_len);
}

int PyObject_AsReadBuffer(PyObject *obj,
const void **buffer,
Py_ssize_t *buffer_len)
{
return as_read_buffer(obj, buffer, buffer_len);
}

int PyObject_AsWriteBuffer(PyObject *obj,
void **buffer,
Py_ssize_t *buffer_len)
{
PyBufferProcs *pb;
Py_buffer view;

if (obj == NULL || buffer == NULL || buffer_len == NULL) {
null_error();
return -1;
}
pb = Py_TYPE(obj)->tp_as_buffer;
if (pb == NULL ||
pb->bf_getbuffer == NULL ||
((*pb->bf_getbuffer)(obj, &view, PyBUF_WRITABLE) != 0)) {
PyErr_SetString(PyExc_TypeError,
"expected a writable bytes-like object");
return -1;
}

*buffer = view.buf;
*buffer_len = view.len;
PyBuffer_Release(&view);
return 0;
}

/* Buffer C-API for Python 3.0 */

int
Expand Down
4 changes: 4 additions & 0 deletions PC/python3dll.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,11 @@ EXPORT_FUNC(PyNumber_Subtract)
EXPORT_FUNC(PyNumber_ToBase)
EXPORT_FUNC(PyNumber_TrueDivide)
EXPORT_FUNC(PyNumber_Xor)
EXPORT_FUNC(PyObject_AsCharBuffer)
EXPORT_FUNC(PyObject_ASCII)
EXPORT_FUNC(PyObject_AsFileDescriptor)
EXPORT_FUNC(PyObject_AsReadBuffer)
EXPORT_FUNC(PyObject_AsWriteBuffer)
EXPORT_FUNC(PyObject_Bytes)
EXPORT_FUNC(PyObject_Call)
EXPORT_FUNC(PyObject_CallFunction)
Expand All @@ -424,6 +427,7 @@ EXPORT_FUNC(PyObject_CallMethodObjArgs)
EXPORT_FUNC(PyObject_CallNoArgs)
EXPORT_FUNC(PyObject_CallObject)
EXPORT_FUNC(PyObject_Calloc)
EXPORT_FUNC(PyObject_CheckReadBuffer)
EXPORT_FUNC(PyObject_ClearWeakRefs)
EXPORT_FUNC(PyObject_DelItem)
EXPORT_FUNC(PyObject_DelItemString)
Expand Down