Skip to content

Commit bbf462c

Browse files
committed
Add PyDict_SetDefaultRef()
1 parent f667991 commit bbf462c

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

pythoncapi_compat.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,47 @@ PyList_GetItemRef(PyObject *op, Py_ssize_t index)
12981298
#endif
12991299

13001300

1301+
// gh-114329 added PyList_GetItemRef() to Python 3.13.0a4
1302+
#if PY_VERSION_HEX < 0x030D00A4
1303+
static int
1304+
PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value,
1305+
PyObject **result)
1306+
{
1307+
PyObject *value;
1308+
if (PyDict_GetItemRef(d, key, &value) < 0) {
1309+
// get error
1310+
if (result) {
1311+
*result = NULL;
1312+
}
1313+
return -1;
1314+
}
1315+
if (value != NULL) {
1316+
// present
1317+
if (result) {
1318+
*result = value;
1319+
}
1320+
else {
1321+
Py_DECREF(value);
1322+
}
1323+
return 1;
1324+
}
1325+
1326+
// missing: set the item
1327+
if (PyDict_SetItem(d, key, default_value) < 0) {
1328+
// set error
1329+
if (result) {
1330+
*result = NULL;
1331+
}
1332+
return -1;
1333+
}
1334+
if (result) {
1335+
*result = Py_NewRef(default_value);
1336+
}
1337+
return 0;
1338+
}
1339+
#endif
1340+
1341+
13011342
#ifdef __cplusplus
13021343
}
13031344
#endif

tests/test_pythoncapi_compat_cext.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,62 @@ test_dict_pop(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
13291329
}
13301330

13311331

1332+
static PyObject *
1333+
test_dict_setdefault(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
1334+
{
1335+
PyObject *dict = PyDict_New();
1336+
if (dict == NULL) {
1337+
return NULL;
1338+
}
1339+
PyObject *key = PyUnicode_FromString("key");
1340+
assert(key != NULL);
1341+
PyObject *value = PyUnicode_FromString("abc");
1342+
assert(value != NULL);
1343+
PyObject *invalid_key = PyList_New(0); // not hashable key
1344+
assert(invalid_key != NULL);
1345+
1346+
// insert item
1347+
PyObject *result = UNINITIALIZED_OBJ;
1348+
assert(PyDict_SetDefaultRef(dict, key, value, &result) == 0);
1349+
assert(result == value);
1350+
Py_DECREF(result);
1351+
1352+
// item already present
1353+
result = UNINITIALIZED_OBJ;
1354+
assert(PyDict_SetDefaultRef(dict, key, value, &result) == 1);
1355+
assert(result == value);
1356+
Py_DECREF(result);
1357+
1358+
// error: invalid key
1359+
assert(!PyErr_Occurred());
1360+
result = UNINITIALIZED_OBJ;
1361+
assert(PyDict_SetDefaultRef(dict, invalid_key, value, &result) == -1);
1362+
assert(result == NULL);
1363+
assert(PyErr_Occurred());
1364+
PyErr_Clear();
1365+
1366+
// insert item with NULL result
1367+
assert(PyDict_Pop(dict, key, NULL) == 1);
1368+
assert(PyDict_SetDefaultRef(dict, key, value, NULL) == 0);
1369+
1370+
// item already present with NULL result
1371+
assert(PyDict_SetDefaultRef(dict, key, value, NULL) == 1);
1372+
1373+
// error: invalid key with NULL result
1374+
assert(!PyErr_Occurred());
1375+
assert(PyDict_SetDefaultRef(dict, invalid_key, value, NULL) == -1);
1376+
assert(PyErr_Occurred());
1377+
PyErr_Clear();
1378+
1379+
// exit
1380+
Py_DECREF(dict);
1381+
Py_DECREF(key);
1382+
Py_DECREF(value);
1383+
Py_DECREF(invalid_key);
1384+
Py_RETURN_NONE;
1385+
}
1386+
1387+
13321388
static PyObject *
13331389
test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
13341390
{
@@ -1694,6 +1750,7 @@ static struct PyMethodDef methods[] = {
16941750
{"test_getitem", test_getitem, METH_NOARGS, _Py_NULL},
16951751
{"test_dict_api", test_dict_api, METH_NOARGS, _Py_NULL},
16961752
{"test_dict_pop", test_dict_pop, METH_NOARGS, _Py_NULL},
1753+
{"test_dict_setdefault", test_dict_setdefault, METH_NOARGS, _Py_NULL},
16971754
{"test_long_api", test_long_api, METH_NOARGS, _Py_NULL},
16981755
#ifdef TEST_MANAGED_DICT
16991756
{"test_managed_dict", test_managed_dict, METH_NOARGS, _Py_NULL},

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy