mirror of https://github.com/python/cpython
bpo-41103: Resurrect the old buffer protocol. (GH-27437)
Revert "bpo-41103: Remove old buffer protocol support (#21117)"
This reverts commit 6f8a6ee59c
.
This commit is contained in:
parent
d542742128
commit
ce5e1a6809
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
@ -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,
|
||||
|
|
|
@ -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`.)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Reverts removal of the old buffer protocol because they are part of stable
|
||||
ABI.
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue