]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-145118: Add `frozendict` support to `type()` (#145124)
authorStan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
Mon, 2 Mar 2026 19:45:03 +0000 (19:45 +0000)
committerGitHub <noreply@github.com>
Mon, 2 Mar 2026 19:45:03 +0000 (20:45 +0100)
Lib/test/test_builtin.py
Misc/NEWS.d/next/Core_and_Builtins/2026-02-22-19-05-03.gh-issue-145118.bU6Sic.rst [new file with mode: 0644]
Objects/typeobject.c

index 7b69374b1868d15e59931528fde5620e95a8c5ce..eabfdcd447f2bb717514b58d412174f692e3c626 100644 (file)
@@ -2993,6 +2993,12 @@ class TestType(unittest.TestCase):
             A.__doc__ = doc
             self.assertEqual(A.__doc__, doc)
 
+    def test_type_frozendict(self):
+        A = type('A', (), frozendict({'x': 4, 'y': 2}))
+        self.assertEqual(A.x, 4)
+        self.assertEqual(A.y, 2)
+        self.assertEqual(A.__name__, 'A')
+
     def test_bad_args(self):
         with self.assertRaises(TypeError):
             type()
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-22-19-05-03.gh-issue-145118.bU6Sic.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-22-19-05-03.gh-issue-145118.bU6Sic.rst
new file mode 100644 (file)
index 0000000..24507d4
--- /dev/null
@@ -0,0 +1 @@
+:func:`type` now accepts :class:`frozendict` as an argument.
index ad26339c9c34df432571a95f3ae903bfff0a2b28..d77d981085f4da26ce8a10c5253841bb867f4d96 100644 (file)
@@ -4872,9 +4872,21 @@ type_new_get_slots(type_new_ctx *ctx, PyObject *dict)
 static PyTypeObject*
 type_new_init(type_new_ctx *ctx)
 {
-    PyObject *dict = PyDict_Copy(ctx->orig_dict);
-    if (dict == NULL) {
-        goto error;
+    PyObject *dict;
+    if (PyFrozenDict_Check(ctx->orig_dict)) {
+        dict = PyDict_New();
+        if (dict == NULL) {
+            goto error;
+        }
+        if (PyDict_Merge(dict, ctx->orig_dict, 1) < 0) {
+            goto error;
+        }
+    }
+    else {
+        dict = PyDict_Copy(ctx->orig_dict);
+        if (dict == NULL) {
+            goto error;
+        }
     }
 
     if (type_new_get_slots(ctx, dict) < 0) {
@@ -5037,13 +5049,19 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
 
     /* Parse arguments: (name, bases, dict) */
     PyObject *name, *bases, *orig_dict;
-    if (!PyArg_ParseTuple(args, "UO!O!:type.__new__",
+    if (!PyArg_ParseTuple(args, "UO!O:type.__new__",
                           &name,
                           &PyTuple_Type, &bases,
-                          &PyDict_Type, &orig_dict))
+                          &orig_dict))
     {
         return NULL;
     }
+    if (!PyAnyDict_Check(orig_dict)) {
+        PyErr_Format(PyExc_TypeError,
+                     "type.__new__() argument 3 must be dict or frozendict, not %T",
+                     orig_dict);
+        return NULL;
+    }
 
     type_new_ctx ctx = {
         .metatype = metatype,