mirror of https://github.com/python/cpython
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:
parent
5a76d1be8e
commit
8bea6c411d
|
@ -6,6 +6,55 @@ Object Protocol
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: PyObject* Py_GetConstant(unsigned int constant_id)
|
||||||
|
|
||||||
|
Get a :term:`strong reference` to a constant.
|
||||||
|
|
||||||
|
Set an exception and return ``NULL`` if *constant_id* is invalid.
|
||||||
|
|
||||||
|
*constant_id* must be one of these constant identifiers:
|
||||||
|
|
||||||
|
.. c:namespace:: NULL
|
||||||
|
|
||||||
|
======================================== ===== =========================
|
||||||
|
Constant Identifier Value Returned object
|
||||||
|
======================================== ===== =========================
|
||||||
|
.. c:macro:: Py_CONSTANT_NONE ``0`` :py:data:`None`
|
||||||
|
.. c:macro:: Py_CONSTANT_FALSE ``1`` :py:data:`False`
|
||||||
|
.. c:macro:: Py_CONSTANT_TRUE ``2`` :py:data:`True`
|
||||||
|
.. c:macro:: Py_CONSTANT_ELLIPSIS ``3`` :py:data:`Ellipsis`
|
||||||
|
.. c:macro:: Py_CONSTANT_NOT_IMPLEMENTED ``4`` :py:data:`NotImplemented`
|
||||||
|
.. c:macro:: Py_CONSTANT_ZERO ``5`` ``0``
|
||||||
|
.. c:macro:: Py_CONSTANT_ONE ``6`` ``1``
|
||||||
|
.. c:macro:: Py_CONSTANT_EMPTY_STR ``7`` ``''``
|
||||||
|
.. c:macro:: Py_CONSTANT_EMPTY_BYTES ``8`` ``b''``
|
||||||
|
.. c:macro:: Py_CONSTANT_EMPTY_TUPLE ``9`` ``()``
|
||||||
|
======================================== ===== =========================
|
||||||
|
|
||||||
|
Numeric values are only given for projects which cannot use the constant
|
||||||
|
identifiers.
|
||||||
|
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
.. impl-detail::
|
||||||
|
|
||||||
|
In CPython, all of these constants are :term:`immortal`.
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: PyObject* Py_GetConstantBorrowed(unsigned int constant_id)
|
||||||
|
|
||||||
|
Similar to :c:func:`Py_GetConstant`, but return a :term:`borrowed
|
||||||
|
reference`.
|
||||||
|
|
||||||
|
This function is primarily intended for backwards compatibility:
|
||||||
|
using :c:func:`Py_GetConstant` is recommended for new code.
|
||||||
|
|
||||||
|
The reference is borrowed from the interpreter, and is valid until the
|
||||||
|
interpreter finalization.
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
|
||||||
.. c:var:: PyObject* Py_NotImplemented
|
.. c:var:: PyObject* Py_NotImplemented
|
||||||
|
|
||||||
The ``NotImplemented`` singleton, used to signal that an operation is
|
The ``NotImplemented`` singleton, used to signal that an operation is
|
||||||
|
|
|
@ -838,6 +838,8 @@ function,Py_GenericAlias,3.9,,
|
||||||
var,Py_GenericAliasType,3.9,,
|
var,Py_GenericAliasType,3.9,,
|
||||||
function,Py_GetBuildInfo,3.2,,
|
function,Py_GetBuildInfo,3.2,,
|
||||||
function,Py_GetCompiler,3.2,,
|
function,Py_GetCompiler,3.2,,
|
||||||
|
function,Py_GetConstant,3.13,,
|
||||||
|
function,Py_GetConstantBorrowed,3.13,,
|
||||||
function,Py_GetCopyright,3.2,,
|
function,Py_GetCopyright,3.2,,
|
||||||
function,Py_GetExecPrefix,3.2,,
|
function,Py_GetExecPrefix,3.2,,
|
||||||
function,Py_GetPath,3.2,,
|
function,Py_GetPath,3.2,,
|
||||||
|
|
|
@ -1731,6 +1731,11 @@ New Features
|
||||||
more information.
|
more information.
|
||||||
(Contributed by Victor Stinner in :gh:`111696`.)
|
(Contributed by Victor Stinner in :gh:`111696`.)
|
||||||
|
|
||||||
|
* Add :c:func:`Py_GetConstant` and :c:func:`Py_GetConstantBorrowed` functions
|
||||||
|
to get constants. For example, ``Py_GetConstant(Py_CONSTANT_ZERO)`` returns a
|
||||||
|
:term:`strong reference` to the constant zero.
|
||||||
|
(Contributed by Victor Stinner in :gh:`115754`.)
|
||||||
|
|
||||||
|
|
||||||
Porting to Python 3.13
|
Porting to Python 3.13
|
||||||
----------------------
|
----------------------
|
||||||
|
|
|
@ -18,8 +18,13 @@ PyAPI_DATA(PyLongObject) _Py_FalseStruct;
|
||||||
PyAPI_DATA(PyLongObject) _Py_TrueStruct;
|
PyAPI_DATA(PyLongObject) _Py_TrueStruct;
|
||||||
|
|
||||||
/* Use these macros */
|
/* Use these macros */
|
||||||
#define Py_False _PyObject_CAST(&_Py_FalseStruct)
|
#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030D0000
|
||||||
#define Py_True _PyObject_CAST(&_Py_TrueStruct)
|
# define Py_False Py_GetConstantBorrowed(Py_CONSTANT_FALSE)
|
||||||
|
# define Py_True Py_GetConstantBorrowed(Py_CONSTANT_TRUE)
|
||||||
|
#else
|
||||||
|
# define Py_False _PyObject_CAST(&_Py_FalseStruct)
|
||||||
|
# define Py_True _PyObject_CAST(&_Py_TrueStruct)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Test if an object is the True singleton, the same as "x is True" in Python.
|
// Test if an object is the True singleton, the same as "x is True" in Python.
|
||||||
PyAPI_FUNC(int) Py_IsTrue(PyObject *x);
|
PyAPI_FUNC(int) Py_IsTrue(PyObject *x);
|
||||||
|
|
|
@ -716,6 +716,8 @@ PyAPI_DATA(PyTypeObject) _PyNotImplemented_Type;
|
||||||
// Export for the stable ABI.
|
// Export for the stable ABI.
|
||||||
PyAPI_DATA(int) _Py_SwappedOp[];
|
PyAPI_DATA(int) _Py_SwappedOp[];
|
||||||
|
|
||||||
|
extern void _Py_GetConstant_Init(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1068,12 +1068,34 @@ static inline PyObject* _Py_XNewRef(PyObject *obj)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define Py_CONSTANT_NONE 0
|
||||||
|
#define Py_CONSTANT_FALSE 1
|
||||||
|
#define Py_CONSTANT_TRUE 2
|
||||||
|
#define Py_CONSTANT_ELLIPSIS 3
|
||||||
|
#define Py_CONSTANT_NOT_IMPLEMENTED 4
|
||||||
|
#define Py_CONSTANT_ZERO 5
|
||||||
|
#define Py_CONSTANT_ONE 6
|
||||||
|
#define Py_CONSTANT_EMPTY_STR 7
|
||||||
|
#define Py_CONSTANT_EMPTY_BYTES 8
|
||||||
|
#define Py_CONSTANT_EMPTY_TUPLE 9
|
||||||
|
|
||||||
|
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
|
||||||
|
PyAPI_FUNC(PyObject*) Py_GetConstant(unsigned int constant_id);
|
||||||
|
PyAPI_FUNC(PyObject*) Py_GetConstantBorrowed(unsigned int constant_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
_Py_NoneStruct is an object of undefined type which can be used in contexts
|
_Py_NoneStruct is an object of undefined type which can be used in contexts
|
||||||
where NULL (nil) is not suitable (since NULL often means 'error').
|
where NULL (nil) is not suitable (since NULL often means 'error').
|
||||||
*/
|
*/
|
||||||
PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */
|
PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */
|
||||||
#define Py_None (&_Py_NoneStruct)
|
|
||||||
|
#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030D0000
|
||||||
|
# define Py_None Py_GetConstantBorrowed(Py_CONSTANT_NONE)
|
||||||
|
#else
|
||||||
|
# define Py_None (&_Py_NoneStruct)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Test if an object is the None singleton, the same as "x is None" in Python.
|
// Test if an object is the None singleton, the same as "x is None" in Python.
|
||||||
PyAPI_FUNC(int) Py_IsNone(PyObject *x);
|
PyAPI_FUNC(int) Py_IsNone(PyObject *x);
|
||||||
|
@ -1087,7 +1109,12 @@ Py_NotImplemented is a singleton used to signal that an operation is
|
||||||
not implemented for a given type combination.
|
not implemented for a given type combination.
|
||||||
*/
|
*/
|
||||||
PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */
|
PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */
|
||||||
#define Py_NotImplemented (&_Py_NotImplementedStruct)
|
|
||||||
|
#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030D0000
|
||||||
|
# define Py_NotImplemented Py_GetConstantBorrowed(Py_CONSTANT_NOT_IMPLEMENTED)
|
||||||
|
#else
|
||||||
|
# define Py_NotImplemented (&_Py_NotImplementedStruct)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Macro for returning Py_NotImplemented from a function */
|
/* Macro for returning Py_NotImplemented from a function */
|
||||||
#define Py_RETURN_NOTIMPLEMENTED return Py_NotImplemented
|
#define Py_RETURN_NOTIMPLEMENTED return Py_NotImplemented
|
||||||
|
|
|
@ -8,7 +8,11 @@ extern "C" {
|
||||||
|
|
||||||
PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */
|
PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */
|
||||||
|
|
||||||
#define Py_Ellipsis (&_Py_EllipsisObject)
|
#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030D0000
|
||||||
|
# define Py_Ellipsis Py_GetConstantBorrowed(Py_CONSTANT_ELLIPSIS)
|
||||||
|
#else
|
||||||
|
# define Py_Ellipsis (&_Py_EllipsisObject)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Slice object interface */
|
/* Slice object interface */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
import enum
|
||||||
|
import unittest
|
||||||
|
from test.support import import_helper
|
||||||
|
|
||||||
|
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
|
||||||
|
|
||||||
|
|
||||||
|
class Constant(enum.IntEnum):
|
||||||
|
Py_CONSTANT_NONE = 0
|
||||||
|
Py_CONSTANT_FALSE = 1
|
||||||
|
Py_CONSTANT_TRUE = 2
|
||||||
|
Py_CONSTANT_ELLIPSIS = 3
|
||||||
|
Py_CONSTANT_NOT_IMPLEMENTED = 4
|
||||||
|
Py_CONSTANT_ZERO = 5
|
||||||
|
Py_CONSTANT_ONE = 6
|
||||||
|
Py_CONSTANT_EMPTY_STR = 7
|
||||||
|
Py_CONSTANT_EMPTY_BYTES = 8
|
||||||
|
Py_CONSTANT_EMPTY_TUPLE = 9
|
||||||
|
|
||||||
|
INVALID_CONSTANT = Py_CONSTANT_EMPTY_TUPLE + 1
|
||||||
|
|
||||||
|
|
||||||
|
class CAPITest(unittest.TestCase):
|
||||||
|
def check_get_constant(self, get_constant):
|
||||||
|
self.assertIs(get_constant(Constant.Py_CONSTANT_NONE), None)
|
||||||
|
self.assertIs(get_constant(Constant.Py_CONSTANT_FALSE), False)
|
||||||
|
self.assertIs(get_constant(Constant.Py_CONSTANT_TRUE), True)
|
||||||
|
self.assertIs(get_constant(Constant.Py_CONSTANT_ELLIPSIS), Ellipsis)
|
||||||
|
self.assertIs(get_constant(Constant.Py_CONSTANT_NOT_IMPLEMENTED), NotImplemented)
|
||||||
|
|
||||||
|
for constant_id, constant_type, value in (
|
||||||
|
(Constant.Py_CONSTANT_ZERO, int, 0),
|
||||||
|
(Constant.Py_CONSTANT_ONE, int, 1),
|
||||||
|
(Constant.Py_CONSTANT_EMPTY_STR, str, ""),
|
||||||
|
(Constant.Py_CONSTANT_EMPTY_BYTES, bytes, b""),
|
||||||
|
(Constant.Py_CONSTANT_EMPTY_TUPLE, tuple, ()),
|
||||||
|
):
|
||||||
|
with self.subTest(constant_id=constant_id):
|
||||||
|
obj = get_constant(constant_id)
|
||||||
|
self.assertEqual(type(obj), constant_type, obj)
|
||||||
|
self.assertEqual(obj, value)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
get_constant(Constant.INVALID_CONSTANT)
|
||||||
|
|
||||||
|
def test_get_constant(self):
|
||||||
|
self.check_get_constant(_testlimitedcapi.get_constant)
|
||||||
|
|
||||||
|
def test_get_constant_borrowed(self):
|
||||||
|
self.check_get_constant(_testlimitedcapi.get_constant_borrowed)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
|
@ -856,6 +856,8 @@ SYMBOL_NAMES = (
|
||||||
"Py_GetArgcArgv",
|
"Py_GetArgcArgv",
|
||||||
"Py_GetBuildInfo",
|
"Py_GetBuildInfo",
|
||||||
"Py_GetCompiler",
|
"Py_GetCompiler",
|
||||||
|
"Py_GetConstant",
|
||||||
|
"Py_GetConstantBorrowed",
|
||||||
"Py_GetCopyright",
|
"Py_GetCopyright",
|
||||||
"Py_GetExecPrefix",
|
"Py_GetExecPrefix",
|
||||||
"Py_GetPath",
|
"Py_GetPath",
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Add :c:func:`Py_GetConstant` and :c:func:`Py_GetConstantBorrowed` functions to
|
||||||
|
get constants. For example, ``Py_GetConstant(Py_CONSTANT_ZERO)`` returns a
|
||||||
|
:term:`strong reference` to the constant zero. Patch by Victor Stinner.
|
|
@ -0,0 +1,5 @@
|
||||||
|
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. Patch by
|
||||||
|
Victor Stinner.
|
|
@ -2500,3 +2500,7 @@
|
||||||
added = '3.13'
|
added = '3.13'
|
||||||
[function.PyType_GetModuleName]
|
[function.PyType_GetModuleName]
|
||||||
added = '3.13'
|
added = '3.13'
|
||||||
|
[function.Py_GetConstant]
|
||||||
|
added = '3.13'
|
||||||
|
[function.Py_GetConstantBorrowed]
|
||||||
|
added = '3.13'
|
||||||
|
|
|
@ -163,7 +163,7 @@
|
||||||
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
|
@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__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__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_TRUE@_testclinic _testclinic.c
|
||||||
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
|
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,9 @@ PyInit__testlimitedcapi(void)
|
||||||
if (_PyTestLimitedCAPI_Init_Long(mod) < 0) {
|
if (_PyTestLimitedCAPI_Init_Long(mod) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (_PyTestLimitedCAPI_Init_Object(mod) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (_PyTestLimitedCAPI_Init_PyOS(mod) < 0) {
|
if (_PyTestLimitedCAPI_Init_PyOS(mod) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ int _PyTestLimitedCAPI_Init_Complex(PyObject *module);
|
||||||
int _PyTestLimitedCAPI_Init_Dict(PyObject *module);
|
int _PyTestLimitedCAPI_Init_Dict(PyObject *module);
|
||||||
int _PyTestLimitedCAPI_Init_Float(PyObject *module);
|
int _PyTestLimitedCAPI_Init_Float(PyObject *module);
|
||||||
int _PyTestLimitedCAPI_Init_HeaptypeRelative(PyObject *module);
|
int _PyTestLimitedCAPI_Init_HeaptypeRelative(PyObject *module);
|
||||||
|
int _PyTestLimitedCAPI_Init_Object(PyObject *module);
|
||||||
int _PyTestLimitedCAPI_Init_List(PyObject *module);
|
int _PyTestLimitedCAPI_Init_List(PyObject *module);
|
||||||
int _PyTestLimitedCAPI_Init_Long(PyObject *module);
|
int _PyTestLimitedCAPI_Init_Long(PyObject *module);
|
||||||
int _PyTestLimitedCAPI_Init_PyOS(PyObject *module);
|
int _PyTestLimitedCAPI_Init_PyOS(PyObject *module);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "pycore_memoryobject.h" // _PyManagedBuffer_Type
|
#include "pycore_memoryobject.h" // _PyManagedBuffer_Type
|
||||||
#include "pycore_namespace.h" // _PyNamespace_Type
|
#include "pycore_namespace.h" // _PyNamespace_Type
|
||||||
#include "pycore_object.h" // PyAPI_DATA() _Py_SwappedOp definition
|
#include "pycore_object.h" // PyAPI_DATA() _Py_SwappedOp definition
|
||||||
|
#include "pycore_long.h" // _PyLong_GetZero()
|
||||||
#include "pycore_optimizer.h" // _PyUOpExecutor_Type, _PyUOpOptimizer_Type, ...
|
#include "pycore_optimizer.h" // _PyUOpExecutor_Type, _PyUOpOptimizer_Type, ...
|
||||||
#include "pycore_pyerrors.h" // _PyErr_Occurred()
|
#include "pycore_pyerrors.h" // _PyErr_Occurred()
|
||||||
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
|
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
|
||||||
|
@ -2991,3 +2992,53 @@ _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt)
|
||||||
{
|
{
|
||||||
Py_SET_REFCNT(ob, refcnt);
|
Py_SET_REFCNT(ob, refcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject* constants[] = {
|
||||||
|
&_Py_NoneStruct, // Py_CONSTANT_NONE
|
||||||
|
(PyObject*)(&_Py_FalseStruct), // Py_CONSTANT_FALSE
|
||||||
|
(PyObject*)(&_Py_TrueStruct), // Py_CONSTANT_TRUE
|
||||||
|
&_Py_EllipsisObject, // Py_CONSTANT_ELLIPSIS
|
||||||
|
&_Py_NotImplementedStruct, // Py_CONSTANT_NOT_IMPLEMENTED
|
||||||
|
NULL, // Py_CONSTANT_ZERO
|
||||||
|
NULL, // Py_CONSTANT_ONE
|
||||||
|
NULL, // Py_CONSTANT_EMPTY_STR
|
||||||
|
NULL, // Py_CONSTANT_EMPTY_BYTES
|
||||||
|
NULL, // Py_CONSTANT_EMPTY_TUPLE
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
_Py_GetConstant_Init(void)
|
||||||
|
{
|
||||||
|
constants[Py_CONSTANT_ZERO] = _PyLong_GetZero();
|
||||||
|
constants[Py_CONSTANT_ONE] = _PyLong_GetOne();
|
||||||
|
constants[Py_CONSTANT_EMPTY_STR] = PyUnicode_New(0, 0);
|
||||||
|
constants[Py_CONSTANT_EMPTY_BYTES] = PyBytes_FromStringAndSize(NULL, 0);
|
||||||
|
constants[Py_CONSTANT_EMPTY_TUPLE] = PyTuple_New(0);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
for (size_t i=0; i < Py_ARRAY_LENGTH(constants); i++) {
|
||||||
|
assert(constants[i] != NULL);
|
||||||
|
assert(_Py_IsImmortal(constants[i]));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject*
|
||||||
|
Py_GetConstant(unsigned int constant_id)
|
||||||
|
{
|
||||||
|
if (constant_id < Py_ARRAY_LENGTH(constants)) {
|
||||||
|
return constants[constant_id];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject*
|
||||||
|
Py_GetConstantBorrowed(unsigned int constant_id)
|
||||||
|
{
|
||||||
|
// All constants are immortal
|
||||||
|
return Py_GetConstant(constant_id);
|
||||||
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@ EXPORT_FUNC(Py_GenericAlias)
|
||||||
EXPORT_FUNC(Py_GetArgcArgv)
|
EXPORT_FUNC(Py_GetArgcArgv)
|
||||||
EXPORT_FUNC(Py_GetBuildInfo)
|
EXPORT_FUNC(Py_GetBuildInfo)
|
||||||
EXPORT_FUNC(Py_GetCompiler)
|
EXPORT_FUNC(Py_GetCompiler)
|
||||||
|
EXPORT_FUNC(Py_GetConstant)
|
||||||
|
EXPORT_FUNC(Py_GetConstantBorrowed)
|
||||||
EXPORT_FUNC(Py_GetCopyright)
|
EXPORT_FUNC(Py_GetCopyright)
|
||||||
EXPORT_FUNC(Py_GetExecPrefix)
|
EXPORT_FUNC(Py_GetExecPrefix)
|
||||||
EXPORT_FUNC(Py_GetPath)
|
EXPORT_FUNC(Py_GetPath)
|
||||||
|
|
|
@ -103,6 +103,7 @@
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\heaptype_relative.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\heaptype_relative.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\list.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\list.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\long.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\long.c" />
|
||||||
|
<ClCompile Include="..\Modules\_testlimitedcapi\object.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\pyos.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\pyos.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\set.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\set.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\sys.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\sys.c" />
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\heaptype_relative.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\heaptype_relative.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\list.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\list.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\long.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\long.c" />
|
||||||
|
<ClCompile Include="..\Modules\_testlimitedcapi\object.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\pyos.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\pyos.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\set.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\set.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\sys.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\sys.c" />
|
||||||
|
|
|
@ -687,6 +687,10 @@ pycore_init_global_objects(PyInterpreterState *interp)
|
||||||
|
|
||||||
_PyUnicode_InitState(interp);
|
_PyUnicode_InitState(interp);
|
||||||
|
|
||||||
|
if (_Py_IsMainInterpreter(interp)) {
|
||||||
|
_Py_GetConstant_Init();
|
||||||
|
}
|
||||||
|
|
||||||
return _PyStatus_OK();
|
return _PyStatus_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -742,3 +742,4 @@ Modules/_sqlite/module.c - _sqlite3module -
|
||||||
Modules/clinic/md5module.c.h _md5_md5 _keywords -
|
Modules/clinic/md5module.c.h _md5_md5 _keywords -
|
||||||
Modules/clinic/grpmodule.c.h grp_getgrgid _keywords -
|
Modules/clinic/grpmodule.c.h grp_getgrgid _keywords -
|
||||||
Modules/clinic/grpmodule.c.h grp_getgrnam _keywords -
|
Modules/clinic/grpmodule.c.h grp_getgrnam _keywords -
|
||||||
|
Objects/object.c - constants static PyObject*[]
|
||||||
|
|
Can't render this file because it has a wrong number of fields in line 4.
|
Loading…
Reference in New Issue