https://github.com/python/cpython/commit/9e083b57eeb0282f8c5f7bbeec3750b51cf80dcc
commit: 9e083b57eeb0282f8c5f7bbeec3750b51cf80dcc
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-02-21T17:00:23+01:00
summary:
gh-141510: Test frozendict C API (#145081)
Add tests on functions:
* PyAnyDict_Check()
* PyAnyDict_CheckExact()
* PyFrozenDict_Check()
* PyFrozenDict_CheckExact()
* PyFrozenDict_New()
files:
M Lib/test/test_capi/test_dict.py
M Modules/_testcapi/dict.c
diff --git a/Lib/test/test_capi/test_dict.py b/Lib/test/test_capi/test_dict.py
index e726e3d813d888..bdd7aa9819fc48 100644
--- a/Lib/test/test_capi/test_dict.py
+++ b/Lib/test/test_capi/test_dict.py
@@ -26,6 +26,19 @@ def gen():
yield 'c'
+class FrozenDictSubclass(frozendict):
+ pass
+
+
+DICT_TYPES = (dict, DictSubclass, OrderedDict)
+FROZENDICT_TYPES = (frozendict, FrozenDictSubclass)
+ANYDICT_TYPES = DICT_TYPES + FROZENDICT_TYPES
+MAPPING_TYPES = (UserDict,)
+NOT_FROZENDICT_TYPES = DICT_TYPES + MAPPING_TYPES
+NOT_ANYDICT_TYPES = MAPPING_TYPES
+OTHER_TYPES = (lambda: [1], lambda: 42, object) # (list, int, object)
+
+
class CAPITest(unittest.TestCase):
def test_dict_check(self):
@@ -545,6 +558,61 @@ def test_dict_popstring(self):
# CRASHES dict_popstring({}, NULL)
# CRASHES dict_popstring({"a": 1}, NULL)
+ def test_frozendict_check(self):
+ # Test PyFrozenDict_Check()
+ check = _testcapi.frozendict_check
+ for dict_type in FROZENDICT_TYPES:
+ self.assertTrue(check(dict_type(x=1)))
+ for dict_type in NOT_FROZENDICT_TYPES + OTHER_TYPES:
+ self.assertFalse(check(dict_type()))
+ # CRASHES check(NULL)
+
+ def test_frozendict_checkexact(self):
+ # Test PyFrozenDict_CheckExact()
+ check = _testcapi.frozendict_checkexact
+ for dict_type in FROZENDICT_TYPES:
+ self.assertEqual(check(dict_type(x=1)), dict_type == frozendict)
+ for dict_type in NOT_FROZENDICT_TYPES + OTHER_TYPES:
+ self.assertFalse(check(dict_type()))
+ # CRASHES check(NULL)
+
+ def test_anydict_check(self):
+ # Test PyAnyDict_Check()
+ check = _testcapi.anydict_check
+ for dict_type in ANYDICT_TYPES:
+ self.assertTrue(check(dict_type({1: 2})))
+ for test_type in NOT_ANYDICT_TYPES + OTHER_TYPES:
+ self.assertFalse(check(test_type()))
+ # CRASHES check(NULL)
+
+ def test_anydict_checkexact(self):
+ # Test PyAnyDict_CheckExact()
+ check = _testcapi.anydict_checkexact
+ for dict_type in ANYDICT_TYPES:
+ self.assertEqual(check(dict_type(x=1)),
+ dict_type in (dict, frozendict))
+ for test_type in NOT_ANYDICT_TYPES + OTHER_TYPES:
+ self.assertFalse(check(test_type()))
+ # CRASHES check(NULL)
+
+ def test_frozendict_new(self):
+ # Test PyFrozenDict_New()
+ frozendict_new = _testcapi.frozendict_new
+
+ for dict_type in ANYDICT_TYPES:
+ dct = frozendict_new(dict_type({'x': 1}))
+ self.assertEqual(dct, frozendict(x=1))
+ self.assertIs(type(dct), frozendict)
+
+ dct = frozendict_new([('x', 1), ('y', 2)])
+ self.assertEqual(dct, frozendict(x=1, y=2))
+ self.assertIs(type(dct), frozendict)
+
+ # PyFrozenDict_New(NULL) creates an empty dictionary
+ dct = frozendict_new(NULL)
+ self.assertEqual(dct, frozendict())
+ self.assertIs(type(dct), frozendict)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Modules/_testcapi/dict.c b/Modules/_testcapi/dict.c
index b7c73d7332bd4e..172591b03182ab 100644
--- a/Modules/_testcapi/dict.c
+++ b/Modules/_testcapi/dict.c
@@ -258,6 +258,43 @@ test_dict_iteration(PyObject* self, PyObject
*Py_UNUSED(ignored))
}
+static PyObject *
+frozendict_check(PyObject *self, PyObject *obj)
+{
+ NULLABLE(obj);
+ return PyLong_FromLong(PyFrozenDict_Check(obj));
+}
+
+static PyObject *
+frozendict_checkexact(PyObject *self, PyObject *obj)
+{
+ NULLABLE(obj);
+ return PyLong_FromLong(PyFrozenDict_CheckExact(obj));
+}
+
+static PyObject *
+anydict_check(PyObject *self, PyObject *obj)
+{
+ NULLABLE(obj);
+ return PyLong_FromLong(PyAnyDict_Check(obj));
+}
+
+static PyObject *
+anydict_checkexact(PyObject *self, PyObject *obj)
+{
+ NULLABLE(obj);
+ return PyLong_FromLong(PyAnyDict_CheckExact(obj));
+}
+
+
+static PyObject *
+frozendict_new(PyObject *self, PyObject *obj)
+{
+ NULLABLE(obj);
+ return PyFrozenDict_New(obj);
+}
+
+
static PyMethodDef test_methods[] = {
{"dict_containsstring", dict_containsstring, METH_VARARGS},
{"dict_getitemref", dict_getitemref, METH_VARARGS},
@@ -269,6 +306,11 @@ static PyMethodDef test_methods[] = {
{"dict_popstring", dict_popstring, METH_VARARGS},
{"dict_popstring_null", dict_popstring_null, METH_VARARGS},
{"test_dict_iteration", test_dict_iteration, METH_NOARGS},
+ {"frozendict_check", frozendict_check, METH_O},
+ {"frozendict_checkexact", frozendict_checkexact, METH_O},
+ {"anydict_check", anydict_check, METH_O},
+ {"anydict_checkexact", anydict_checkexact, METH_O},
+ {"frozendict_new", frozendict_new, METH_O},
{NULL},
};
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]