Skip to content

Commit 5d30544

Browse files
authored
gh-94808: cover PyMapping_HasKeyString and PyMapping_HasKey (#98486)
1 parent 216f45e commit 5d30544

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

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

Modules/_testcapimodule.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4690,6 +4690,40 @@ get_mapping_items(PyObject* self, PyObject *obj)
46904690
return PyMapping_Items(obj);
46914691
}
46924692

4693+
static PyObject *
4694+
test_mapping_has_key_string(PyObject *self, PyObject *Py_UNUSED(args))
4695+
{
4696+
PyObject *context = PyDict_New();
4697+
PyObject *val = PyLong_FromLong(1);
4698+
4699+
// Since this uses `const char*` it is easier to test this in C:
4700+
PyDict_SetItemString(context, "a", val);
4701+
if (!PyMapping_HasKeyString(context, "a")) {
4702+
PyErr_SetString(PyExc_RuntimeError,
4703+
"Existing mapping key does not exist");
4704+
return NULL;
4705+
}
4706+
if (PyMapping_HasKeyString(context, "b")) {
4707+
PyErr_SetString(PyExc_RuntimeError,
4708+
"Missing mapping key exists");
4709+
return NULL;
4710+
}
4711+
4712+
Py_DECREF(val);
4713+
Py_DECREF(context);
4714+
Py_RETURN_NONE;
4715+
}
4716+
4717+
static PyObject *
4718+
mapping_has_key(PyObject* self, PyObject *args)
4719+
{
4720+
PyObject *context, *key;
4721+
if (!PyArg_ParseTuple(args, "OO", &context, &key)) {
4722+
return NULL;
4723+
}
4724+
return PyLong_FromLong(PyMapping_HasKey(context, key));
4725+
}
4726+
46934727

46944728
static PyObject *
46954729
test_pythread_tss_key_state(PyObject *self, PyObject *args)
@@ -6054,6 +6088,8 @@ static PyMethodDef TestMethods[] = {
60546088
{"get_mapping_keys", get_mapping_keys, METH_O},
60556089
{"get_mapping_values", get_mapping_values, METH_O},
60566090
{"get_mapping_items", get_mapping_items, METH_O},
6091+
{"test_mapping_has_key_string", test_mapping_has_key_string, METH_NOARGS},
6092+
{"mapping_has_key", mapping_has_key, METH_VARARGS},
60576093
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
60586094
{"hamt", new_hamt, METH_NOARGS},
60596095
{"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL},

0 commit comments

Comments
 (0)