]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-141510: Change marshal version to 6 (#145551)
authorVictor Stinner <vstinner@python.org>
Fri, 6 Mar 2026 09:23:11 +0000 (10:23 +0100)
committerGitHub <noreply@github.com>
Fri, 6 Mar 2026 09:23:11 +0000 (10:23 +0100)
Fix SliceTestCase: test also that version 4 fails with ValueError.

Doc/library/marshal.rst
Include/cpython/marshal.h
Lib/test/test_marshal.py
Misc/NEWS.d/next/Library/2026-03-05-16-06-09.gh-issue-141510.dFPAQS.rst [new file with mode: 0644]
Programs/_freeze_module.c
Python/marshal.c

index ed182ea24e8f3cac00f5814b814f38bdff268a97..25902622b8730b3588a9fea505473547d00afb44 100644 (file)
@@ -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
    ======= =============== ====================================================
 
 
index 6c1f7f96b6a2e81aab5d84cde37900c02bef4423..159459fcaec3d9390aad3bb44077b1cd0be7f89f 100644 (file)
@@ -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 *);
index 28f24d0fc59cb0ac3fa912e4fcf511f43f30c3aa..78db4219e2997c5bffc8f6b5a8f8793b20f1004e 100644 (file)
@@ -570,6 +570,15 @@ class InstancingTestCase(unittest.TestCase, HelperMixin):
             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 @@ class SliceTestCase(unittest.TestCase, HelperMixin):
             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 (file)
index 0000000..280a7b3
--- /dev/null
@@ -0,0 +1,2 @@
+:mod:`marshal` now supports :class:`frozendict` objects. The marshal format
+version was increased to 6. Patch by Victor Stinner.
index a5809b37b6b493fa282883db5642fea34121293d..27a60171f3eca8677609cefbe8d4dc32b93e6fd2 100644 (file)
@@ -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) {
index a71909f103ebfc4847392ef7da95625883ecdc2e..59db6456552c35c189953cbbd1a995b8d161628b 100644 (file)
@@ -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 {