Skip to content

Commit db14a9d

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 2aedba5 commit db14a9d

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
@@ -403,6 +403,18 @@ def items(self):
403403
self.assertRaises(TypeError, _testcapi.get_mapping_values, bad_mapping)
404404
self.assertRaises(TypeError, _testcapi.get_mapping_items, bad_mapping)
405405

406+
def test_mapping_has_key(self):
407+
dct = {'a': 1}
408+
self.assertTrue(_testcapi.mapping_has_key(dct, 'a'))
409+
self.assertFalse(_testcapi.mapping_has_key(dct, 'b'))
410+
411+
class SubDict(dict):
412+
pass
413+
414+
dct2 = SubDict({'a': 1})
415+
self.assertTrue(_testcapi.mapping_has_key(dct2, 'a'))
416+
self.assertFalse(_testcapi.mapping_has_key(dct2, 'b'))
417+
406418
@unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'),
407419
'need _testcapi.negative_refcount')
408420
def test_negative_refcount(self):

Modules/_testcapimodule.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5348,6 +5348,40 @@ get_mapping_items(PyObject* self, PyObject *obj)
53485348
return PyMapping_Items(obj);
53495349
}
53505350

5351+
static PyObject *
5352+
test_mapping_has_key_string(PyObject *self, PyObject *Py_UNUSED(args))
5353+
{
5354+
PyObject *context = PyDict_New();
5355+
PyObject *val = PyLong_FromLong(1);
5356+
5357+
// Since this uses `const char*` it is easier to test this in C:
5358+
PyDict_SetItemString(context, "a", val);
5359+
if (!PyMapping_HasKeyString(context, "a")) {
5360+
PyErr_SetString(PyExc_RuntimeError,
5361+
"Existing mapping key does not exist");
5362+
return NULL;
5363+
}
5364+
if (PyMapping_HasKeyString(context, "b")) {
5365+
PyErr_SetString(PyExc_RuntimeError,
5366+
"Missing mapping key exists");
5367+
return NULL;
5368+
}
5369+
5370+
Py_DECREF(val);
5371+
Py_DECREF(context);
5372+
Py_RETURN_NONE;
5373+
}
5374+
5375+
static PyObject *
5376+
mapping_has_key(PyObject* self, PyObject *args)
5377+
{
5378+
PyObject *context, *key;
5379+
if (!PyArg_ParseTuple(args, "OO", &context, &key)) {
5380+
return NULL;
5381+
}
5382+
return PyLong_FromLong(PyMapping_HasKey(context, key));
5383+
}
5384+
53515385

53525386
static PyObject *
53535387
test_pythread_tss_key_state(PyObject *self, PyObject *args)
@@ -6382,6 +6416,8 @@ static PyMethodDef TestMethods[] = {
63826416
{"get_mapping_keys", get_mapping_keys, METH_O},
63836417
{"get_mapping_values", get_mapping_values, METH_O},
63846418
{"get_mapping_items", get_mapping_items, METH_O},
6419+
{"test_mapping_has_key_string", test_mapping_has_key_string, METH_NOARGS},
6420+
{"mapping_has_key", mapping_has_key, METH_VARARGS},
63856421
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
63866422
{"hamt", new_hamt, METH_NOARGS},
63876423
{"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL},

0 commit comments

Comments
 (0)