https://github.com/python/cpython/commit/f8d2f9fe67f8ab279cf7c5f6fa6a4feb588ce8f0
commit: f8d2f9fe67f8ab279cf7c5f6fa6a4feb588ce8f0
branch: main
author: Stan Ulbrych <[email protected]>
committer: vstinner <[email protected]>
date: 2026-03-02T20:45:03+01:00
summary:

gh-145118: Add `frozendict` support to `type()` (#145124)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-02-22-19-05-03.gh-issue-145118.bU6Sic.rst
M Lib/test/test_builtin.py
M Objects/typeobject.c

diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 7b69374b1868d1..eabfdcd447f2bb 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -2993,6 +2993,12 @@ def test_type_doc(self):
             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
index 00000000000000..24507d4a411f85
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-22-19-05-03.gh-issue-145118.bU6Sic.rst
@@ -0,0 +1 @@
+:func:`type` now accepts :class:`frozendict` as an argument.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index ad26339c9c34df..d77d981085f4da 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -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,

_______________________________________________
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]

Reply via email to