Skip to content

Commit d516781

Browse files
committed
Add simple tests for Py_buffer stable ABI
1 parent 0e67e2c commit d516781

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

Lib/test/test_xxlimited.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ def test_error(self):
5858
with self.assertRaises(self.module.Error):
5959
raise self.module.Error
6060

61+
def test_buffer(self):
62+
xxo = self.module.Xxo()
63+
self.assertEqual(xxo.x_exports, 0)
64+
b1 = memoryview(xxo)
65+
self.assertEqual(xxo.x_exports, 1)
66+
b2 = memoryview(xxo)
67+
self.assertEqual(xxo.x_exports, 2)
68+
b1[0] = 1
69+
self.assertEqual(b1[0], 1)
70+
self.assertEqual(b2[0], 1)
71+
6172

6273
class TestXXLimited35(CommonTests, unittest.TestCase):
6374
module = xxlimited_35

Modules/xxlimited.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
def __init__(self):
2020
# In the C class, "_x_attr" is not accessible from Python code
2121
self._x_attr = {}
22+
self._x_buffer = bytesarray(10)
23+
self._x_exports = 0
2224
2325
def __getattr__(self, name):
2426
return self._x_attr[name]
@@ -29,6 +31,10 @@
2931
def __delattr__(self, name):
3032
del self._x_attr[name]
3133
34+
@property
35+
def x_exports(self):
36+
return self._x_exports
37+
3238
def demo(o, /):
3339
if isinstance(o, str):
3440
return o
@@ -57,6 +63,9 @@
5763
#define Py_LIMITED_API 0x030b0000
5864

5965
#include "Python.h"
66+
#include <string.h>
67+
68+
#define BUFSIZE 10
6069

6170
// Module state
6271
typedef struct {
@@ -70,7 +79,9 @@ typedef struct {
7079
// Instance state
7180
typedef struct {
7281
PyObject_HEAD
73-
PyObject *x_attr; /* Attributes dictionary */
82+
PyObject *x_attr; /* Attributes dictionary */
83+
char x_buffer[BUFSIZE]; /* buffer for Py_buffer */
84+
Py_ssize_t x_exports; /* how many buffer are exported */
7485
} XxoObject;
7586

7687
// XXX: no good way to do this yet
@@ -89,6 +100,8 @@ newXxoObject(PyObject *module)
89100
return NULL;
90101
}
91102
self->x_attr = NULL;
103+
memset(self->x_buffer, 0, BUFSIZE);
104+
self->x_exports = 0;
92105
return self;
93106
}
94107

@@ -212,11 +225,43 @@ static PyMethodDef Xxo_methods[] = {
212225
{NULL, NULL} /* sentinel */
213226
};
214227

228+
/* Xxo buffer interface */
229+
230+
static int
231+
Xxo_getbuffer(XxoObject *self, Py_buffer *view, int flags)
232+
{
233+
int res = PyBuffer_FillInfo(view, (PyObject*)self,
234+
(void *)self->x_buffer, BUFSIZE,
235+
0, flags);
236+
if (res == 0) {
237+
self->x_exports++;
238+
}
239+
return res;
240+
}
241+
242+
static void
243+
Xxo_releasebuffer(XxoObject *self, Py_buffer *view)
244+
{
245+
self->x_exports--;
246+
}
247+
248+
static PyObject *
249+
Xxo_get_x_exports(XxoObject *self, void *c)
250+
{
251+
return PyLong_FromSsize_t(self->x_exports);
252+
}
253+
215254
/* Xxo type definition */
216255

217256
PyDoc_STRVAR(Xxo_doc,
218257
"A class that explicitly stores attributes in an internal dict");
219258

259+
static PyGetSetDef Xxo_getsetlist[] = {
260+
{"x_exports", (getter) Xxo_get_x_exports, NULL, NULL},
261+
{NULL},
262+
};
263+
264+
220265
static PyType_Slot Xxo_Type_slots[] = {
221266
{Py_tp_doc, (char *)Xxo_doc},
222267
{Py_tp_traverse, Xxo_traverse},
@@ -226,6 +271,9 @@ static PyType_Slot Xxo_Type_slots[] = {
226271
{Py_tp_getattro, Xxo_getattro},
227272
{Py_tp_setattro, Xxo_setattro},
228273
{Py_tp_methods, Xxo_methods},
274+
{Py_bf_getbuffer, Xxo_getbuffer},
275+
{Py_bf_releasebuffer, Xxo_releasebuffer},
276+
{Py_tp_getset, Xxo_getsetlist},
229277
{0, 0}, /* sentinel */
230278
};
231279

0 commit comments

Comments
 (0)