From 813fc7a291c98654c27f2b5d8f9afa8e53b066a6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 19 Jan 2026 14:01:29 +0200 Subject: [PATCH 1/7] gh-143754: Modernize Tkinter docs (GH-143841) Use more relevant terminology instead of "master"/"slave" widgets where possible. --- Doc/library/tkinter.rst | 26 +++++++------- Lib/tkinter/__init__.py | 79 +++++++++++++++++++++++------------------ 2 files changed, 58 insertions(+), 47 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 81177533be84c9..07ce8c40577280 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -177,12 +177,12 @@ the modern themed widget set and API:: .. attribute:: master The widget object that contains this widget. For :class:`Tk`, the - *master* is :const:`None` because it is the main window. The terms + :attr:`!master` is :const:`None` because it is the main window. The terms *master* and *parent* are similar and sometimes used interchangeably as argument names; however, calling :meth:`winfo_parent` returns a - string of the widget name whereas :attr:`master` returns the object. + string of the widget name whereas :attr:`!master` returns the object. *parent*/*child* reflects the tree-like relationship while - *master*/*slave* reflects the container structure. + *master* (or *container*)/*content* reflects the container structure. .. attribute:: children @@ -638,15 +638,15 @@ The Packer .. index:: single: packing (widgets) The packer is one of Tk's geometry-management mechanisms. Geometry managers -are used to specify the relative positioning of widgets within their container - -their mutual *master*. In contrast to the more cumbersome *placer* (which is +are used to specify the relative positioning of widgets within their container. +In contrast to the more cumbersome *placer* (which is used less commonly, and we do not cover here), the packer takes qualitative relationship specification - *above*, *to the left of*, *filling*, etc - and works everything out to determine the exact placement coordinates for you. -The size of any *master* widget is determined by the size of the "slave widgets" -inside. The packer is used to control where slave widgets appear inside the -master into which they are packed. You can pack widgets into frames, and frames +The size of any container widget is determined by the size of the "content widgets" +inside. The packer is used to control where content widgets appear inside the +container into which they are packed. You can pack widgets into frames, and frames into other frames, in order to achieve the kind of layout you desire. Additionally, the arrangement is dynamically adjusted to accommodate incremental changes to the configuration, once it is packed. @@ -673,7 +673,7 @@ For more extensive information on the packer and the options that it can take, see the man pages and page 183 of John Ousterhout's book. anchor - Anchor type. Denotes where the packer is to place each slave in its parcel. + Anchor type. Denotes where the packer is to place each content in its parcel. expand Boolean, ``0`` or ``1``. @@ -682,10 +682,10 @@ fill Legal values: ``'x'``, ``'y'``, ``'both'``, ``'none'``. ipadx and ipady - A distance - designating internal padding on each side of the slave widget. + A distance - designating internal padding on each side of the content. padx and pady - A distance - designating external padding on each side of the slave widget. + A distance - designating external padding on each side of the content. side Legal values are: ``'left'``, ``'right'``, ``'top'``, ``'bottom'``. @@ -758,8 +758,8 @@ subclassed from the :class:`Wm` class, and so can call the :class:`Wm` methods directly. To get at the toplevel window that contains a given widget, you can often just -refer to the widget's master. Of course if the widget has been packed inside of -a frame, the master won't represent a toplevel window. To get at the toplevel +refer to the widget's :attr:`master`. Of course if the widget has been packed inside of +a frame, the :attr:`!master` won't represent a toplevel window. To get at the toplevel window that contains an arbitrary widget, you can call the :meth:`_root` method. This method begins with an underscore to denote the fact that this function is part of the implementation, and not an interface to Tk functionality. diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 737583a42c6399..be150e2b892e4b 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1867,15 +1867,15 @@ def __repr__(self): return '<%s.%s object %s>' % ( self.__class__.__module__, self.__class__.__qualname__, self._w) - # Pack methods that apply to the master + # Pack methods that apply to the container widget _noarg_ = ['_noarg_'] def pack_propagate(self, flag=_noarg_): """Set or get the status for propagation of geometry information. - A boolean argument specifies whether the geometry information - of the slaves will determine the size of this widget. If no argument - is given the current setting will be returned. + A boolean argument specifies whether the size of this container will + be determined by the geometry information of its content. + If no argument is given the current setting will be returned. """ if flag is Misc._noarg_: return self._getboolean(self.tk.call( @@ -1886,28 +1886,28 @@ def pack_propagate(self, flag=_noarg_): propagate = pack_propagate def pack_slaves(self): - """Return a list of all slaves of this widget - in its packing order.""" + """Returns a list of all of the content widgets in the packing order + for this container.""" return [self._nametowidget(x) for x in self.tk.splitlist( self.tk.call('pack', 'slaves', self._w))] slaves = pack_slaves - # Place method that applies to the master + # Place method that applies to the container widget def place_slaves(self): - """Return a list of all slaves of this widget - in its packing order.""" + """Returns a list of all the content widgets for which this widget is + the container.""" return [self._nametowidget(x) for x in self.tk.splitlist( self.tk.call( 'place', 'slaves', self._w))] - # Grid methods that apply to the master + # Grid methods that apply to the container widget def grid_anchor(self, anchor=None): # new in Tk 8.5 """The anchor value controls how to place the grid within the - master when no row/column has any weight. + container widget when no row/column has any weight. The default anchor is nw.""" self.tk.call('grid', 'anchor', self._w, anchor) @@ -1924,7 +1924,7 @@ def grid_bbox(self, column=None, row=None, col2=None, row2=None): starts at that cell. The returned integers specify the offset of the upper left - corner in the master widget and the width and height. + corner in the container widget and the width and height. """ args = ('grid', 'bbox', self._w) if column is not None and row is not None: @@ -1982,7 +1982,7 @@ def grid_columnconfigure(self, index, cnf={}, **kw): def grid_location(self, x, y): """Return a tuple of column and row which identify the cell - at which the pixel at position X and Y inside the master + at which the pixel at position X and Y inside the container widget is located.""" return self._getints( self.tk.call( @@ -1991,9 +1991,9 @@ def grid_location(self, x, y): def grid_propagate(self, flag=_noarg_): """Set or get the status for propagation of geometry information. - A boolean argument specifies whether the geometry information - of the slaves will determine the size of this widget. If no argument - is given, the current setting will be returned. + A boolean argument specifies whether the size of this container will + be determined by the geometry information of its content. + If no argument is given the current setting will be returned. """ if flag is Misc._noarg_: return self._getboolean(self.tk.call( @@ -2019,8 +2019,13 @@ def grid_size(self): size = grid_size def grid_slaves(self, row=None, column=None): - """Return a list of all slaves of this widget - in its packing order.""" + """Returns a list of the content widgets. + + If no arguments are supplied, a list of all of the content in this + container widget is returned, most recently managed first. + If ROW or COLUMN is specified, only the content in the row or + column is returned. + """ args = () if row is not None: args = args + ('-row', row) @@ -2606,8 +2611,8 @@ def pack_configure(self, cnf={}, **kw): before=widget - pack it before you will pack widget expand=bool - expand widget if parent size grows fill=NONE or X or Y or BOTH - fill widget if widget grows - in=master - use master to contain this widget - in_=master - see 'in' option description + in=container - use the container widget to contain this widget + in_=container - see 'in' option description ipadx=amount - add internal padding in x direction ipady=amount - add internal padding in y direction padx=amount - add padding in x direction @@ -2646,25 +2651,31 @@ class Place: def place_configure(self, cnf={}, **kw): """Place a widget in the parent widget. Use as options: - in=master - master relative to which the widget is placed - in_=master - see 'in' option description - x=amount - locate anchor of this widget at position x of master - y=amount - locate anchor of this widget at position y of master + in=container - the container widget relative to which this widget is + placed + in_=container - see 'in' option description + x=amount - locate anchor of this widget at position x of the + container widget + y=amount - locate anchor of this widget at position y of the + container widget relx=amount - locate anchor of this widget between 0.0 and 1.0 - relative to width of master (1.0 is right edge) + relative to width of the container widget (1.0 is + right edge) rely=amount - locate anchor of this widget between 0.0 and 1.0 - relative to height of master (1.0 is bottom edge) - anchor=NSEW (or subset) - position anchor according to given direction + relative to height of the container widget (1.0 is + bottom edge) + anchor=NSEW (or subset) - position anchor according to given + direction width=amount - width of this widget in pixel height=amount - height of this widget in pixel relwidth=amount - width of this widget between 0.0 and 1.0 - relative to width of master (1.0 is the same width - as the master) + relative to width of the container widget (1.0 is + the same width as the container widget) relheight=amount - height of this widget between 0.0 and 1.0 - relative to height of master (1.0 is the same - height as the master) + relative to height of the container widget (1.0 + is the same height as the container widget) bordermode="inside" or "outside" - whether to take border width of - master widget into account + the container widget into account """ self.tk.call( ('place', 'configure', self._w) @@ -2700,8 +2711,8 @@ def grid_configure(self, cnf={}, **kw): """Position a widget in the parent widget in a grid. Use as options: column=number - use cell identified with given column (starting with 0) columnspan=number - this widget will span several columns - in=master - use master to contain this widget - in_=master - see 'in' option description + in=container - use the container widget to contain this widget + in_=container - see 'in' option description ipadx=amount - add internal padding in x direction ipady=amount - add internal padding in y direction padx=amount - add padding in x direction From 7dca4e3af118328d7013b58106d129b162047cb3 Mon Sep 17 00:00:00 2001 From: AZero13 Date: Mon, 19 Jan 2026 07:19:20 -0500 Subject: [PATCH 2/7] gh-142440: Fix _decimal builds configured with EXTRA_FUNCTIONALITY (GH-142441) There was a typo in _decimal.Context.apply(). --- .../next/Library/2025-12-08-18-40-17.gh-issue-142438.tH-Y16.rst | 2 ++ Modules/_decimal/_decimal.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-08-18-40-17.gh-issue-142438.tH-Y16.rst diff --git a/Misc/NEWS.d/next/Library/2025-12-08-18-40-17.gh-issue-142438.tH-Y16.rst b/Misc/NEWS.d/next/Library/2025-12-08-18-40-17.gh-issue-142438.tH-Y16.rst new file mode 100644 index 00000000000000..5c1db433e1b14b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-08-18-40-17.gh-issue-142438.tH-Y16.rst @@ -0,0 +1,2 @@ +Fix _decimal builds configured with EXTRA_FUNCTIONALITY by correcting the +Context.apply wrapper to pass the right argument. diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 33e624e342eaee..dcea4da8f24268 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -6991,7 +6991,7 @@ _decimal_Context_apply_impl(PyObject *context, PyTypeObject *cls, PyObject *x) /*[clinic end generated code: output=f8a7142d47ad4ff3 input=388e66ca82733516]*/ { - return _decimal_Context__apply(context, v); + return _decimal_Context__apply(context, x); } #endif From bb2b9ba49d8a60629f0905bc27191fc84db39879 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 19 Jan 2026 14:37:41 +0200 Subject: [PATCH 3/7] gh-143897: Remove the isxidstart() and isxidcontinue() methods of unicodedata.ucd_3_2_0 (GH-143898) They are now only exposed as the unicodedata function. --- Lib/test/test_unicodedata.py | 27 +++++++------- ...-01-16-10-53-17.gh-issue-143897.hWJBHN.rst | 3 ++ Modules/clinic/unicodedata.c.h | 30 ++++++++-------- Modules/unicodedata.c | 36 +++++-------------- 4 files changed, 39 insertions(+), 57 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-16-10-53-17.gh-issue-143897.hWJBHN.rst diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index 07aa992de6d706..f9c0cd20438174 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -83,15 +83,7 @@ def test_method_checksum(self): self.assertEqual(result, self.expectedchecksum) -class UnicodeFunctionsTest(unittest.TestCase): - db = unicodedata - old = False - - # Update this if the database changes. Make sure to do a full rebuild - # (e.g. 'make distclean && make') to get the correct checksum. - expectedchecksum = ('83cc43a2fbb779185832b4c049217d80b05bf349' - if quicktest else - '65670ae03a324c5f9e826a4de3e25bae4d73c9b7') +class BaseUnicodeFunctionsTest: def test_function_checksum(self): db = self.db @@ -589,6 +581,16 @@ def test_east_asian_width_unassigned(self): self.assertEqual(eaw(char), 'A') self.assertIs(self.db.name(char, None), None) +class UnicodeFunctionsTest(unittest.TestCase, BaseUnicodeFunctionsTest): + db = unicodedata + old = False + + # Update this if the database changes. Make sure to do a full rebuild + # (e.g. 'make distclean && make') to get the correct checksum. + expectedchecksum = ('83cc43a2fbb779185832b4c049217d80b05bf349' + if quicktest else + '65670ae03a324c5f9e826a4de3e25bae4d73c9b7') + def test_isxidstart(self): self.assertTrue(self.db.isxidstart('S')) self.assertTrue(self.db.isxidstart('\u0AD0')) # GUJARATI OM @@ -832,18 +834,13 @@ def graphemes(*args): ['a', '\U0001F1FA\U0001F1E6', '\U0001F1FA\U0001F1F3']) -class Unicode_3_2_0_FunctionsTest(UnicodeFunctionsTest): +class Unicode_3_2_0_FunctionsTest(unittest.TestCase, BaseUnicodeFunctionsTest): db = unicodedata.ucd_3_2_0 old = True expectedchecksum = ('f4526159891a4b766dd48045646547178737ba09' if quicktest else 'f217b8688d7bdff31db4207e078a96702f091597') - test_grapheme_cluster_break = None - test_indic_conjunct_break = None - test_extended_pictographic = None - test_grapheme_break = None - class UnicodeMiscTest(unittest.TestCase): db = unicodedata diff --git a/Misc/NEWS.d/next/Library/2026-01-16-10-53-17.gh-issue-143897.hWJBHN.rst b/Misc/NEWS.d/next/Library/2026-01-16-10-53-17.gh-issue-143897.hWJBHN.rst new file mode 100644 index 00000000000000..d53eac0bd356ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-16-10-53-17.gh-issue-143897.hWJBHN.rst @@ -0,0 +1,3 @@ +Remove the :meth:`!isxidstart` and :meth:`!isxidcontinue` methods of +:data:`unicodedata.ucd_3_2_0`. They are now only exposed as +:func:`unicodedata.isxidstart` and :func:`unicodedata.isxidcontinue`. diff --git a/Modules/clinic/unicodedata.c.h b/Modules/clinic/unicodedata.c.h index c0497cf45f6cff..8e2dd7a0ce5663 100644 --- a/Modules/clinic/unicodedata.c.h +++ b/Modules/clinic/unicodedata.c.h @@ -519,20 +519,20 @@ unicodedata_UCD_name(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return return_value; } -PyDoc_STRVAR(unicodedata_UCD_isxidstart__doc__, -"isxidstart($self, chr, /)\n" +PyDoc_STRVAR(unicodedata_isxidstart__doc__, +"isxidstart($module, chr, /)\n" "--\n" "\n" "Return True if the character has the XID_Start property, else False."); -#define UNICODEDATA_UCD_ISXIDSTART_METHODDEF \ - {"isxidstart", (PyCFunction)unicodedata_UCD_isxidstart, METH_O, unicodedata_UCD_isxidstart__doc__}, +#define UNICODEDATA_ISXIDSTART_METHODDEF \ + {"isxidstart", (PyCFunction)unicodedata_isxidstart, METH_O, unicodedata_isxidstart__doc__}, static PyObject * -unicodedata_UCD_isxidstart_impl(PyObject *self, int chr); +unicodedata_isxidstart_impl(PyObject *module, int chr); static PyObject * -unicodedata_UCD_isxidstart(PyObject *self, PyObject *arg) +unicodedata_isxidstart(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int chr; @@ -549,26 +549,26 @@ unicodedata_UCD_isxidstart(PyObject *self, PyObject *arg) goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); - return_value = unicodedata_UCD_isxidstart_impl(self, chr); + return_value = unicodedata_isxidstart_impl(module, chr); exit: return return_value; } -PyDoc_STRVAR(unicodedata_UCD_isxidcontinue__doc__, -"isxidcontinue($self, chr, /)\n" +PyDoc_STRVAR(unicodedata_isxidcontinue__doc__, +"isxidcontinue($module, chr, /)\n" "--\n" "\n" "Return True if the character has the XID_Continue property, else False."); -#define UNICODEDATA_UCD_ISXIDCONTINUE_METHODDEF \ - {"isxidcontinue", (PyCFunction)unicodedata_UCD_isxidcontinue, METH_O, unicodedata_UCD_isxidcontinue__doc__}, +#define UNICODEDATA_ISXIDCONTINUE_METHODDEF \ + {"isxidcontinue", (PyCFunction)unicodedata_isxidcontinue, METH_O, unicodedata_isxidcontinue__doc__}, static PyObject * -unicodedata_UCD_isxidcontinue_impl(PyObject *self, int chr); +unicodedata_isxidcontinue_impl(PyObject *module, int chr); static PyObject * -unicodedata_UCD_isxidcontinue(PyObject *self, PyObject *arg) +unicodedata_isxidcontinue(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int chr; @@ -585,7 +585,7 @@ unicodedata_UCD_isxidcontinue(PyObject *self, PyObject *arg) goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); - return_value = unicodedata_UCD_isxidcontinue_impl(self, chr); + return_value = unicodedata_isxidcontinue_impl(module, chr); exit: return return_value; @@ -798,4 +798,4 @@ unicodedata_extended_pictographic(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=6991246310e3f2aa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0f09cc90f06ace76 input=a9049054013a1b77]*/ diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 6904ee14811d48..586ce8d36dd46f 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -1565,9 +1565,8 @@ unicodedata_UCD_name_impl(PyObject *self, int chr, PyObject *default_value) } /*[clinic input] -unicodedata.UCD.isxidstart +unicodedata.isxidstart - self: self chr: int(accept={str}) / @@ -1576,24 +1575,15 @@ Return True if the character has the XID_Start property, else False. [clinic start generated code]*/ static PyObject * -unicodedata_UCD_isxidstart_impl(PyObject *self, int chr) -/*[clinic end generated code: output=944005823c72c3ef input=9353f88d709c21fb]*/ +unicodedata_isxidstart_impl(PyObject *module, int chr) +/*[clinic end generated code: output=7ae0e1a3915aa031 input=3812717f3a6bfc56]*/ { - if (UCD_Check(self)) { - const change_record *old = get_old_record(self, chr); - if (old->category_changed == 0) { - /* unassigned */ - Py_RETURN_FALSE; - } - } - return PyBool_FromLong(_PyUnicode_IsXidStart(chr)); } /*[clinic input] -unicodedata.UCD.isxidcontinue +unicodedata.isxidcontinue - self: self chr: int(accept={str}) / @@ -1602,17 +1592,9 @@ Return True if the character has the XID_Continue property, else False. [clinic start generated code]*/ static PyObject * -unicodedata_UCD_isxidcontinue_impl(PyObject *self, int chr) -/*[clinic end generated code: output=9438dcbff5ca3e41 input=bbb8dd3ac0d2d709]*/ +unicodedata_isxidcontinue_impl(PyObject *module, int chr) +/*[clinic end generated code: output=517caa8b38c73aed input=a971ed6e57cac374]*/ { - if (UCD_Check(self)) { - const change_record *old = get_old_record(self, chr); - if (old->category_changed == 0) { - /* unassigned */ - Py_RETURN_FALSE; - } - } - return PyBool_FromLong(_PyUnicode_IsXidContinue(chr)); } @@ -2128,10 +2110,12 @@ static PyMethodDef unicodedata_functions[] = { UNICODEDATA_INDIC_CONJUNCT_BREAK_METHODDEF UNICODEDATA_EXTENDED_PICTOGRAPHIC_METHODDEF UNICODEDATA_ITER_GRAPHEMES_METHODDEF + UNICODEDATA_ISXIDSTART_METHODDEF + UNICODEDATA_ISXIDCONTINUE_METHODDEF // The following definitions are shared between the module // and the UCD class. -#define DB_methods (unicodedata_functions + 4) +#define DB_methods (unicodedata_functions + 6) UNICODEDATA_UCD_DECIMAL_METHODDEF UNICODEDATA_UCD_DIGIT_METHODDEF @@ -2143,8 +2127,6 @@ static PyMethodDef unicodedata_functions[] = { UNICODEDATA_UCD_EAST_ASIAN_WIDTH_METHODDEF UNICODEDATA_UCD_DECOMPOSITION_METHODDEF UNICODEDATA_UCD_NAME_METHODDEF - UNICODEDATA_UCD_ISXIDSTART_METHODDEF - UNICODEDATA_UCD_ISXIDCONTINUE_METHODDEF UNICODEDATA_UCD_LOOKUP_METHODDEF UNICODEDATA_UCD_IS_NORMALIZED_METHODDEF UNICODEDATA_UCD_NORMALIZE_METHODDEF From 17d1490aa97bd6b98a42b1a9b324ead84e7fd8a2 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Mon, 19 Jan 2026 06:38:22 -0600 Subject: [PATCH 4/7] gh-143935: Email preserve parens when folding comments (#143936) Fix a bug in the folding of comments when flattening an email message using a modern email policy. Comments consisting of a very long sequence of non-foldable characters could trigger a forced line wrap that omitted the required leading space on the continuation line, causing the remainder of the comment to be interpreted as a new header field. This enabled header injection with carefully crafted inputs. Co-authored-by: Denis Ledoux --- Lib/email/_header_value_parser.py | 15 +++++++++++- .../test_email/test__header_value_parser.py | 23 +++++++++++++++++++ ...-01-16-14-40-31.gh-issue-143935.U2YtKl.rst | 6 +++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index 46fef2048babe7..172f9ef9e5f096 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -101,6 +101,12 @@ def make_quoted_pairs(value): return str(value).replace('\\', '\\\\').replace('"', '\\"') +def make_parenthesis_pairs(value): + """Escape parenthesis and backslash for use within a comment.""" + return str(value).replace('\\', '\\\\') \ + .replace('(', '\\(').replace(')', '\\)') + + def quote_string(value): escaped = make_quoted_pairs(value) return f'"{escaped}"' @@ -943,7 +949,7 @@ def value(self): return ' ' def startswith_fws(self): - return True + return self and self[0] in WSP class ValueTerminal(Terminal): @@ -2963,6 +2969,13 @@ def _refold_parse_tree(parse_tree, *, policy): [ValueTerminal(make_quoted_pairs(p), 'ptext') for p in newparts] + [ValueTerminal('"', 'ptext')]) + if part.token_type == 'comment': + newparts = ( + [ValueTerminal('(', 'ptext')] + + [ValueTerminal(make_parenthesis_pairs(p), 'ptext') + if p.token_type == 'ptext' else p + for p in newparts] + + [ValueTerminal(')', 'ptext')]) if not part.as_ew_allowed: wrap_as_ew_blocked += 1 newparts.append(end_ew_not_allowed) diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py index 426ec4644e3096..e28fe3892015b9 100644 --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -3294,6 +3294,29 @@ def test_address_list_with_specials_in_long_quoted_string(self): with self.subTest(to=to): self._test(parser.get_address_list(to)[0], folded, policy=policy) + def test_address_list_with_long_unwrapable_comment(self): + policy = self.policy.clone(max_line_length=40) + cases = [ + # (to, folded) + ('(loremipsumdolorsitametconsecteturadipi)', + '(loremipsumdolorsitametconsecteturadipi)\n'), + ('(loremipsumdolorsitametconsecteturadipi)', + '(loremipsumdolorsitametconsecteturadipi)\n'), + ('(loremipsum dolorsitametconsecteturadipi)', + '(loremipsum dolorsitametconsecteturadipi)\n'), + ('(loremipsum dolorsitametconsecteturadipi)', + '(loremipsum\n dolorsitametconsecteturadipi)\n'), + ('(Escaped \\( \\) chars \\\\ in comments stay escaped)', + '(Escaped \\( \\) chars \\\\ in comments stay\n escaped)\n'), + ('((loremipsum)(loremipsum)(loremipsum)(loremipsum))', + '((loremipsum)(loremipsum)(loremipsum)(loremipsum))\n'), + ('((loremipsum)(loremipsum)(loremipsum) (loremipsum))', + '((loremipsum)(loremipsum)(loremipsum)\n (loremipsum))\n'), + ] + for (to, folded) in cases: + with self.subTest(to=to): + self._test(parser.get_address_list(to)[0], folded, policy=policy) + # XXX Need tests with comments on various sides of a unicode token, # and with unicode tokens in the comments. Spaces inside the quotes # currently don't do the right thing. diff --git a/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst b/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst new file mode 100644 index 00000000000000..c3d864936884ac --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst @@ -0,0 +1,6 @@ +Fixed a bug in the folding of comments when flattening an email message +using a modern email policy. Comments consisting of a very long sequence of +non-foldable characters could trigger a forced line wrap that omitted the +required leading space on the continuation line, causing the remainder of +the comment to be interpreted as a new header field. This enabled header +injection with carefully crafted inputs. From 72bacb0cd0882bce6bd7e9e2e4e9c112d70213e7 Mon Sep 17 00:00:00 2001 From: Aniket <148300120+Aniketsy@users.noreply.github.com> Date: Mon, 19 Jan 2026 18:29:26 +0530 Subject: [PATCH 5/7] gh-142461: Move misplaced NEWS entries to an appropriate section (GH-143392) --- Misc/NEWS.d/3.12.0a1.rst | 24 ++++++++++++------------ Misc/NEWS.d/3.12.0a2.rst | 4 ++-- Misc/NEWS.d/3.12.0a3.rst | 4 ++-- Misc/NEWS.d/3.12.0a4.rst | 4 ++-- Misc/NEWS.d/3.12.0a5.rst | 2 +- Misc/NEWS.d/3.12.0a7.rst | 6 +++--- Misc/NEWS.d/3.12.0b1.rst | 8 ++++---- Misc/NEWS.d/3.13.0a5.rst | 4 ++-- Misc/NEWS.d/3.13.0a6.rst | 4 ++-- Misc/NEWS.d/3.13.0b1.rst | 2 +- 10 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 0da7cdde1b2535..c977022d87fc95 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -160,7 +160,7 @@ to calculate those doing pointer arithmetic. .. date: 2022-10-06-15-45-57 .. gh-issue: 96078 .. nonce: fS-6mU -.. section: Core and Builtins +.. section: Library :func:`os.sched_yield` now release the GIL while calling sched_yield(2). Patch by Donghee Na. @@ -170,7 +170,7 @@ Patch by Donghee Na. .. date: 2022-10-06-14-14-28 .. gh-issue: 97955 .. nonce: Nq5VXD -.. section: Core and Builtins +.. section: Library Migrate :mod:`zoneinfo` to Argument Clinic. @@ -361,7 +361,7 @@ branching conditions. .. date: 2022-09-19-03-35-01 .. gh-issue: 96821 .. nonce: izK6JA -.. section: Core and Builtins +.. section: Library Fix undefined behaviour in ``audioop.c``. @@ -481,7 +481,7 @@ Fix case of undefined behavior in ceval.c .. date: 2022-09-08-20-58-10 .. gh-issue: 64373 .. nonce: AfCi36 -.. section: Core and Builtins +.. section: Library Convert :mod:`!_functools` to argument clinic. @@ -490,7 +490,7 @@ Convert :mod:`!_functools` to argument clinic. .. date: 2022-09-07-13-38-37 .. gh-issue: 96641 .. nonce: wky0Fc -.. section: Core and Builtins +.. section: Library Do not expose ``KeyWrapper`` in :mod:`!_functools`. @@ -990,7 +990,7 @@ bytecode compiler. .. date: 2022-07-20-09-04-55 .. gh-issue: 95023 .. nonce: bs-xd7 -.. section: Core and Builtins +.. section: Library Implement :func:`os.setns` and :func:`os.unshare` for Linux. Patch by Noam Cohen. @@ -1021,7 +1021,7 @@ Previously it could cause SystemError or other undesired behavior. .. date: 2022-07-19-04-34-56 .. gh-issue: 94996 .. nonce: dV564A -.. section: Core and Builtins +.. section: Library :func:`ast.parse` will no longer parse function definitions with positional-only params when passed ``feature_version`` less than ``(3, 8)``. @@ -1041,7 +1041,7 @@ Allow jumping within, out of, and across exception handlers in the debugger. .. date: 2022-07-18-05-10-29 .. gh-issue: 94949 .. nonce: OsZ7_s -.. section: Core and Builtins +.. section: Library :func:`ast.parse` will no longer parse parenthesized context managers when passed ``feature_version`` less than ``(3, 9)``. Patch by Shantanu Jain. @@ -1051,7 +1051,7 @@ passed ``feature_version`` less than ``(3, 9)``. Patch by Shantanu Jain. .. date: 2022-07-18-04-48-34 .. gh-issue: 94947 .. nonce: df9gUw -.. section: Core and Builtins +.. section: Library :func:`ast.parse` will no longer parse assignment expressions when passed ``feature_version`` less than ``(3, 8)``. Patch by Shantanu Jain. @@ -1394,7 +1394,7 @@ calls. Previously, the end column could precede the column offset. .. date: 2022-06-09-19-19-02 .. gh-issue: 93461 .. nonce: 5DqP1e -.. section: Core and Builtins +.. section: Library :func:`importlib.invalidate_caches` now drops entries from :data:`sys.path_importer_cache` with a relative path as name. This solves a @@ -1729,7 +1729,7 @@ tracing functions implemented in C. .. date: 2022-05-11-09-16-54 .. gh-issue: 91102 .. nonce: lenv9h -.. section: Core and Builtins +.. section: Library :meth:`!_warnings.warn_explicit` is ported to Argument Clinic. @@ -1759,7 +1759,7 @@ no longer does anything. .. date: 2022-05-03-20-12-18 .. gh-issue: 92261 .. nonce: aigLnb -.. section: Core and Builtins +.. section: Library Fix hang when trying to iterate over a ``typing.Union``. diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index 20e27c0d92f05f..9c73ae95d10a4c 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -333,7 +333,7 @@ aware of this shim frame and the changes to the semantics of .. date: 2022-10-19-01-01-08 .. gh-issue: 98415 .. nonce: ZS2eWh -.. section: Core and Builtins +.. section: Build Fix detection of MAC addresses for :mod:`uuid` on certain OSs. Patch by Chaim Sanders @@ -405,7 +405,7 @@ Expose :const:`~socket.ETH_P_ALL` and some of the :ref:`ETHERTYPE_* constants .. date: 2022-06-10-16-37-44 .. gh-issue: 93696 .. nonce: 65BI2R -.. section: Core and Builtins +.. section: Library Allow :mod:`pdb` to locate source for frozen modules in the standard library. diff --git a/Misc/NEWS.d/3.12.0a3.rst b/Misc/NEWS.d/3.12.0a3.rst index 04a2bf9fb916b7..d2c717afcb6e8d 100644 --- a/Misc/NEWS.d/3.12.0a3.rst +++ b/Misc/NEWS.d/3.12.0a3.rst @@ -100,7 +100,7 @@ Fix bug where an :exc:`ExceptionGroup` subclass can wrap a .. date: 2022-11-16-21-35-30 .. gh-issue: 99547 .. nonce: p_c_bp -.. section: Core and Builtins +.. section: Library Add a function to os.path to check if a path is a junction: isjunction. Add similar functionality to pathlib.Path as is_junction. @@ -110,7 +110,7 @@ similar functionality to pathlib.Path as is_junction. .. date: 2022-11-12-01-39-57 .. gh-issue: 99370 .. nonce: _cu32j -.. section: Core and Builtins +.. section: Library Fix zip path for venv created from a non-installed python on POSIX platforms. diff --git a/Misc/NEWS.d/3.12.0a4.rst b/Misc/NEWS.d/3.12.0a4.rst index 57fb2052764b6f..1fdebf54da9cdc 100644 --- a/Misc/NEWS.d/3.12.0a4.rst +++ b/Misc/NEWS.d/3.12.0a4.rst @@ -125,7 +125,7 @@ Improve the accuracy of ``sum()`` with compensated summation. .. date: 2022-12-20-16-14-19 .. gh-issue: 100374 .. nonce: YRrVHT -.. section: Core and Builtins +.. section: Library Fix incorrect result and delay in :func:`socket.getfqdn`. Patch by Dominic Socular. @@ -315,7 +315,7 @@ Improve performance of ``list.pop`` for small lists. .. date: 2022-06-17-08-00-34 .. gh-issue: 89051 .. nonce: yP4Na0 -.. section: Core and Builtins +.. section: Library Add :const:`ssl.OP_LEGACY_SERVER_CONNECT` diff --git a/Misc/NEWS.d/3.12.0a5.rst b/Misc/NEWS.d/3.12.0a5.rst index b73bbfbfdc4819..74801bf1add5d8 100644 --- a/Misc/NEWS.d/3.12.0a5.rst +++ b/Misc/NEWS.d/3.12.0a5.rst @@ -181,7 +181,7 @@ regen-all``. .. bpo: 32780 .. date: 2018-02-05-21-54-46 .. nonce: Dtiz8z -.. section: Core and Builtins +.. section: Library Inter-field padding is now inserted into the PEP3118 format strings obtained from :class:`ctypes.Structure` objects, reflecting their true representation diff --git a/Misc/NEWS.d/3.12.0a7.rst b/Misc/NEWS.d/3.12.0a7.rst index f48b9ce0550440..e0c079c5def971 100644 --- a/Misc/NEWS.d/3.12.0a7.rst +++ b/Misc/NEWS.d/3.12.0a7.rst @@ -102,7 +102,7 @@ Shrink the number of inline :opcode:`CACHE` entries used by .. date: 2023-03-08-08-37-36 .. gh-issue: 102491 .. nonce: SFvvsC -.. section: Core and Builtins +.. section: Library Improve import time of ``platform`` by removing IronPython version parsing. The IronPython version parsing was not functional (see @@ -187,7 +187,7 @@ Improve build support for the Xbox. Patch by Max Bachmann. .. date: 2023-02-21-23-42-39 .. gh-issue: 102027 .. nonce: fQARG0 -.. section: Core and Builtins +.. section: Build Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max Bachmann. @@ -207,7 +207,7 @@ Deprecate ``co_lnotab`` in code objects, schedule it for removal in Python .. bpo: 1635741 .. date: 2020-07-04-09-04-41 .. nonce: ZsP31Y -.. section: Core and Builtins +.. section: Library Adapt :mod:`!_pickle` to :pep:`687`. Patch by Mohamed Koubaa and Erlend Aasland. diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index b867a4f623006f..e897bfebd24f2c 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -44,7 +44,7 @@ response to :cve:`2023-24329`. Patch by Illia Volochii. .. date: 2023-05-20-23-08-48 .. gh-issue: 102856 .. nonce: Knv9WT -.. section: Core and Builtins +.. section: Library Implement PEP 701 changes in the :mod:`tokenize` module. Patch by Marta Gómez Macías and Pablo Galindo Salgado @@ -312,7 +312,7 @@ Patch by Eric Traut, Larry Hastings, and Jelle Zijlstra. .. date: 2023-04-24-21-47-38 .. gh-issue: 103801 .. nonce: WaBanq -.. section: Core and Builtins +.. section: Library Adds three minor linting fixes to the wasm module caught that were caught by ruff. @@ -322,7 +322,7 @@ ruff. .. date: 2023-04-24-14-38-16 .. gh-issue: 103793 .. nonce: kqoH6Q -.. section: Core and Builtins +.. section: Library Optimized asyncio Task creation by deferring expensive string formatting (task name generation) from Task creation to the first time ``get_name`` is @@ -573,7 +573,7 @@ raising an :exc:`IndexError`. .. bpo: 31821 .. date: 2019-12-01-12-58-31 .. nonce: 1FNmwk -.. section: Core and Builtins +.. section: Library Fix :func:`!pause_reading` to work when called from :func:`!connection_made` in :mod:`asyncio`. diff --git a/Misc/NEWS.d/3.13.0a5.rst b/Misc/NEWS.d/3.13.0a5.rst index 19ba16bc8c83d5..6f8c82e5af3d75 100644 --- a/Misc/NEWS.d/3.13.0a5.rst +++ b/Misc/NEWS.d/3.13.0a5.rst @@ -136,7 +136,7 @@ threads to be interrupted. .. date: 2024-02-08-16-01-18 .. gh-issue: 115154 .. nonce: ji96FV -.. section: Core and Builtins +.. section: Library Fix a bug that was causing the :func:`tokenize.untokenize` function to handle unicode named literals incorrectly. Patch by Pablo Galindo @@ -156,7 +156,7 @@ Add ability to force alignment of :mod:`ctypes.Structure` by way of the new .. date: 2023-07-16-15-02-47 .. gh-issue: 104090 .. nonce: oMjNa9 -.. section: Core and Builtins +.. section: Library The multiprocessing resource tracker now exits with non-zero status code if a resource leak was detected. It still exits with status code 0 otherwise. diff --git a/Misc/NEWS.d/3.13.0a6.rst b/Misc/NEWS.d/3.13.0a6.rst index ad6622d23bf36b..b97973fad020af 100644 --- a/Misc/NEWS.d/3.13.0a6.rst +++ b/Misc/NEWS.d/3.13.0a6.rst @@ -224,7 +224,7 @@ When the collecting space becomes empty, the two spaces are swapped. .. date: 2023-10-14-00-05-17 .. gh-issue: 109870 .. nonce: oKpJ3P -.. section: Core and Builtins +.. section: Library Dataclasses now calls :func:`exec` once per dataclass, instead of once per method being added. This can speed up dataclass creation by up to 20%. @@ -234,7 +234,7 @@ method being added. This can speed up dataclass creation by up to 20%. .. date: 2022-10-05-09-33-48 .. gh-issue: 97901 .. nonce: BOLluU -.. section: Core and Builtins +.. section: Library Mime type ``text/rtf`` is now supported by :mod:`mimetypes`. diff --git a/Misc/NEWS.d/3.13.0b1.rst b/Misc/NEWS.d/3.13.0b1.rst index 97731276679ba6..d0eef2d8c11641 100644 --- a/Misc/NEWS.d/3.13.0b1.rst +++ b/Misc/NEWS.d/3.13.0b1.rst @@ -60,7 +60,7 @@ for speed. .. date: 2024-05-03-18-01-26 .. gh-issue: 95382 .. nonce: 73FSEv -.. section: Core and Builtins +.. section: Library Improve performance of :func:`json.dumps` and :func:`json.dump` when using the argument *indent*. Depending on the data the encoding using From 375e372c6661d818b85d1405c5ba681a06988ebd Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Mon, 19 Jan 2026 22:09:30 +0800 Subject: [PATCH 6/7] gh-143689: Fix BufferedReader.read1 leaving object in reentrant state on error (#143690) BufferedReader.read1() could leave the buffered object in a reentrant (locked) state when an exception was raised while allocating the output buffer. This change ensures the internal buffered lock is always released on error, keeping the object in a consistent state after failures. Signed-off-by: Yongtao Huang Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Cody Maloney Co-authored-by: sobolevn --- Lib/test/test_io/test_bufferedio.py | 21 ++++++++++++++++++- ...-01-11-14-14-19.gh-issue-143689.fzHJ2W.rst | 1 + Modules/_io/bufferedio.c | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-11-14-14-19.gh-issue-143689.fzHJ2W.rst diff --git a/Lib/test/test_io/test_bufferedio.py b/Lib/test/test_io/test_bufferedio.py index 3278665bdc9dd3..e83dd0d4e28d00 100644 --- a/Lib/test/test_io/test_bufferedio.py +++ b/Lib/test/test_io/test_bufferedio.py @@ -10,7 +10,7 @@ from collections import deque, UserList from itertools import cycle, count from test import support -from test.support import os_helper, threading_helper +from test.support import check_sanitizer, os_helper, threading_helper from .utils import byteslike, CTestCase, PyTestCase @@ -623,6 +623,25 @@ def test_bad_readinto_type(self): bufio.readline() self.assertIsInstance(cm.exception.__cause__, TypeError) + @unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform') + @unittest.skipIf(check_sanitizer(thread=True), + 'ThreadSanitizer aborts on huge allocations (exit code 66).') + def test_read1_error_does_not_cause_reentrant_failure(self): + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + with self.open(os_helper.TESTFN, "wb") as f: + f.write(b"hello") + + with self.open(os_helper.TESTFN, "rb", buffering=0) as raw: + bufio = self.tp(raw, buffer_size=8) + # To request a size that is far too huge to ever be satisfied, + # so that the internal buffer allocation reliably fails with MemoryError. + huge = sys.maxsize // 2 + 1 + with self.assertRaises(MemoryError): + bufio.read1(huge) + + # Used to crash before gh-143689: + self.assertEqual(bufio.read1(1), b"h") + class PyBufferedReaderTest(BufferedReaderTest, PyTestCase): tp = pyio.BufferedReader diff --git a/Misc/NEWS.d/next/Library/2026-01-11-14-14-19.gh-issue-143689.fzHJ2W.rst b/Misc/NEWS.d/next/Library/2026-01-11-14-14-19.gh-issue-143689.fzHJ2W.rst new file mode 100644 index 00000000000000..a423b1b70ad077 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-11-14-14-19.gh-issue-143689.fzHJ2W.rst @@ -0,0 +1 @@ +Fix :meth:`io.BufferedReader.read1` state cleanup on buffer allocation failure. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 4602f2b42a6017..6d779abd89ca84 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1073,6 +1073,7 @@ _io__Buffered_read1_impl(buffered *self, Py_ssize_t n) PyBytesWriter *writer = PyBytesWriter_Create(n); if (writer == NULL) { + LEAVE_BUFFERED(self) return NULL; } From 3c9c3d33cbdef257526871cbc12e93635026f5d6 Mon Sep 17 00:00:00 2001 From: Adorilson Bezerra Date: Mon, 19 Jan 2026 14:15:55 +0000 Subject: [PATCH 7/7] gh-106318: Add examples for str.rpartition() method (#143891) --- Doc/library/stdtypes.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 22bc1536c1a37b..ce0d7cbb2e4276 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2562,6 +2562,19 @@ expression support in the :mod:`re` module). after the separator. If the separator is not found, return a 3-tuple containing two empty strings, followed by the string itself. + For example: + + .. doctest:: + + >>> 'Monty Python'.rpartition(' ') + ('Monty', ' ', 'Python') + >>> "Monty Python's Flying Circus".rpartition(' ') + ("Monty Python's Flying", ' ', 'Circus') + >>> 'Monty Python'.rpartition('-') + ('', '', 'Monty Python') + + See also :meth:`partition`. + .. method:: str.rsplit(sep=None, maxsplit=-1)