Skip to content

Commit fd9bdde

Browse files
gh-94808: cover PyMapping_HasKeyString and PyMapping_HasKey (GH-98486)
(cherry picked from commit 5d30544) Co-authored-by: Nikita Sobolev <[email protected]>
1 parent 5e08585 commit fd9bdde

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

Lib/test/test_capi.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,18 @@ def items(self):
371371
self.assertRaises(TypeError, _testcapi.get_mapping_values, bad_mapping)
372372
self.assertRaises(TypeError, _testcapi.get_mapping_items, bad_mapping)
373373

374+
def test_mapping_has_key(self):
375+
dct = {'a': 1}
376+
self.assertTrue(_testcapi.mapping_has_key(dct, 'a'))
377+
self.assertFalse(_testcapi.mapping_has_key(dct, 'b'))
378+
379+
class SubDict(dict):
380+
pass
381+
382+
dct2 = SubDict({'a': 1})
383+
self.assertTrue(_testcapi.mapping_has_key(dct2, 'a'))
384+
self.assertFalse(_testcapi.mapping_has_key(dct2, 'b'))
385+
374386
@unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'),
375387
'need _testcapi.negative_refcount')
376388
def test_negative_refcount(self):

Modules/_testcapimodule.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5155,6 +5155,40 @@ get_mapping_items(PyObject* self, PyObject *obj)
51555155
return PyMapping_Items(obj);
51565156
}
51575157

5158+
static PyObject *
5159+
test_mapping_has_key_string(PyObject *self, PyObject *Py_UNUSED(args))
5160+
{
5161+
PyObject *context = PyDict_New();
5162+
PyObject *val = PyLong_FromLong(1);
5163+
5164+
// Since this uses `const char*` it is easier to test this in C:
5165+
PyDict_SetItemString(context, "a", val);
5166+
if (!PyMapping_HasKeyString(context, "a")) {
5167+
PyErr_SetString(PyExc_RuntimeError,
5168+
"Existing mapping key does not exist");
5169+
return NULL;
5170+
}
5171+
if (PyMapping_HasKeyString(context, "b")) {
5172+
PyErr_SetString(PyExc_RuntimeError,
5173+
"Missing mapping key exists");
5174+
return NULL;
5175+
}
5176+
5177+
Py_DECREF(val);
5178+
Py_DECREF(context);
5179+
Py_RETURN_NONE;
5180+
}
5181+
5182+
static PyObject *
5183+
mapping_has_key(PyObject* self, PyObject *args)
5184+
{
5185+
PyObject *context, *key;
5186+
if (!PyArg_ParseTuple(args, "OO", &context, &key)) {
5187+
return NULL;
5188+
}
5189+
return PyLong_FromLong(PyMapping_HasKey(context, key));
5190+
}
5191+
51585192

51595193
static PyObject *
51605194
test_pythread_tss_key_state(PyObject *self, PyObject *args)
@@ -5894,6 +5928,8 @@ static PyMethodDef TestMethods[] = {
58945928
{"get_mapping_keys", get_mapping_keys, METH_O},
58955929
{"get_mapping_values", get_mapping_values, METH_O},
58965930
{"get_mapping_items", get_mapping_items, METH_O},
5931+
{"test_mapping_has_key_string", test_mapping_has_key_string, METH_NOARGS},
5932+
{"mapping_has_key", mapping_has_key, METH_VARARGS},
58975933
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
58985934
{"hamt", new_hamt, METH_NOARGS},
58995935
{"bad_get", (PyCFunction)(void(*)(void))bad_get, METH_FASTCALL},

0 commit comments

Comments
 (0)