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/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/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) 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/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/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/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/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/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. 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. 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. 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);