gh-115754: Add Py_GetConstant() function (#116883)

Add Py_GetConstant() and Py_GetConstantBorrowed() functions.

In the limited C API version 3.13, getting Py_None, Py_False,
Py_True, Py_Ellipsis and Py_NotImplemented singletons is now
implemented as function calls at the stable ABI level to hide
implementation details. Getting these constants still return borrowed
references.

Add _testlimitedcapi/object.c and test_capi/test_object.py to test
Py_GetConstant() and Py_GetConstantBorrowed() functions.
This commit is contained in:
Victor Stinner 2024-03-21 17:07:00 +01:00 committed by GitHub
parent 5a76d1be8e
commit 8bea6c411d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 312 additions and 6 deletions

View file

@ -163,7 +163,7 @@
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c

View file

@ -53,6 +53,9 @@ PyInit__testlimitedcapi(void)
if (_PyTestLimitedCAPI_Init_Long(mod) < 0) {
return NULL;
}
if (_PyTestLimitedCAPI_Init_Object(mod) < 0) {
return NULL;
}
if (_PyTestLimitedCAPI_Init_PyOS(mod) < 0) {
return NULL;
}

View file

@ -0,0 +1,80 @@
// Need limited C API version 3.13 for Py_GetConstant()
#include "pyconfig.h" // Py_GIL_DISABLED
#if !defined(Py_GIL_DISABLED) && !defined(Py_LIMITED_API )
# define Py_LIMITED_API 0x030d0000
#endif
#include "parts.h"
#include "util.h"
/* Test Py_GetConstant() */
static PyObject *
get_constant(PyObject *Py_UNUSED(module), PyObject *args)
{
int constant_id;
if (!PyArg_ParseTuple(args, "i", &constant_id)) {
return NULL;
}
PyObject *obj = Py_GetConstant(constant_id);
if (obj == NULL) {
assert(PyErr_Occurred());
return NULL;
}
return obj;
}
/* Test Py_GetConstantBorrowed() */
static PyObject *
get_constant_borrowed(PyObject *Py_UNUSED(module), PyObject *args)
{
int constant_id;
if (!PyArg_ParseTuple(args, "i", &constant_id)) {
return NULL;
}
PyObject *obj = Py_GetConstantBorrowed(constant_id);
if (obj == NULL) {
assert(PyErr_Occurred());
return NULL;
}
return Py_NewRef(obj);
}
/* Test constants */
static PyObject *
test_constants(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
{
// Test that implementation of constants in the limited C API:
// check that the C code compiles.
//
// Test also that constants and Py_GetConstant() return the same
// objects.
assert(Py_None == Py_GetConstant(Py_CONSTANT_NONE));
assert(Py_False == Py_GetConstant(Py_CONSTANT_FALSE));
assert(Py_True == Py_GetConstant(Py_CONSTANT_TRUE));
assert(Py_Ellipsis == Py_GetConstant(Py_CONSTANT_ELLIPSIS));
assert(Py_NotImplemented == Py_GetConstant(Py_CONSTANT_NOT_IMPLEMENTED));
// Other constants are tested in test_capi.test_object
Py_RETURN_NONE;
}
static PyMethodDef test_methods[] = {
{"get_constant", get_constant, METH_VARARGS},
{"get_constant_borrowed", get_constant_borrowed, METH_VARARGS},
{"test_constants", test_constants, METH_NOARGS},
{NULL},
};
int
_PyTestLimitedCAPI_Init_Object(PyObject *m)
{
if (PyModule_AddFunctions(m, test_methods) < 0) {
return -1;
}
return 0;
}

View file

@ -29,6 +29,7 @@ int _PyTestLimitedCAPI_Init_Complex(PyObject *module);
int _PyTestLimitedCAPI_Init_Dict(PyObject *module);
int _PyTestLimitedCAPI_Init_Float(PyObject *module);
int _PyTestLimitedCAPI_Init_HeaptypeRelative(PyObject *module);
int _PyTestLimitedCAPI_Init_Object(PyObject *module);
int _PyTestLimitedCAPI_Init_List(PyObject *module);
int _PyTestLimitedCAPI_Init_Long(PyObject *module);
int _PyTestLimitedCAPI_Init_PyOS(PyObject *module);