mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
gh-106004: Add PyDict_GetItemRef() function (#106005)
* Add PyDict_GetItemRef() and PyDict_GetItemStringRef() functions. Add these functions to the stable ABI version 3.13. * Add unit tests on the PyDict C API in test_capi.
This commit is contained in:
parent
0ba07b2108
commit
41ca164551
10 changed files with 308 additions and 18 deletions
|
@ -3464,6 +3464,196 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
|||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
test_dict_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
||||
{
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
PyObject *dict= NULL, *key = NULL, *missing_key = NULL, *value = NULL;
|
||||
PyObject *invalid_key = NULL;
|
||||
int res;
|
||||
|
||||
// test PyDict_New()
|
||||
dict = PyDict_New();
|
||||
if (dict == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
key = PyUnicode_FromString("key");
|
||||
if (key == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
missing_key = PyUnicode_FromString("missing_key");
|
||||
if (missing_key == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
value = PyUnicode_FromString("value");
|
||||
if (value == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// test PyDict_SetItem()
|
||||
Py_ssize_t key_refcnt = Py_REFCNT(key);
|
||||
Py_ssize_t value_refcnt = Py_REFCNT(value);
|
||||
res = PyDict_SetItem(dict, key, value);
|
||||
if (res < 0) {
|
||||
goto error;
|
||||
}
|
||||
assert(res == 0);
|
||||
assert(Py_REFCNT(key) == (key_refcnt + 1));
|
||||
assert(Py_REFCNT(value) == (value_refcnt + 1));
|
||||
|
||||
// test PyDict_SetItemString()
|
||||
res = PyDict_SetItemString(dict, "key", value);
|
||||
if (res < 0) {
|
||||
goto error;
|
||||
}
|
||||
assert(res == 0);
|
||||
assert(Py_REFCNT(key) == (key_refcnt + 1));
|
||||
assert(Py_REFCNT(value) == (value_refcnt + 1));
|
||||
|
||||
// test PyDict_Size()
|
||||
assert(PyDict_Size(dict) == 1);
|
||||
|
||||
// test PyDict_Contains(), key is present
|
||||
assert(PyDict_Contains(dict, key) == 1);
|
||||
|
||||
// test PyDict_GetItem(), key is present
|
||||
assert(PyDict_GetItem(dict, key) == value);
|
||||
|
||||
// test PyDict_GetItemString(), key is present
|
||||
assert(PyDict_GetItemString(dict, "key") == value);
|
||||
|
||||
// test PyDict_GetItemWithError(), key is present
|
||||
assert(PyDict_GetItemWithError(dict, key) == value);
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
// test PyDict_GetItemRef(), key is present
|
||||
PyObject *get_value = Py_Ellipsis; // marker value
|
||||
assert(PyDict_GetItemRef(dict, key, &get_value) == 1);
|
||||
assert(get_value == value);
|
||||
Py_DECREF(get_value);
|
||||
|
||||
// test PyDict_GetItemStringRef(), key is present
|
||||
get_value = Py_Ellipsis; // marker value
|
||||
assert(PyDict_GetItemStringRef(dict, "key", &get_value) == 1);
|
||||
assert(get_value == value);
|
||||
Py_DECREF(get_value);
|
||||
|
||||
// test PyDict_Contains(), missing key
|
||||
assert(PyDict_Contains(dict, missing_key) == 0);
|
||||
|
||||
// test PyDict_GetItem(), missing key
|
||||
assert(PyDict_GetItem(dict, missing_key) == NULL);
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
// test PyDict_GetItemString(), missing key
|
||||
assert(PyDict_GetItemString(dict, "missing_key") == NULL);
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
// test PyDict_GetItemWithError(), missing key
|
||||
assert(PyDict_GetItem(dict, missing_key) == NULL);
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
// test PyDict_GetItemRef(), missing key
|
||||
get_value = Py_Ellipsis; // marker value
|
||||
assert(PyDict_GetItemRef(dict, missing_key, &get_value) == 0);
|
||||
assert(!PyErr_Occurred());
|
||||
assert(get_value == NULL);
|
||||
|
||||
// test PyDict_GetItemStringRef(), missing key
|
||||
get_value = Py_Ellipsis; // marker value
|
||||
assert(PyDict_GetItemStringRef(dict, "missing_key", &get_value) == 0);
|
||||
assert(!PyErr_Occurred());
|
||||
assert(get_value == NULL);
|
||||
|
||||
// test PyDict_GetItem(), invalid dict
|
||||
PyObject *invalid_dict = key; // borrowed reference
|
||||
assert(PyDict_GetItem(invalid_dict, key) == NULL);
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
// test PyDict_GetItemWithError(), invalid dict
|
||||
assert(PyDict_GetItemWithError(invalid_dict, key) == NULL);
|
||||
assert(PyErr_ExceptionMatches(PyExc_SystemError));
|
||||
PyErr_Clear();
|
||||
|
||||
// test PyDict_GetItemRef(), invalid dict
|
||||
get_value = Py_Ellipsis; // marker value
|
||||
assert(PyDict_GetItemRef(invalid_dict, key, &get_value) == -1);
|
||||
assert(PyErr_ExceptionMatches(PyExc_SystemError));
|
||||
PyErr_Clear();
|
||||
assert(get_value == NULL);
|
||||
|
||||
// test PyDict_GetItemStringRef(), invalid dict
|
||||
get_value = Py_Ellipsis; // marker value
|
||||
assert(PyDict_GetItemStringRef(invalid_dict, "key", &get_value) == -1);
|
||||
assert(PyErr_ExceptionMatches(PyExc_SystemError));
|
||||
PyErr_Clear();
|
||||
assert(get_value == NULL);
|
||||
|
||||
invalid_key = PyList_New(0);
|
||||
if (invalid_key == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// test PyDict_Contains(), invalid key
|
||||
assert(PyDict_Contains(dict, invalid_key) == -1);
|
||||
assert(PyErr_ExceptionMatches(PyExc_TypeError));
|
||||
PyErr_Clear();
|
||||
|
||||
// test PyDict_GetItem(), invalid key
|
||||
assert(PyDict_GetItem(dict, invalid_key) == NULL);
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
// test PyDict_GetItemWithError(), invalid key
|
||||
assert(PyDict_GetItemWithError(dict, invalid_key) == NULL);
|
||||
assert(PyErr_ExceptionMatches(PyExc_TypeError));
|
||||
PyErr_Clear();
|
||||
|
||||
// test PyDict_GetItemRef(), invalid key
|
||||
get_value = Py_Ellipsis; // marker value
|
||||
assert(PyDict_GetItemRef(dict, invalid_key, &get_value) == -1);
|
||||
assert(PyErr_ExceptionMatches(PyExc_TypeError));
|
||||
PyErr_Clear();
|
||||
assert(get_value == NULL);
|
||||
|
||||
// test PyDict_DelItem(), key is present
|
||||
assert(PyDict_DelItem(dict, key) == 0);
|
||||
assert(PyDict_Size(dict) == 0);
|
||||
|
||||
// test PyDict_DelItem(), missing key
|
||||
assert(PyDict_DelItem(dict, missing_key) == -1);
|
||||
assert(PyErr_ExceptionMatches(PyExc_KeyError));
|
||||
PyErr_Clear();
|
||||
|
||||
// test PyDict_DelItem(), invalid key
|
||||
assert(PyDict_DelItem(dict, invalid_key) == -1);
|
||||
assert(PyErr_ExceptionMatches(PyExc_TypeError));
|
||||
PyErr_Clear();
|
||||
|
||||
// test PyDict_Clear()
|
||||
PyDict_Clear(dict);
|
||||
|
||||
Py_DECREF(dict);
|
||||
Py_DECREF(key);
|
||||
Py_DECREF(missing_key);
|
||||
Py_DECREF(value);
|
||||
Py_DECREF(invalid_key);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
|
||||
error:
|
||||
Py_XDECREF(dict);
|
||||
Py_XDECREF(key);
|
||||
Py_XDECREF(missing_key);
|
||||
Py_XDECREF(value);
|
||||
Py_XDECREF(invalid_key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef TestMethods[] = {
|
||||
{"set_errno", set_errno, METH_VARARGS},
|
||||
{"test_config", test_config, METH_NOARGS},
|
||||
|
@ -3609,6 +3799,7 @@ static PyMethodDef TestMethods[] = {
|
|||
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
|
||||
{"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS},
|
||||
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
|
||||
{"test_dict_capi", test_dict_capi, METH_NOARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue