Skip to content

Commit 8af4606

Browse files
committed
WIP: gh-106593: PyResource API
* Add PyUnicode_AsUTF8Resource() * Add PyBytes_AsStringResource() * Add PySequence_AsObjectArray() * Add Include/pyresource.h * Add PyResource_Close() to the stable ABI * compute_abstract_methods(): Replace PySequence_Fast() with PySequence_AsObjectArray()
1 parent b2b261a commit 8af4606

File tree

17 files changed

+176
-16
lines changed

17 files changed

+176
-16
lines changed

Doc/data/stable_abi.dat

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/Python.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "pymacro.h"
4040
#include "pymath.h"
4141
#include "pymem.h"
42+
#include "pyresource.h"
4243
#include "pytypedefs.h"
4344
#include "pybuffer.h"
4445
#include "object.h"

Include/abstract.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,12 @@ PyAPI_FUNC(PyObject *) PySequence_List(PyObject *o);
706706
TypeError exception with 'm' as the message text. */
707707
PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m);
708708

709+
PyAPI_FUNC(int) PySequence_AsObjectArray(
710+
PyObject *,
711+
PyResource *res,
712+
PyObject ***parray,
713+
Py_ssize_t *psize);
714+
709715
/* Return the size of the sequence 'o', assuming that 'o' was returned by
710716
PySequence_Fast and is not NULL. */
711717
#define PySequence_Fast_GET_SIZE(o) \

Include/bytesobject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ PyAPI_FUNC(PyObject *) PyBytes_FromFormat(const char*, ...)
4040
Py_GCC_ATTRIBUTE((format(printf, 1, 2)));
4141
PyAPI_FUNC(Py_ssize_t) PyBytes_Size(PyObject *);
4242
PyAPI_FUNC(char *) PyBytes_AsString(PyObject *);
43+
PyAPI_FUNC(char *) PyBytes_AsStringResource(PyObject *, PyResource *res);
4344
PyAPI_FUNC(PyObject *) PyBytes_Repr(PyObject *, int);
4445
PyAPI_FUNC(void) PyBytes_Concat(PyObject **, PyObject *);
4546
PyAPI_FUNC(void) PyBytes_ConcatAndDel(PyObject **, PyObject *);

Include/cpython/unicodeobject.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,10 @@ PyAPI_FUNC(PyObject*) PyUnicode_FromKindAndData(
455455

456456
PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode);
457457

458+
PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode);
459+
460+
PyAPI_FUNC(const char *) PyUnicode_AsUTF8Resource(PyObject *unicode, PyResource *res);
461+
458462
#define _PyUnicode_AsString PyUnicode_AsUTF8
459463

460464
/* === Characters Type APIs =============================================== */

Include/pyresource.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef Py_RESOURCE_H
2+
#define Py_RESOURCE_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
typedef struct {
8+
void (*close_func) (void *data);
9+
void *data;
10+
} PyResource;
11+
12+
PyAPI_FUNC(void) PyResource_Close(PyResource *res);
13+
14+
#ifdef Py_BUILD_CORE
15+
PyAPI_FUNC(void) _PyResource_DECREF(void *data);
16+
#endif
17+
18+
#ifdef __cplusplus
19+
}
20+
#endif
21+
#endif // !Py_RESOURCE_H

Lib/test/test_stable_abi_ctypes.py

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,7 @@ PYTHON_HEADERS= \
16571657
$(srcdir)/Include/pymath.h \
16581658
$(srcdir)/Include/pymem.h \
16591659
$(srcdir)/Include/pyport.h \
1660+
$(srcdir)/Include/pyresource.h \
16601661
$(srcdir)/Include/pystate.h \
16611662
$(srcdir)/Include/pystats.h \
16621663
$(srcdir)/Include/pystrcmp.h \

Misc/stable_abi.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2444,3 +2444,8 @@
24442444
added = '3.13'
24452445
[function.PyMapping_GetOptionalItemString]
24462446
added = '3.13'
2447+
[struct.PyResource]
2448+
added = '3.13'
2449+
struct_abi_kind = 'full-abi'
2450+
[function.PyResource_Close]
2451+
added = '3.13'

Modules/_abc.c

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -317,34 +317,46 @@ compute_abstract_methods(PyObject *self)
317317
}
318318
assert(PyList_Check(items));
319319
for (Py_ssize_t pos = 0; pos < PyList_GET_SIZE(items); pos++) {
320-
PyObject *it = PySequence_Fast(
321-
PyList_GET_ITEM(items, pos),
322-
"items() returned non-iterable");
323-
if (!it) {
320+
PyObject *seq = PyList_GET_ITEM(items, pos);
321+
PyResource res;
322+
PyObject **items;
323+
Py_ssize_t nitem;
324+
if (PySequence_AsObjectArray(seq, &res, &items, &nitem) < 0) {
325+
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
326+
PyErr_SetString(PyExc_TypeError, "items() returned non-iterable");
327+
}
324328
goto error;
325329
}
326-
if (PySequence_Fast_GET_SIZE(it) != 2) {
330+
if (nitem != 2) {
327331
PyErr_SetString(PyExc_TypeError,
328332
"items() returned item which size is not 2");
329-
Py_DECREF(it);
333+
PyResource_Close(&res);
330334
goto error;
331335
}
332336

333-
// borrowed
334-
PyObject *key = PySequence_Fast_GET_ITEM(it, 0);
335-
PyObject *value = PySequence_Fast_GET_ITEM(it, 1);
336337
// items or it may be cleared while accessing __abstractmethod__
337338
// So we need to keep strong reference for key
338-
Py_INCREF(key);
339+
PyObject *key = Py_NewRef(items[0]);
340+
PyObject *value = Py_NewRef(items[1]);
341+
PyResource_Close(&res);
342+
339343
int is_abstract = _PyObject_IsAbstract(value);
340-
if (is_abstract < 0 ||
341-
(is_abstract && PySet_Add(abstracts, key) < 0)) {
342-
Py_DECREF(it);
343-
Py_DECREF(key);
344-
goto error;
344+
int err;
345+
if (is_abstract < 0) {
346+
err = 1;
347+
}
348+
else if (is_abstract) {
349+
err = PySet_Add(abstracts, key) < 0;
350+
}
351+
else {
352+
err = 0;
345353
}
346354
Py_DECREF(key);
347-
Py_DECREF(it);
355+
Py_DECREF(value);
356+
357+
if (err) {
358+
goto error;
359+
}
348360
}
349361

350362
/* Stage 2: inherited abstract methods. */

0 commit comments

Comments
 (0)