From 05eab964350dc1b4c04352c87fff4904d324b7ca Mon Sep 17 00:00:00 2001 From: Bodhi Silberling Date: Mon, 19 Jan 2026 22:50:34 -0800 Subject: [PATCH 1/5] Fix typo: 'exept' -> 'except' in Lib/dbm/dumb.py (GH-144060) --- Lib/dbm/dumb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/dbm/dumb.py b/Lib/dbm/dumb.py index 1bc239a84fff83..c1c38da5101a57 100644 --- a/Lib/dbm/dumb.py +++ b/Lib/dbm/dumb.py @@ -9,7 +9,7 @@ - seems to contain a bug when updating... - reclaim free space (currently, space once occupied by deleted or expanded -items is not reused exept if .reorganize() is called) +items is not reused except if .reorganize() is called) - support concurrent access (currently, if two processes take turns making updates, they can mess up the index) From 71cbffde61449a224dffcae937f5f6be4f86ad09 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 20 Jan 2026 09:16:36 +0200 Subject: [PATCH 2/5] gh-143754: Add Tkinter methods pack_content(), place_content() and grid_content() (GH-143845) They use Tk commands with new name like "pack content instead of old "pack slaves". --- Doc/whatsnew/3.15.rst | 6 ++ .../test_tkinter/test_geometry_managers.py | 66 ++++++++++++++----- Lib/tkinter/__init__.py | 46 ++++++++++++- ...-01-14-20-35-40.gh-issue-143754.m2NQXA.rst | 3 + 4 files changed, 102 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-14-20-35-40.gh-issue-143754.m2NQXA.rst diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index b7a27d5db63875..1dd66065b0f93d 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -792,6 +792,12 @@ tkinter using Tcl's ``-all`` and ``-overlap`` options. (Contributed by Rihaan Meher in :gh:`130848`) +* Added new methods :meth:`!pack_content`, :meth:`!place_content` and + :meth:`!grid_content` which use Tk commands with new names (introduced + in Tk 8.6) instead of :meth:`!*_slaves` methods which use Tk commands + with outdated names. + (Contributed by Serhiy Storchaka in :gh:`143754`) + types ------ diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index b2ce143ff0948f..3dcdadd1aacf10 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -40,11 +40,11 @@ def test_pack_configure_after(self): b.pack_configure(side='top') c.pack_configure(side='top') d.pack_configure(side='top') - self.assertEqual(pack.pack_slaves(), [a, b, c, d]) + self.assertEqual(pack.pack_content(), [a, b, c, d]) a.pack_configure(after=b) - self.assertEqual(pack.pack_slaves(), [b, a, c, d]) + self.assertEqual(pack.pack_content(), [b, a, c, d]) a.pack_configure(after=a) - self.assertEqual(pack.pack_slaves(), [b, a, c, d]) + self.assertEqual(pack.pack_content(), [b, a, c, d]) def test_pack_configure_anchor(self): pack, a, b, c, d = self.create2() @@ -73,11 +73,11 @@ def test_pack_configure_before(self): b.pack_configure(side='top') c.pack_configure(side='top') d.pack_configure(side='top') - self.assertEqual(pack.pack_slaves(), [a, b, c, d]) + self.assertEqual(pack.pack_content(), [a, b, c, d]) a.pack_configure(before=d) - self.assertEqual(pack.pack_slaves(), [b, c, a, d]) + self.assertEqual(pack.pack_content(), [b, c, a, d]) a.pack_configure(before=a) - self.assertEqual(pack.pack_slaves(), [b, c, a, d]) + self.assertEqual(pack.pack_content(), [b, c, a, d]) def test_pack_configure_expand(self): pack, a, b, c, d = self.create2() @@ -110,10 +110,10 @@ def test_pack_configure_in(self): c.pack_configure(side='top') d.pack_configure(side='top') a.pack_configure(in_=pack) - self.assertEqual(pack.pack_slaves(), [b, c, d, a]) + self.assertEqual(pack.pack_content(), [b, c, d, a]) a.pack_configure(in_=c) - self.assertEqual(pack.pack_slaves(), [b, c, d]) - self.assertEqual(c.pack_slaves(), [a]) + self.assertEqual(pack.pack_content(), [b, c, d]) + self.assertEqual(c.pack_content(), [a]) with self.assertRaisesRegex( TclError, """can't pack "?%s"? inside itself""" % (a,)): a.pack_configure(in_=a) @@ -223,11 +223,11 @@ def test_pack_forget(self): a.pack_configure() b.pack_configure() c.pack_configure() - self.assertEqual(pack.pack_slaves(), [a, b, c]) + self.assertEqual(pack.pack_content(), [a, b, c]) b.pack_forget() - self.assertEqual(pack.pack_slaves(), [a, c]) + self.assertEqual(pack.pack_content(), [a, c]) b.pack_forget() - self.assertEqual(pack.pack_slaves(), [a, c]) + self.assertEqual(pack.pack_content(), [a, c]) d.pack_forget() def test_pack_info(self): @@ -273,6 +273,14 @@ def test_pack_propagate(self): self.assertEqual(pack.winfo_reqwidth(), 20) self.assertEqual(pack.winfo_reqheight(), 40) + def test_pack_content(self): + pack, a, b, c, d = self.create2() + self.assertEqual(pack.pack_content(), []) + a.pack_configure() + self.assertEqual(pack.pack_content(), [a]) + b.pack_configure() + self.assertEqual(pack.pack_content(), [a, b]) + def test_pack_slaves(self): pack, a, b, c, d = self.create2() self.assertEqual(pack.pack_slaves(), []) @@ -477,6 +485,15 @@ def test_place_info(self): with self.assertRaises(TypeError): f2.place_info(0) + def test_place_content(self): + foo = tkinter.Frame(self.root) + bar = tkinter.Frame(self.root) + self.assertEqual(foo.place_content(), []) + bar.place_configure(in_=foo) + self.assertEqual(foo.place_content(), [bar]) + with self.assertRaises(TypeError): + foo.place_content(0) + def test_place_slaves(self): foo = tkinter.Frame(self.root) bar = tkinter.Frame(self.root) @@ -729,10 +746,10 @@ def test_grid_forget(self): c = tkinter.Button(self.root) b.grid_configure(row=2, column=2, rowspan=2, columnspan=2, padx=3, pady=4, sticky='ns') - self.assertEqual(self.root.grid_slaves(), [b]) + self.assertEqual(self.root.grid_content(), [b]) b.grid_forget() c.grid_forget() - self.assertEqual(self.root.grid_slaves(), []) + self.assertEqual(self.root.grid_content(), []) self.assertEqual(b.grid_info(), {}) b.grid_configure(row=0, column=0) info = b.grid_info() @@ -749,10 +766,10 @@ def test_grid_remove(self): c = tkinter.Button(self.root) b.grid_configure(row=2, column=2, rowspan=2, columnspan=2, padx=3, pady=4, sticky='ns') - self.assertEqual(self.root.grid_slaves(), [b]) + self.assertEqual(self.root.grid_content(), [b]) b.grid_remove() c.grid_remove() - self.assertEqual(self.root.grid_slaves(), []) + self.assertEqual(self.root.grid_content(), []) self.assertEqual(b.grid_info(), {}) b.grid_configure(row=0, column=0) info = b.grid_info() @@ -887,6 +904,23 @@ def test_grid_size(self): f.grid_configure(row=4, column=5) self.assertEqual(self.root.grid_size(), (6, 5)) + def test_grid_content(self): + self.assertEqual(self.root.grid_content(), []) + a = tkinter.Label(self.root) + a.grid_configure(row=0, column=1) + b = tkinter.Label(self.root) + b.grid_configure(row=1, column=0) + c = tkinter.Label(self.root) + c.grid_configure(row=1, column=1) + d = tkinter.Label(self.root) + d.grid_configure(row=1, column=1) + self.assertEqual(self.root.grid_content(), [d, c, b, a]) + self.assertEqual(self.root.grid_content(row=0), [a]) + self.assertEqual(self.root.grid_content(row=1), [d, c, b]) + self.assertEqual(self.root.grid_content(column=0), [b]) + self.assertEqual(self.root.grid_content(column=1), [d, c, a]) + self.assertEqual(self.root.grid_content(row=1, column=1), [d, c]) + def test_grid_slaves(self): self.assertEqual(self.root.grid_slaves(), []) a = tkinter.Label(self.root) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index be150e2b892e4b..d695e3ec9cb1b4 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1885,9 +1885,21 @@ def pack_propagate(self, flag=_noarg_): propagate = pack_propagate - def pack_slaves(self): + def pack_content(self): """Returns a list of all of the content widgets in the packing order for this container.""" + try: + res = self.tk.call('pack', 'content', self._w) + except TclError: + if self.info_patchlevel() >= (8, 6): + raise + res = self.tk.call('pack', 'slaves', self._w) + return [self._nametowidget(x) for x in self.tk.splitlist(res)] + + content = pack_content + + def pack_slaves(self): + """Synonym for pack_content().""" return [self._nametowidget(x) for x in self.tk.splitlist( self.tk.call('pack', 'slaves', self._w))] @@ -1895,9 +1907,19 @@ def pack_slaves(self): slaves = pack_slaves # Place method that applies to the container widget - def place_slaves(self): + def place_content(self): """Returns a list of all the content widgets for which this widget is the container.""" + try: + res = self.tk.call('place', 'content', self._w) + except TclError: + if self.info_patchlevel() >= (8, 6): + raise + res = self.tk.call('place', 'slaves', self._w) + return [self._nametowidget(x) for x in self.tk.splitlist(res)] + + def place_slaves(self): + """Synonym for place_content().""" return [self._nametowidget(x) for x in self.tk.splitlist( self.tk.call( @@ -2018,7 +2040,7 @@ def grid_size(self): size = grid_size - def grid_slaves(self, row=None, column=None): + def grid_content(self, row=None, column=None): """Returns a list of the content widgets. If no arguments are supplied, a list of all of the content in this @@ -2027,6 +2049,21 @@ def grid_slaves(self, row=None, column=None): column is returned. """ args = () + if row is not None: + args = args + ('-row', row) + if column is not None: + args = args + ('-column', column) + try: + res = self.tk.call('grid', 'content', self._w, *args) + except TclError: + if self.info_patchlevel() >= (8, 6): + raise + res = self.tk.call('grid', 'slaves', self._w, *args) + return [self._nametowidget(x) for x in self.tk.splitlist(res)] + + def grid_slaves(self, row=None, column=None): + """Synonym for grid_content().""" + args = () if row is not None: args = args + ('-row', row) if column is not None: @@ -2641,6 +2678,7 @@ def pack_info(self): info = pack_info propagate = pack_propagate = Misc.pack_propagate + content = pack_content = Misc.pack_content slaves = pack_slaves = Misc.pack_slaves @@ -2698,6 +2736,7 @@ def place_info(self): return d info = place_info + content = place_content = Misc.place_content slaves = place_slaves = Misc.place_slaves @@ -2753,6 +2792,7 @@ def grid_info(self): propagate = grid_propagate = Misc.grid_propagate rowconfigure = grid_rowconfigure = Misc.grid_rowconfigure size = grid_size = Misc.grid_size + content = grid_content = Misc.grid_content slaves = grid_slaves = Misc.grid_slaves diff --git a/Misc/NEWS.d/next/Library/2026-01-14-20-35-40.gh-issue-143754.m2NQXA.rst b/Misc/NEWS.d/next/Library/2026-01-14-20-35-40.gh-issue-143754.m2NQXA.rst new file mode 100644 index 00000000000000..edfdd109400d08 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-14-20-35-40.gh-issue-143754.m2NQXA.rst @@ -0,0 +1,3 @@ +Add new :mod:`tkinter` widget methods :meth:`!pack_content`, +:meth:`!place_content` and :meth:`!grid_content` which are alternative +spelling of old :meth:`!*_slaves` methods. From fa3abf5a51d42b2d62e1bc89e9465b398a567e94 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Tue, 20 Jan 2026 04:07:29 -0500 Subject: [PATCH 3/5] gh-143774 - Improve IDLE Format Paragraph doc (#143775) Add a reminder to not rewrap code line to the Menu => Format => Reformat Paragraph entry. In Editing and Nagivagion, add a new 'Format block' subsection that defines 'paragraph' to better match what is dependably handled as more or less expected. In particular, specify equal indents and that the resulting indent equals original indent. Also mention that selections are expanded to complete lines and how to modify max length. (Also fix a couple case errors in cross references.) --- Doc/library/idle.rst | 24 ++++++++++++++---- Lib/idlelib/help.html | 25 +++++++++++++------ ...-01-13-01-21-20.gh-issue-143774.rqGwX1.rst | 1 + 3 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2026-01-13-01-21-20.gh-issue-143774.rqGwX1.rst diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst index a16f46ef812400..89be225b6baae4 100644 --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -158,7 +158,7 @@ Go to Line Show Completions Open a scrollable list allowing selection of existing names. See - :ref:`Completions ` in the Editing and navigation section below. + :ref:`Completions ` in the Editing and Navigation section below. Expand Word Expand a prefix you have typed to match a full word in the same window; @@ -167,7 +167,7 @@ Expand Word Show Call Tip After an unclosed parenthesis for a function, open a small window with function parameter hints. See :ref:`Calltips ` in the - Editing and navigation section below. + Editing and Navigation section below. Show Surrounding Parens Highlight the surrounding parenthesis. @@ -178,9 +178,9 @@ Format menu (Editor window only) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Format Paragraph - Reformat the current blank-line-delimited paragraph in comment block or - multiline string or selected line in a string. All lines in the - paragraph will be formatted to less than N columns, where N defaults to 72. + Rewrap the text block containing the text insert cursor. + Avoid code lines. See :ref:`Format block` in the + Editing and Navigation section below. Indent Region Shift selected lines right by the indent width (default 4 spaces). @@ -566,6 +566,20 @@ In an editor, import statements have no effect until one runs the file. One might want to run a file after writing import statements, after adding function definitions, or after opening an existing file. +.. _format-block: + +Format block +^^^^^^^^^^^^ + +Reformat Paragraph rewraps a block ('paragraph') of contiguous equally +indented non-blank comments, a similar block of text within a multiline +string, or a selected subset of either. +If needed, add a blank line to separate string from code. +Partial lines in a selection expand to complete lines. +The resulting lines have the same indent as before +but have maximum total length of N columns (characters). +Change the default N of 72 on the Window tab of IDLE Settings. + .. _code-context: Code Context diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html index 9eb18d8f39b7c6..eda16ac5bed118 100644 --- a/Lib/idlelib/help.html +++ b/Lib/idlelib/help.html @@ -111,14 +111,14 @@

