diff options
author | Victor Stinner <vstinner@python.org> | 2023-07-21 21:10:51 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-21 21:10:51 (GMT) |
commit | 41ca16455188db806bfc7037058e8ecff2755e6c (patch) | |
tree | 925ab5df83f04657ea3b4be058c104556b094424 /Modules/_testcapimodule.c | |
parent | 0ba07b2108d4763273f3fb85544dde34c5acd40a (diff) | |
download | cpython-41ca16455188db806bfc7037058e8ecff2755e6c.zip cpython-41ca16455188db806bfc7037058e8ecff2755e6c.tar.gz cpython-41ca16455188db806bfc7037058e8ecff2755e6c.tar.bz2 |
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.
Diffstat (limited to 'Modules/_testcapimodule.c')
-rw-r--r-- | Modules/_testcapimodule.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index dd2c9c7..065a7fb 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -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 */ }; |