8000 Add PyDict_SetDefaultRef() · python/pythoncapi-compat@bbf462c · GitHub
[go: up one dir, main page]

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)
0