diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 383ccad9df041b5..5e8c452a5ab9a1f 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -486,7 +486,7 @@ Encoders and Decoders +----------------------------------------+---------------+ | Python | JSON | +========================================+===============+ - | dict | object | + | dict, frozendict | object | +----------------------------------------+---------------+ | list, tuple | array | +----------------------------------------+---------------+ @@ -504,6 +504,9 @@ Encoders and Decoders .. versionchanged:: 3.4 Added support for int- and float-derived Enum classes. + .. versionchanged:: 3.15 + Added support for :class:`frozendict`. + To extend this to recognize other objects, subclass and implement a :meth:`~JSONEncoder.default` method with another method that returns a serializable object for ``o`` if possible, otherwise it should call the superclass implementation diff --git a/Lib/calendar.py b/Lib/calendar.py index 92fe6b7723fe268..7aaaf73bfe0044b 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -609,11 +609,11 @@ def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None): content = self.formatyear(theyear, width) return self._format_html_page(theyear, content, css, encoding) - def formatmonthpage(self, theyear, themonth, width=3, css='calendar.css', encoding=None): + def formatmonthpage(self, theyear, themonth, *, css='calendar.css', encoding=None): """ Return a formatted month as a complete HTML page. """ - content = self.formatmonth(theyear, themonth, width) + content = self.formatmonth(theyear, themonth) return self._format_html_page(theyear, content, css, encoding) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 15cce2b30da5768..f1bbee24cba1ca7 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -545,6 +545,12 @@ def test_format_html_year_with_month(self): result_2009_6_html ) + def test_formatmonthpage_no_width(self): + # gh-140212: formatmonthpage must not accept a 'width' argument. + cal = calendar.HTMLCalendar() + self.assertIn(b'class="month">June 2009', cal.formatmonthpage(2009, 6)) + self.assertRaises(TypeError, cal.formatmonthpage, 2009, 6, width=3) + class CalendarTestCase(unittest.TestCase): diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index 9c4d91c456dc5d9..0e71d65f22b4f0d 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -386,6 +386,16 @@ def test_reference_loop_frozendict(self): for v in range(marshal.version + 1): self.assertRaises(ValueError, marshal.dumps, a, v) + def test_shared_reference_frozendict(self): + # A frozendict referenced more than once must round-trip with the + # shared identity preserved, like frozenset. + fd = frozendict({'a': 1, 'b': 2}) + out = marshal.loads(marshal.dumps([fd, fd])) + self.assertEqual(out[0], fd) + self.assertIs(out[0], out[1]) + nested = marshal.loads(marshal.dumps(frozendict({'x': fd, 'y': fd}))) + self.assertIs(nested['x'], nested['y']) + def test_loads_reference_loop_list(self): data = b'\xdb\x01\x00\x00\x00r\x00\x00\x00\x00' # [] a = marshal.loads(data) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-14-45-02.gh-issue-155315.Mk9Fd2.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-14-45-02.gh-issue-155315.Mk9Fd2.rst new file mode 100644 index 000000000000000..a62059c0fa26160 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-14-45-02.gh-issue-155315.Mk9Fd2.rst @@ -0,0 +1,3 @@ +Fix :mod:`marshal` so that a ``frozendict`` referenced more than once in the +serialized data round-trips correctly, instead of failing to load with +:exc:`ValueError`. Patch by tonghuaroot. diff --git a/Misc/NEWS.d/next/Library/2026-07-06-10-30-00.gh-issue-153158.m0nthP.rst b/Misc/NEWS.d/next/Library/2026-07-06-10-30-00.gh-issue-153158.m0nthP.rst new file mode 100644 index 000000000000000..3850860fb2f8db1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-06-10-30-00.gh-issue-153158.m0nthP.rst @@ -0,0 +1,3 @@ +Remove the erroneous *width* argument of +:meth:`!calendar.HTMLCalendar.formatmonthpage`, which could drop the year from +the heading. diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index e742a25e4891fce..031e972aeba0312 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -1273,8 +1273,7 @@ _sre_SRE_Pattern_split_impl(PatternObject *self, PyObject *string, ); if (!item) goto error; - status = PyList_Append(list, item); - Py_DECREF(item); + status = _PyList_AppendTakeRef((PyListObject *)list, item); if (status < 0) goto error; @@ -1283,8 +1282,7 @@ _sre_SRE_Pattern_split_impl(PatternObject *self, PyObject *string, item = state_getslice(&state, i+1, string, 0); if (!item) goto error; - status = PyList_Append(list, item); - Py_DECREF(item); + status = _PyList_AppendTakeRef((PyListObject *)list, item); if (status < 0) goto error; } @@ -1301,8 +1299,7 @@ _sre_SRE_Pattern_split_impl(PatternObject *self, PyObject *string, ); if (!item) goto error; - status = PyList_Append(list, item); - Py_DECREF(item); + status = _PyList_AppendTakeRef((PyListObject *)list, item); if (status < 0) goto error; diff --git a/Objects/stringlib/split.h b/Objects/stringlib/split.h index 0c11b7214e9b0b8..0b23b6430c8d636 100644 --- a/Objects/stringlib/split.h +++ b/Objects/stringlib/split.h @@ -4,6 +4,8 @@ #error must include "stringlib/fastsearch.h" before including this module #endif +#include "pycore_list.h" // _PyList_AppendTakeRef() + /* Overallocate the initial list to reduce the number of reallocs for small split sizes. Eg, "A A A A A A A A A A".split() (10 elements) has three resizes, to sizes 4, 8, then 16. Most observed string splits are for human @@ -22,12 +24,8 @@ (right) - (left)); \ if (sub == NULL) \ goto onError; \ - if (PyList_Append(list, sub)) { \ - Py_DECREF(sub); \ - goto onError; \ - } \ - else \ - Py_DECREF(sub); + if (_PyList_AppendTakeRef((PyListObject *)list, sub)) \ + goto onError; #define SPLIT_ADD(data, left, right) { \ sub = STRINGLIB_NEW((data) + (left), \ @@ -37,12 +35,8 @@ if (count < MAX_PREALLOC) { \ PyList_SET_ITEM(list, count, sub); \ } else { \ - if (PyList_Append(list, sub)) { \ - Py_DECREF(sub); \ + if (_PyList_AppendTakeRef((PyListObject *)list, sub)) \ goto onError; \ - } \ - else \ - Py_DECREF(sub); \ } \ count++; } diff --git a/Python/marshal.c b/Python/marshal.c index 603697e9081c59a..b11f2dca57a226c 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1505,6 +1505,7 @@ r_object(RFILE *p) } if (type == TYPE_FROZENDICT && v != NULL) { Py_SETREF(v, PyFrozenDict_New(v)); + v = r_ref_insert(v, idx, flag, p); } retval = v; break;