https://github.com/python/cpython/commit/4fce98a920f47504e834057cd6606bad9b591ea9
commit: 4fce98a920f47504e834057cd6606bad9b591ea9
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-03-06T10:23:11+01:00
summary:

gh-141510: Change marshal version to 6 (#145551)

Fix SliceTestCase: test also that version 4 fails with ValueError.

files:
A Misc/NEWS.d/next/Library/2026-03-05-16-06-09.gh-issue-141510.dFPAQS.rst
M Doc/library/marshal.rst
M Include/cpython/marshal.h
M Lib/test/test_marshal.py
M Programs/_freeze_module.c
M Python/marshal.c

diff --git a/Doc/library/marshal.rst b/Doc/library/marshal.rst
index ed182ea24e8f3c..25902622b8730b 100644
--- a/Doc/library/marshal.rst
+++ b/Doc/library/marshal.rst
@@ -51,8 +51,9 @@ this module.  The following types are supported:
 * Strings (:class:`str`) and :class:`bytes`.
   :term:`Bytes-like objects <bytes-like object>` like :class:`bytearray` are
   marshalled as :class:`!bytes`.
-* Containers: :class:`tuple`, :class:`list`, :class:`set`, :class:`frozenset`,
-  and (since :data:`version` 5), :class:`slice`.
+* Containers: :class:`tuple`, :class:`list`, :class:`dict`, :class:`frozendict`
+  (since :data:`version` 6), :class:`set`, :class:`frozenset`, and
+  :class:`slice` (since :data:`version` 5).
   It should be understood that these are supported only if the values contained
   therein are themselves supported.
   Recursive containers are supported since :data:`version` 3.
@@ -71,6 +72,10 @@ this module.  The following types are supported:
 
    Added format version 5, which allows marshalling slices.
 
+.. versionchanged:: next
+
+   Added format version 6, which allows marshalling :class:`frozendict`.
+
 
 The module defines these functions:
 
@@ -173,6 +178,8 @@ In addition, the following constants are defined:
    4       Python 3.4      Efficient representation of short strings
    ------- --------------- ----------------------------------------------------
    5       Python 3.14     Support for :class:`slice` objects
+   ------- --------------- ----------------------------------------------------
+   6       Python 3.15     Support for :class:`frozendict` objects
    ======= =============== ====================================================
 
 
diff --git a/Include/cpython/marshal.h b/Include/cpython/marshal.h
index 6c1f7f96b6a2e8..159459fcaec3d9 100644
--- a/Include/cpython/marshal.h
+++ b/Include/cpython/marshal.h
@@ -6,7 +6,7 @@ PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(const 
char *,
                                                       Py_ssize_t);
 PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int);
 
-#define Py_MARSHAL_VERSION 5
+#define Py_MARSHAL_VERSION 6
 
 PyAPI_FUNC(long) PyMarshal_ReadLongFromFile(FILE *);
 PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *);
diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
index 28f24d0fc59cb0..78db4219e2997c 100644
--- a/Lib/test/test_marshal.py
+++ b/Lib/test/test_marshal.py
@@ -570,6 +570,15 @@ def testDict(self):
             self.helper(dictobj)
             self.helper3(dictobj)
 
+    def testFrozenDict(self):
+        for obj in self.keys:
+            dictobj = frozendict({"hello": obj, "goodbye": obj, obj: "hello"})
+            self.helper(dictobj)
+
+            for version in range(6):
+                with self.assertRaises(ValueError):
+                    marshal.dumps(dictobj, version)
+
     def testModule(self):
         with open(__file__, "rb") as f:
             code = f.read()
@@ -635,7 +644,7 @@ def test_slice(self):
             with self.subTest(obj=str(obj)):
                 self.helper(obj)
 
-                for version in range(4):
+                for version in range(5):
                     with self.assertRaises(ValueError):
                         marshal.dumps(obj, version)
 
diff --git 
a/Misc/NEWS.d/next/Library/2026-03-05-16-06-09.gh-issue-141510.dFPAQS.rst 
b/Misc/NEWS.d/next/Library/2026-03-05-16-06-09.gh-issue-141510.dFPAQS.rst
new file mode 100644
index 00000000000000..280a7b3632ddae
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-03-05-16-06-09.gh-issue-141510.dFPAQS.rst
@@ -0,0 +1,2 @@
+:mod:`marshal` now supports :class:`frozendict` objects. The marshal format
+version was increased to 6. Patch by Victor Stinner.
diff --git a/Programs/_freeze_module.c b/Programs/_freeze_module.c
index a5809b37b6b493..27a60171f3eca8 100644
--- a/Programs/_freeze_module.c
+++ b/Programs/_freeze_module.c
@@ -134,7 +134,7 @@ compile_and_marshal(const char *name, const char *text)
         return NULL;
     }
 
-    assert(Py_MARSHAL_VERSION >= 5);
+    assert(Py_MARSHAL_VERSION >= 6);
     PyObject *marshalled = PyMarshal_WriteObjectToString(code, 
Py_MARSHAL_VERSION);
     Py_CLEAR(code);
     if (marshalled == NULL) {
diff --git a/Python/marshal.c b/Python/marshal.c
index a71909f103ebfc..59db6456552c35 100644
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -580,6 +580,12 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
         Py_ssize_t pos;
         PyObject *key, *value;
         if (PyFrozenDict_CheckExact(v)) {
+            if (p->version < 6) {
+                w_byte(TYPE_UNKNOWN, p);
+                p->error = WFERR_UNMARSHALLABLE;
+                return;
+            }
+
             W_TYPE(TYPE_FROZENDICT, p);
         }
         else {

_______________________________________________
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