]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-141510: Test frozendict C API (#145081)
authorVictor Stinner <vstinner@python.org>
Sat, 21 Feb 2026 16:00:23 +0000 (17:00 +0100)
committerGitHub <noreply@github.com>
Sat, 21 Feb 2026 16:00:23 +0000 (17:00 +0100)
Add tests on functions:

* PyAnyDict_Check()
* PyAnyDict_CheckExact()
* PyFrozenDict_Check()
* PyFrozenDict_CheckExact()
* PyFrozenDict_New()

Lib/test/test_capi/test_dict.py
Modules/_testcapi/dict.c

index e726e3d813d888ca5035c73bfecba9dc73a2ab2f..bdd7aa9819fc487be7ec165ea6b4ebba19c09223 100644 (file)
@@ -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 @@ class CAPITest(unittest.TestCase):
         # 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()
index b7c73d7332bd4e99ed03ca416c94e4e0f4831f0d..172591b03182abf584a93f5a356b6967d0ff1a4b 100644 (file)
@@ -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},
 };