Skip to content
Prev Previous commit
Next Next commit
Add simple tests for Py_buffer stable ABI
  • Loading branch information
tiran committed Feb 2, 2022
commit d5167819b1195de97ec85e347c14c05ba73b19cf
11 changes: 11 additions & 0 deletions Lib/test/test_xxlimited.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ def test_error(self):
with self.assertRaises(self.module.Error):
raise self.module.Error

def test_buffer(self):
xxo = self.module.Xxo()
self.assertEqual(xxo.x_exports, 0)
b1 = memoryview(xxo)
self.assertEqual(xxo.x_exports, 1)
b2 = memoryview(xxo)
self.assertEqual(xxo.x_exports, 2)
b1[0] = 1
self.assertEqual(b1[0], 1)
self.assertEqual(b2[0], 1)


class TestXXLimited35(CommonTests, unittest.TestCase):
module = xxlimited_35
Expand Down
50 changes: 49 additions & 1 deletion Modules/xxlimited.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
def __init__(self):
# In the C class, "_x_attr" is not accessible from Python code
self._x_attr = {}
self._x_buffer = bytesarray(10)
self._x_exports = 0
Comment thread
tiran marked this conversation as resolved.
Outdated

def __getattr__(self, name):
return self._x_attr[name]
Expand All @@ -29,6 +31,10 @@
def __delattr__(self, name):
del self._x_attr[name]

@property
def x_exports(self):
return self._x_exports

Comment thread
tiran marked this conversation as resolved.
Outdated
def demo(o, /):
if isinstance(o, str):
return o
Expand Down Expand Up @@ -57,6 +63,9 @@
#define Py_LIMITED_API 0x030b0000

#include "Python.h"
#include <string.h>

#define BUFSIZE 10

// Module state
typedef struct {
Expand All @@ -70,7 +79,9 @@ typedef struct {
// Instance state
typedef struct {
PyObject_HEAD
PyObject *x_attr; /* Attributes dictionary */
PyObject *x_attr; /* Attributes dictionary */
char x_buffer[BUFSIZE]; /* buffer for Py_buffer */
Py_ssize_t x_exports; /* how many buffer are exported */
} XxoObject;

// XXX: no good way to do this yet
Expand All @@ -89,6 +100,8 @@ newXxoObject(PyObject *module)
return NULL;
}
self->x_attr = NULL;
memset(self->x_buffer, 0, BUFSIZE);
self->x_exports = 0;
return self;
}

Expand Down Expand Up @@ -212,11 +225,43 @@ static PyMethodDef Xxo_methods[] = {
{NULL, NULL} /* sentinel */
};

/* Xxo buffer interface */

static int
Xxo_getbuffer(XxoObject *self, Py_buffer *view, int flags)
{
int res = PyBuffer_FillInfo(view, (PyObject*)self,
(void *)self->x_buffer, BUFSIZE,
0, flags);
if (res == 0) {
self->x_exports++;
}
return res;
}

static void
Xxo_releasebuffer(XxoObject *self, Py_buffer *view)
{
self->x_exports--;
}

static PyObject *
Xxo_get_x_exports(XxoObject *self, void *c)
{
return PyLong_FromSsize_t(self->x_exports);
}

/* Xxo type definition */

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

static PyGetSetDef Xxo_getsetlist[] = {
{"x_exports", (getter) Xxo_get_x_exports, NULL, NULL},
{NULL},
};


static PyType_Slot Xxo_Type_slots[] = {
{Py_tp_doc, (char *)Xxo_doc},
{Py_tp_traverse, Xxo_traverse},
Expand All @@ -226,6 +271,9 @@ static PyType_Slot Xxo_Type_slots[] = {
{Py_tp_getattro, Xxo_getattro},
{Py_tp_setattro, Xxo_setattro},
{Py_tp_methods, Xxo_methods},
{Py_bf_getbuffer, Xxo_getbuffer},
{Py_bf_releasebuffer, Xxo_releasebuffer},
{Py_tp_getset, Xxo_getsetlist},
{0, 0}, /* sentinel */
};

Expand Down