Edit menu (Shell and Editor)Completions in the Editing and navigation section below.

+Completions in the Editing and Navigation section below.

Expand Word

Expand a prefix you have typed to match a full word in the same window; repeat to get a different expansion.

Show Call Tip

After an unclosed parenthesis for a function, open a small window with function parameter hints. See Calltips in the -Editing and navigation section below.

+Editing and Navigation section below.

Show Surrounding Parens

Highlight the surrounding parenthesis.

@@ -127,9 +127,9 @@

Edit menu (Shell and Editor)

Format menu (Editor window only)

-
Format Paragraph

Reformat the current blank-line-delimited paragraph in comment block or -multiline string or selected line in a string. All lines in the -paragraph will be formatted to less than N columns, where N defaults to 72.

+
Format Paragraph

Rewrap the text block containing the text insert cursor. +Avoid code lines. See Format block in the +Editing and Navigation section below.

Indent Region

Shift selected lines right by the indent width (default 4 spaces).

@@ -443,8 +443,19 @@

Search and Replace +

Format block

+

Reformat Paragraph rewraps a block (‘paragraph’) of contiguous equally +indented non-blank comments, a similar block of text within a multiline +string, or a selected subset of either. +If needed, add a blank line to separate string from code. +Partial lines in a selection expand to complete lines. +The resulting lines have the same indent as before +but have maximum total length of N columns (characters). +Change the default N of 72 on the Window tab of IDLE Settings.

