Skip to content

Commit

Permalink
Add PyDict_ContainsString() function
Browse files Browse the repository at this point in the history
  • Loading branch information
vstinner committed Aug 23, 2023
1 parent 5b5b547 commit 1b4de24
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 8 deletions.
15 changes: 15 additions & 0 deletions pythoncapi_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,21 @@ static inline int Py_IsFinalizing(void)
#endif


// gh-108323 added PyDict_ContainsString() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int PyDict_ContainsString(PyObject *op, const char *key)
{
PyObject *key_obj = PyUnicode_FromString(key);
if (key_obj == NULL) {
return -1;
}
int res = PyDict_Contains(op, key_obj);
Py_DECREF(key_obj);
return res;
}
#endif


#ifdef __cplusplus
}
#endif
Expand Down
35 changes: 27 additions & 8 deletions tests/test_pythoncapi_compat_cext.c
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,7 @@ test_getitem(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))


static PyObject *
test_dict_getitemref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
test_dict_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
{
assert(!PyErr_Occurred());

Expand All @@ -1112,12 +1112,18 @@ test_dict_getitemref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
if (key == NULL) {
goto error;
}
invalid_dict = key; // borrowed reference

missing_key = PyUnicode_FromString("missing_key");
if (missing_key == NULL) {
goto error;
}

invalid_key = PyList_New(0); // not hashable key
if (invalid_key == NULL) {
goto error;
}

value = PyUnicode_FromString("value");
if (value == NULL) {
goto error;
Expand All @@ -1129,6 +1135,25 @@ test_dict_getitemref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
}
assert(res == 0);

// test PyDict_Contains()
assert(PyDict_Contains(dict, key) == 1);
assert(PyDict_Contains(dict, missing_key) == 0);
#if defined(PYPY_VERSION) && !defined(PYTHON3) // PyPy for Python 2.7
assert(PyDict_Contains(dict, invalid_key) == 0);
assert(!PyErr_Occurred());
#else
assert(PyDict_Contains(dict, invalid_key) == -1);
assert(PyErr_ExceptionMatches(PyExc_TypeError));
PyErr_Clear();
#endif

// test PyDict_ContainsString()
assert(PyDict_ContainsString(dict, "key") == 1);
assert(PyDict_ContainsString(dict, "missing_key") == 0);
assert(PyDict_ContainsString(dict, "\xff") == -1);
assert(PyErr_ExceptionMatches(PyExc_UnicodeDecodeError));
PyErr_Clear();

// test PyDict_GetItemRef(), key is present
get_value = Py_Ellipsis; // marker value
assert(PyDict_GetItemRef(dict, key, &get_value) == 1);
Expand All @@ -1154,7 +1179,6 @@ test_dict_getitemref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
assert(get_value == NULL);

// test PyDict_GetItemRef(), invalid dict
invalid_dict = key; // borrowed reference
get_value = Py_Ellipsis; // marker value
assert(PyDict_GetItemRef(invalid_dict, key, &get_value) == -1);
assert(PyErr_ExceptionMatches(PyExc_SystemError));
Expand All @@ -1168,11 +1192,6 @@ test_dict_getitemref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
PyErr_Clear();
assert(get_value == NULL);

invalid_key = PyList_New(0); // not hashable key
if (invalid_key == NULL) {
goto error;
}

// test PyDict_GetItemRef(), invalid key
get_value = Py_Ellipsis; // marker value
assert(PyDict_GetItemRef(dict, invalid_key, &get_value) == -1);
Expand Down Expand Up @@ -1222,7 +1241,7 @@ static struct PyMethodDef methods[] = {
{"test_vectorcall", test_vectorcall, METH_NOARGS, _Py_NULL},
{"test_getattr", test_getattr, METH_NOARGS, _Py_NULL},
{"test_getitem", test_getitem, METH_NOARGS, _Py_NULL},
{"test_dict_getitemref", test_dict_getitemref, METH_NOARGS, _Py_NULL},
{"test_dict_api", test_dict_api, METH_NOARGS, _Py_NULL},
{_Py_NULL, _Py_NULL, 0, _Py_NULL}
};

Expand Down

0 comments on commit 1b4de24

Please sign in to comment.