Skip to content
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

gh-102500: Implement PEP 688 #102521

Merged
merged 51 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
ca76251
try 1
JelleZijlstra Oct 2, 2022
901b459
progress
JelleZijlstra Oct 3, 2022
c5407c7
this is better
JelleZijlstra Oct 4, 2022
86f2000
this seems to work
JelleZijlstra Oct 4, 2022
ac10887
one more test
JelleZijlstra Oct 5, 2022
2563016
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Oct 5, 2022
530a160
additions
JelleZijlstra Oct 5, 2022
de3a4bc
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Oct 12, 2022
116f72e
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Oct 21, 2022
207d2fd
introduce __mutable_buffer__ (rather hackily)
JelleZijlstra Oct 21, 2022
aee2c33
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Nov 6, 2022
007fdc1
Rip out __mutable_buffer__
JelleZijlstra Nov 6, 2022
46a9239
__release_buffer__ calls mv.release()
JelleZijlstra Nov 8, 2022
3020fee
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Nov 8, 2022
be9bf45
additional test
JelleZijlstra Nov 8, 2022
a6bf0e8
undo stray change
JelleZijlstra Nov 8, 2022
04d267e
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Dec 18, 2022
04d0a42
throw an error if already released
JelleZijlstra Dec 18, 2022
bb6d076
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Mar 8, 2023
5f755fe
Fix compiler warning
JelleZijlstra Mar 8, 2023
0b02e63
news
JelleZijlstra Mar 8, 2023
8e4db43
fix some tests
JelleZijlstra Mar 8, 2023
6c863bc
More tests. Add flags= argument to memoryview
JelleZijlstra Mar 10, 2023
3b4b7d6
Make memoryview flags arg private
JelleZijlstra Mar 11, 2023
f295012
regen global objects
JelleZijlstra Mar 11, 2023
1660ae4
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Apr 5, 2023
0af94ac
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Apr 5, 2023
b5ea908
Ignore new C globals for now
JelleZijlstra Apr 5, 2023
b22bfa9
not static (should not have committed this)
JelleZijlstra Apr 5, 2023
69e8f7c
Use tabs not spaces
JelleZijlstra Apr 5, 2023
4ca7a7c
Address Kumar's feedback
JelleZijlstra Apr 10, 2023
fd2d716
Merge branch 'main' into pep688v2
JelleZijlstra Apr 10, 2023
a70e12d
Address another piece of feedback
JelleZijlstra Apr 13, 2023
96c9253
Use a classmethod instead of a new arg to the memoryview constructor
JelleZijlstra Apr 13, 2023
1f7f7a0
fix typo
JelleZijlstra Apr 13, 2023
7665dde
Merge branch 'main' into pep688v2
JelleZijlstra Apr 25, 2023
e99c188
Merge branch 'main' into pep688v2
JelleZijlstra Apr 26, 2023
33691ea
Add Py_SAFE_DOWNCAST
JelleZijlstra Apr 26, 2023
8f5073f
Add some test cases (thanks Shantanu)
JelleZijlstra Apr 26, 2023
b69dc7c
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Apr 26, 2023
9d33003
Merge remote-tracking branch 'upstream/main' into pep688v2
JelleZijlstra Apr 29, 2023
cecb6a5
Remove spurious global strings
JelleZijlstra Apr 29, 2023
9b941a0
Merge branch 'main' into pep688v2
JelleZijlstra May 4, 2023
b22d66f
Merge branch 'main' of https://github.com/python/cpython into pep688v2
kumaraditya303 May 4, 2023
0f77bbb
fixup global objects
kumaraditya303 May 4, 2023
61f54ce
minor fixes
kumaraditya303 May 4, 2023
9f2d16b
newlines
JelleZijlstra May 4, 2023
5e0d2de
Rename variable
JelleZijlstra May 4, 2023
b380632
Check for INT_MAX
JelleZijlstra May 4, 2023
8502b98
Remove tp_new
JelleZijlstra May 4, 2023
b51465f
regen-all
JelleZijlstra May 4, 2023
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
Prev Previous commit
Next Next commit
progress
  • Loading branch information
JelleZijlstra committed Oct 3, 2022
commit 901b459cd92e224afddc5291e3670cd0efdd3511
2 changes: 1 addition & 1 deletion Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(__rdivmod__)
STRUCT_FOR_ID(__reduce__)
STRUCT_FOR_ID(__reduce_ex__)
STRUCT_FOR_ID(__release_buffer__)
STRUCT_FOR_ID(__release_buffer__)
STRUCT_FOR_ID(__repr__)
STRUCT_FOR_ID(__reversed__)
STRUCT_FOR_ID(__rfloordiv__)
Expand Down
17 changes: 17 additions & 0 deletions Include/internal/pycore_memoryobject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef Py_INTERNAL_MEMORYOBJECT_H
#define Py_INTERNAL_MEMORYOBJECT_H
#ifdef __cplusplus
extern "C" {
#endif

#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif

PyObject *
PyMemoryView_FromObjectAndFlags(PyObject *v, int flags);

#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_MEMORYOBJECT_H */
14 changes: 14 additions & 0 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions Lib/test/test_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4436,5 +4436,56 @@ def test_pybuffer_size_from_format(self):
struct.calcsize(format))


class TestPythonBufferProtocol(unittest.TestCase):
def test_basic(self):
class MyBuffer:
def __buffer__(self, flags):
return memoryview(b"hello")

mv = memoryview(MyBuffer())
self.assertEqual(mv.tobytes(), b"hello")
self.assertEqual(bytes(MyBuffer()), b"hello")

def test_bad_buffer_method(self):
class MustReturnMV:
def __buffer__(self, flags):
return 42

self.assertRaises(TypeError, memoryview, MustReturnMV())

