8000 Add Py_GetConstant() and Py_GetConstantBorrowed() · python/pythoncapi-compat@1a08548 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1a08548

Browse files
committed
Add Py_GetConstant() and Py_GetConstantBorrowed()
1 parent 7000d0e commit 1a08548

File tree

4 files changed

+182
-0
lines changed

4 files changed

+182
-0
lines changed

docs/api.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,15 @@ Python 3.12
192192
193193
Not available on PyPy.
194194
195+
.. c:function:: PyObject* Py_GetConstant(unsigned int constant_id)
196+
197+
See `Py_GetConstant() documentation <https://docs.python.org/dev/c-api/object.html#c.Py_GetConstant>`__.
198+
199+
.. c:function:: PyObject* Py_GetConstantBorrowed(unsigned int constant_id)
200+
201+
See `Py_GetConstantBorrowed() documentation <https://docs.python.org/dev/c-api/object.html#c.Py_GetConstantBorrowed>`__.
202+
203+
195204
Not supported:
196205
197206
* ``PyDict_AddWatcher()``, ``PyDict_Watch()``.

docs/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Changelog
22
=========
33

4+
* 2024-03-21: Add functions:
5+
6+
* ``Py_GetConstant()``
7+
* ``Py_GetConstantBorrowed()``
8+
49
* 2024-03-09: Add hash constants:
510

611
* ``PyHASH_BITS``

pythoncapi_compat.h

Lines changed: 82 additions & 0 deletions
+
#define Py_CONSTANT_FALSE 1
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,88 @@ static inline int PyTime_PerfCounter(PyTime_t *result)
12091209
#endif
12101210

12111211

1212+
// gh-111545 added Py_GetConstant() and Py_GetConstantBorrowed()
1213+
// to Python 3.13.0a6
1214+
#if PY_VERSION_HEX < 0x030D00A6
1215+
1216+
#define Py_CONSTANT_NONE 0
1217
1218+
#define Py_CONSTANT_TRUE 2
1219+
#define Py_CONSTANT_ELLIPSIS 3
1220+
#define Py_CONSTANT_NOT_IMPLEMENTED 4
1221+
#define Py_CONSTANT_ZERO 5
1222+
#define Py_CONSTANT_ONE 6
1223+
#define Py_CONSTANT_EMPTY_STR 7
1224+
#define Py_CONSTANT_EMPTY_BYTES 8
1225+
#define Py_CONSTANT_EMPTY_TUPLE 9
1226+
1227+
static inline PyObject* Py_GetConstant(unsigned int constant_id)
1228+
{
1229+
static PyObject* constants[] = {
1230+
Py_None, // Py_CONSTANT_NONE
1231+
Py_False, // Py_CONSTANT_FALSE
1232+
Py_True, // Py_CONSTANT_TRUE
1233+
Py_Ellipsis, // Py_CONSTANT_ELLIPSIS
1234+
Py_NotImplemented, // Py_CONSTANT_NOT_IMPLEMENTED
1235+
NULL, // Py_CONSTANT_ZERO
1236+
NULL, // Py_CONSTANT_ONE
1237+
NULL, // Py_CONSTANT_EMPTY_STR
1238+
NULL, // Py_CONSTANT_EMPTY_BYTES
1239+
NULL, // Py_CONSTANT_EMPTY_TUPLE
1240+
};
1241+
1242+
if (constants[Py_CONSTANT_ZERO] == NULL) {
1243+
constants[Py_CONSTANT_ZERO] = PyLong_FromLong(0);
1244+
if (constants[Py_CONSTANT_ZERO] == NULL) {
1245+
goto fatal_error;
1246+
}
1247+
1248+
constants[Py_CONSTANT_ONE] = PyLong_FromLong(1);
1249+
if (constants[Py_CONSTANT_ONE] == NULL) {
1250+
goto fatal_error;
1251+
}
1252+
1253+
constants[Py_CONSTANT_EMPTY_STR] = PyUnicode_FromStringAndSize("", 0);
1254+
if (constants[Py_CONSTANT_EMPTY_STR] == NULL) {
1255+
goto fatal_error;
1256+
}
1257+
1258+
constants[Py_CONSTANT_EMPTY_BYTES] = PyBytes_FromStringAndSize("", 0);
1259+
if (constants[Py_CONSTANT_EMPTY_BYTES] == NULL) {
1260+
goto fatal_error;
1261+
}
1262+
1263+
constants[Py_CONSTANT_EMPTY_TUPLE] = PyTuple_New(0);
1264+
if (constants[Py_CONSTANT_EMPTY_TUPLE] == NULL) {
1265+
goto fatal_error;
1266+
}
1267+
// goto dance to avoid compiler warnings about Py_FatalError()
1268+
goto init_done;
1269+
1270+
fatal_error:
1271+
// This case should never happen
1272+
Py_FatalError("Py_GetConstant() failed to get constants");
1273+
}
1274+
1275+
init_done:
1276+
if (constant_id <= Py_CONSTANT_EMPTY_TUPLE) {
1277+
return Py_NewRef(constants[constant_id]);
1278+
}
1279+
else {
1280+
PyErr_BadInternalCall();
1281+
return NULL;
1282+
}
1283+
}
1284+
1285+
static inline PyObject* Py_GetConstantBorrowed(unsigned int constant_id)
1286+
{
1287+
PyObject *obj = Py_GetConstant(constant_id);
1288+
Py_XDECREF(obj);
1289+
return obj;
1290+
}
1291+
#endif
1292+
1293+
12121294
#ifdef __cplusplus
12131295
}
12141296
#endif