+
-

Code Context

+

Code Context

Within an editor window containing Python code, code context can be toggled in order to show or hide a pane at the top of the window. When shown, this pane freezes the opening lines for block code, such as those beginning with @@ -791,7 +802,7 @@

Running without a subprocess

Help and Preferences

-

Help sources

+

Help sources

Help menu entry “IDLE Help” displays a formatted html version of the IDLE chapter of the Library Reference. The result, in a read-only tkinter text window, is close to what one sees in a web browser. diff --git a/Misc/NEWS.d/next/IDLE/2026-01-13-01-21-20.gh-issue-143774.rqGwX1.rst b/Misc/NEWS.d/next/IDLE/2026-01-13-01-21-20.gh-issue-143774.rqGwX1.rst new file mode 100644 index 00000000000000..dd15d1672b1b54 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-01-13-01-21-20.gh-issue-143774.rqGwX1.rst @@ -0,0 +1 @@ +Better explain the operation of Format / Format Paragraph. From fa44efa0ef1972ac1e2f66996303154be11f605e Mon Sep 17 00:00:00 2001 From: AZero13 Date: Tue, 20 Jan 2026 04:50:51 -0500 Subject: [PATCH 4/5] gh-144023: Prevent follow_symlinks from being allowed with an fd of 0 (GH-144022) The check was (fd > 0), should be (fd >= 0). --- Lib/test/test_os/test_posix.py | 12 ++++++++++++ .../2026-01-19-00-57-40.gh-issue-144023.29XUcp.rst | 2 ++ Modules/posixmodule.c | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-19-00-57-40.gh-issue-144023.29XUcp.rst diff --git a/Lib/test/test_os/test_posix.py b/Lib/test/test_os/test_posix.py index 37da293a441e46..995c48bdbbffd6 100644 --- a/Lib/test/test_os/test_posix.py +++ b/Lib/test/test_os/test_posix.py @@ -668,6 +668,18 @@ def test_fstat(self): finally: fp.close() + @unittest.skipUnless(hasattr(posix, 'stat'), + 'test needs posix.stat()') + @unittest.skipUnless(os.stat in os.supports_follow_symlinks, + 'test needs follow_symlinks support in os.stat()') + def test_stat_fd_zero_follow_symlinks(self): + with self.assertRaisesRegex(ValueError, + 'cannot use fd and follow_symlinks together'): + posix.stat(0, follow_symlinks=False) + with self.assertRaisesRegex(ValueError, + 'cannot use fd and follow_symlinks together'): + posix.stat(1, follow_symlinks=False) + def check_statlike_path(self, func): self.assertTrue(func(os_helper.TESTFN)) self.assertTrue(func(os.fsencode(os_helper.TESTFN))) diff --git a/Misc/NEWS.d/next/Library/2026-01-19-00-57-40.gh-issue-144023.29XUcp.rst b/Misc/NEWS.d/next/Library/2026-01-19-00-57-40.gh-issue-144023.29XUcp.rst new file mode 100644 index 00000000000000..0d06506e1ec106 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-19-00-57-40.gh-issue-144023.29XUcp.rst @@ -0,0 +1,2 @@ +Fixed validation of file descriptor 0 in posix functions when used with +follow_symlinks parameter. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 49214d57a2e362..ef90ac5de09c65 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1637,7 +1637,7 @@ static int fd_and_follow_symlinks_invalid(const char *function_name, int fd, int follow_symlinks) { - if ((fd > 0) && (!follow_symlinks)) { + if ((fd >= 0) && (!follow_symlinks)) { PyErr_Format(PyExc_ValueError, "%s: cannot use fd and follow_symlinks together", function_name); From 76b484b9d16d6a3b1749dc89d99773b5b4a5c4a5 Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Tue, 20 Jan 2026 18:20:06 +0800 Subject: [PATCH 5/5] gh-143999: Fix: handle suspended state on types.coroutine wrappers (GH-144000) --- Lib/test/test_inspect/test_inspect.py | 24 +++++++++++++++++++ Lib/types.py | 4 ++++ ...-01-18-14-35-37.gh-issue-143999.MneN4O.rst | 1 + 3 files changed, 29 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index b25414bea659b7..1999aa770ecc56 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -2804,6 +2804,30 @@ def running_check_generator(): # Running after the first yield next(self.generator) + def test_types_coroutine_wrapper_state(self): + def gen(): + yield 1 + yield 2 + + @types.coroutine + def wrapped_generator_coro(): + # return a generator iterator so types.coroutine + # wraps it into types._GeneratorWrapper. + return gen() + + g = wrapped_generator_coro() + self.addCleanup(g.close) + self.assertIs(type(g), types._GeneratorWrapper) + + # _GeneratorWrapper must provide gi_suspended/cr_suspended + # so inspect.get*state() doesn't raise AttributeError. + self.assertEqual(inspect.getgeneratorstate(g), inspect.GEN_CREATED) + self.assertEqual(inspect.getcoroutinestate(g), inspect.CORO_CREATED) + + next(g) + self.assertEqual(inspect.getgeneratorstate(g), inspect.GEN_SUSPENDED) + self.assertEqual(inspect.getcoroutinestate(g), inspect.CORO_SUSPENDED) + def test_easy_debugging(self): # repr() and str() of a generator state should contain the state name names = 'GEN_CREATED GEN_RUNNING GEN_SUSPENDED GEN_CLOSED'.split() diff --git a/Lib/types.py b/Lib/types.py index f96c75b46daba7..73a69c40c8d4b8 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -276,10 +276,14 @@ def gi_running(self): @property def gi_yieldfrom(self): return self.__wrapped.gi_yieldfrom + @property + def gi_suspended(self): + return self.__wrapped.gi_suspended cr_code = gi_code cr_frame = gi_frame cr_running = gi_running cr_await = gi_yieldfrom + cr_suspended = gi_suspended def __next__(self): return next(self.__wrapped) def __iter__(self): diff --git a/Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst b/Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst new file mode 100644 index 00000000000000..dc87411aacc821 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst @@ -0,0 +1 @@ +Fix an issue where :func:`inspect.getgeneratorstate` and :func:`inspect.getcoroutinestate` could fail for generators wrapped by :func:`types.coroutine` in the suspended state.