class WrongArity:
def __buffer__(self):
return memoryview(b"hello")

self.assertRaises(TypeError, memoryview, WrongArity())

def test_release_buffer(self):
class WhatToRelease:
def __init__(self):
self.held = False
self.ba = bytearray(b"hello")
def __buffer__(self, flags):
if self.held:
raise TypeError("already held")
self.held = True
return memoryview(self.ba)
def __release_buffer__(self, buffer):
assert self is buffer.obj
self.held = False

wr = WhatToRelease()
self.assertFalse(wr.held)
with memoryview(wr) as mv:
self.assertTrue(wr.held)
self.assertEqual(mv.tobytes(), b"hello")
self.assertFalse(wr.held)

def test_call_builtins(self):
ba = bytearray(b"hello")
mv = ba.__buffer__(0)
self.assertEqual(mv.tobytes(), b"hello")
ba.__release_buffer__(mv)


if __name__ == "__main__":
unittest.main()
21 changes: 15 additions & 6 deletions Objects/memoryobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ mbuf_alloc(void)
}

static PyObject *
_PyManagedBuffer_FromObject(PyObject *base)
_PyManagedBuffer_FromObject(PyObject *base, int flags)
{
_PyManagedBufferObject *mbuf;

mbuf = mbuf_alloc();
if (mbuf == NULL)
return NULL;

if (PyObject_GetBuffer(base, &mbuf->master, PyBUF_FULL_RO) < 0) {
if (PyObject_GetBuffer(base, &mbuf->master, flags) < 0) {
mbuf->master.obj = NULL;
Py_DECREF(mbuf);
return NULL;
Expand Down Expand Up @@ -779,11 +779,12 @@ PyMemoryView_FromBuffer(const Py_buffer *info)
return mv;
}

/* Create a memoryview from an object that implements the buffer protocol.
/* Create a memoryview from an object that implements the buffer protocol,
using the given flags.
If the object is a memoryview, the new memoryview must be registered
with the same managed buffer. Otherwise, a new managed buffer is created. */
PyObject *
PyMemoryView_FromObject(PyObject *v)
PyMemoryView_FromObjectAndFlags(PyObject *v, int flags)
{
_PyManagedBufferObject *mbuf;

Expand All @@ -794,7 +795,7 @@ PyMemoryView_FromObject(PyObject *v)
}
else if (PyObject_CheckBuffer(v)) {
PyObject *ret;
mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(v);
mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(v, flags);
if (mbuf == NULL)
return NULL;
ret = mbuf_add_view(mbuf, NULL);
Expand All @@ -807,6 +808,14 @@ PyMemoryView_FromObject(PyObject *v)
Py_TYPE(v)->tp_name);
return NULL;
}
/* Create a memoryview from an object that implements the buffer protocol.
If the object is a memoryview, the new memoryview must be registered
with the same managed buffer. Otherwise, a new managed buffer is created. */
PyObject *
PyMemoryView_FromObject(PyObject *v)
{
return PyMemoryView_FromObjectAndFlags(v, PyBUF_FULL_RO);
}

/* Copy the format string from a base object that might vanish. */
static int
Expand Down Expand Up @@ -853,7 +862,7 @@ memory_from_contiguous_copy(const Py_buffer *src, char order)
if (bytes == NULL)
return NULL;

mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(bytes);
mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(bytes, PyBUF_FULL_RO);
Py_DECREF(bytes);
if (mbuf == NULL)
return NULL;
Expand Down
15 changes: 8 additions & 7 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "pycore_code.h" // CO_FAST_FREE
#include "pycore_compile.h" // _Py_Mangle()
#include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_memoryobject.h" // PyMemoryView_FromObjectAndFlags()
#include "pycore_moduleobject.h" // _PyModule_GetDef()
#include "pycore_object.h" // _PyType_HasFeature()
#include "pycore_pyerrors.h" // _PyErr_Occurred()
Expand Down Expand Up @@ -7554,8 +7555,6 @@ wrap_descr_delete(PyObject *self, PyObject *args, void *wrapped)
static PyObject *
wrap_buffer(PyObject *self, PyObject *args, void *wrapped)
{
getbufferproc func = (getbufferproc)wrapped;
Py_buffer view;
int flags = 0;

if (!check_num_args(args, 1)) {
Expand All @@ -7564,10 +7563,7 @@ wrap_buffer(PyObject *self, PyObject *args, void *wrapped)
if (!PyArg_ParseTuple(args, "i", &flags)) {
return NULL;
}
if ((*func)(self, &view, flags) < 0) {
return NULL;
}
return PyMemoryView_FromBuffer(&view);
return PyMemoryView_FromObjectAndFlags(self, flags);
}

static PyObject *
Expand Down Expand Up @@ -8441,6 +8437,9 @@ slot_bf_getbuffer(PyObject *self, Py_buffer *buffer, int flags)
goto fail;
}
*buffer = ((PyMemoryViewObject *)ret)->view;
// TODO does this leak the existing ref in buffer->obj?
buffer->obj = self;
Py_INCREF(buffer->obj);
Py_DECREF(ret);
Py_DECREF(flags_obj);
return 0;
Expand All @@ -8459,6 +8458,9 @@ slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer)
PyErr_WriteUnraisable(self);
return;
}
if (buffer->obj != NULL) {
((PyMemoryViewObject *)mv)->view.obj = Py_NewRef(buffer->obj);
}
PyObject *stack[2] = {self, mv};
PyObject *ret = vectorcall_method(&_Py_ID(__release_buffer__), stack, 2);
Py_DECREF(mv);
Expand All @@ -8470,7 +8472,6 @@ slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer)
}
}


static PyObject *
slot_am_await(PyObject *self)
{
Expand Down