tests/test_pythoncapi_compat_cext.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,91 @@ test_time(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
15731573
#endif
15741574

15751575

1576+
static void
1577+
check_get_constant(PyObject* (*get_constant)(unsigned int), int borrowed)
1578+
{
1579+
#define CLEAR(var) if (!borrowed) { Py_DECREF(var); }
1580+
1581+
PyObject *obj, *expected;
1582+
1583+
// Py_CONSTANT_NONE
1584+
obj = get_constant(Py_CONSTANT_NONE);
1585+
assert(obj == Py_None);
1586+
CLEAR(obj);
1587+
1588+
// Py_CONSTANT_FALSE
1589+
obj = get_constant(Py_CONSTANT_FALSE);
1590+
assert(obj = Py_False);
1591+
CLEAR(obj);
1592+
1593+
// Py_CONSTANT_TRUE
1594+
obj = get_constant(Py_CONSTANT_TRUE);
1595+
assert(obj == Py_True);
1596+
CLEAR(obj);
1597+
1598+
// Py_CONSTANT_ELLIPSIS
1599+
obj = get_constant(Py_CONSTANT_ELLIPSIS);
1600+
assert(obj == Py_Ellipsis);
1601+
CLEAR(obj);
1602+
1603+
// Py_CONSTANT_NOT_IMPLEMENTED
1604+
obj = get_constant(Py_CONSTANT_NOT_IMPLEMENTED);
1605+
assert(obj == Py_NotImplemented);
1606+
CLEAR(obj);
1607+
1608+
// Py_CONSTANT_ZERO
1609+
obj = get_constant(Py_CONSTANT_ZERO);
1610+
expected = PyLong_FromLong(0);
1611+
assert(expected != NULL);
1612+
assert(Py_TYPE(obj) == &PyLong_Type);
1613+
assert(PyObject_RichCompareBool(obj, expected, Py_EQ) == 1);
1614+
CLEAR(obj);
1615+
Py_DECREF(expected);
1616+
1617+
// Py_CONSTANT_ONE
1618+
obj = get_constant(Py_CONSTANT_ONE);
1619+
expected = PyLong_FromLong(1);
1620+
assert(expected != NULL);
1621+
assert(Py_TYPE(obj) == &PyL 10000 ong_Type);
1622+
assert(PyObject_RichCompareBool(obj, expected, Py_EQ) == 1);
1623+
CLEAR(obj);
1624+
Py_DECREF(expected);
1625+
1626+
// Py_CONSTANT_EMPTY_STR
1627+
obj = get_constant(Py_CONSTANT_EMPTY_STR);
1628+
assert(Py_TYPE(obj) == &PyUnicode_Type);
1629+
#if PY_VERSION_HEX >= 0x03030000
1630+
assert(PyUnicode_GetLength(obj) == 0);
1631+
#else
1632+
assert(PyUnicode_GetSize(obj) == 0);
1633+
#endif
1634+
CLEAR(obj);
1635+
1636+
// Py_CONSTANT_EMPTY_BYTES
1637+
obj = get_constant(Py_CONSTANT_EMPTY_BYTES);
1638+
assert(Py_TYPE(obj) == &PyBytes_Type);
1639+
assert(PyBytes_Size(obj) == 0);
1640+
CLEAR(obj);
1641+
1642+
// Py_CONSTANT_EMPTY_TUPLE
1643+
obj = get_constant(Py_CONSTANT_EMPTY_TUPLE);
1644+
assert(Py_TYPE(obj) == &PyTuple_Type);
1645+
assert(PyTuple_Size(obj) == 0);
1646+
CLEAR(obj);
1647+
1648+
#undef CLEAR
1649+
}
1650+
1651+
1652+
static PyObject *
1653+
test_get_constant(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
1654+
{
1655+
check_get_constant(Py_GetConstant, 0);
1656+
check_get_constant(Py_GetConstantBorrowed, 1);
1657+
Py_RETURN_NONE;
1658+
}
1659+
1660+
15761661
static struct PyMethodDef methods[] = {
15771662
{"test_object", test_object, METH_NOARGS, _Py_NULL},
15781663
{"test_py_is", test_py_is, METH_NOARGS, _Py_NULL},
@@ -1609,6 +1694,7 @@ static struct PyMethodDef methods[] = {
16091694
#ifdef TEST_PYTIME
16101695
{"test_time", test_time, METH_NOARGS, _Py_NULL},
16111696
#endif
1697+
{"test_get_constant", test_get_constant, METH_NOARGS, _Py_NULL},
16121698
{_Py_NULL, _Py_NULL, 0, _Py_NULL}
16131699
};
16141700

0 commit comments

Comments
 (0)
0