Skip to content

Commit 8bc8ee9

Browse files
generatedunixname1734921407115435meta-codesync[bot]
authored andcommitted
Sync pre-release CPython 3.15 branch from GitHub (2026-07-02)
Summary: Imported python/cpython `3.15.0b3+dev` from upstream rev [`7d8b0b3`](https://www.github.com/python/cpython/commit/7d8b0b3a81df388274402d4172e89f97e2ed0146) (committed 2026-07-02 03:20:31+00:00). # Commit Info - Base: (`3.15.0b3+dev`) - [`fc8d7ed`](https://www.github.com/python/cpython/commit/fc8d7edd56951e7b015d6d6d33a80639196c1197) (commit date: 2026-07-01 03:29:44+00:00) - Imported: (`3.15.0b3+dev`) - [`7d8b0b3`](https://www.github.com/python/cpython/commit/7d8b0b3a81df388274402d4172e89f97e2ed0146) (commit date: 2026-07-02 03:20:31+00:00) # Noteworthy file changes - Low-signal files (11 added) (NEWS.d, docs, .github) Complete list of added/removed files: https://www.internalfb.com/intern/everpaste/?color=0&handle=GJdgwCTtFJ3T8akDAD_PdHS9838ubr0LAAAz Differential Revision: D110429001 fbshipit-source-id: a28b3601bba8f4dd169c1d8108bc1c030a642dbf
1 parent f365bd3 commit 8bc8ee9

46 files changed

Lines changed: 510 additions & 119 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Doc/c-api/module.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ defining the module state.
488488
489489
.. versionadded:: 3.15
490490
491-
Use :c:member:`PyModuleDef.m_size` instead to support previous versions.
491+
Use :c:member:`PyModuleDef.m_traverse` instead to support previous versions.
492492
493493
.. c:macro:: Py_mod_state_clear
494494

Lib/idlelib/News3.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,46 @@ Released on 2026-10-01
44
=========================
55

66

7+
gh-152745: When "Run... Customized" with "Restart shell" unchecked
8+
while Shell is running code, including waiting for an input('prompt:')
9+
response, just report that the shell is executing instead of
10+
reporting twice and restarting anyway. Patch by Serhiy Storchaka.
11+
12+
gh-152743: When an integer entry in IDLE's Settings dialog, such as
13+
"Auto squeeze min lines", is deleted, do not save '', which is an
14+
invalid configuration value. Patch by Serhiy Storchaka.
15+
16+
gh-152742: MakeChange the default extension when saving a Shell or
17+
Output window '.txt' and list text files before Python files. Their
18+
content is not Python source. Patch by Serhiy Storchaka and Claude Code.
19+
20+
gh-152740: Fill the "In files:" field of IDLE's Find in Files dialog
21+
with a full directory path, even for an unsaved editor or the Shell.
22+
In the grep output whow which directory was searched. Patch by Serhiy
23+
Storchaka and Claude Code.
24+
25+
gh-152739: Omit the idlelib directory from the path of the IDLE user
26+
process. User code imports such as `import help' can no longer import
27+
an idlelib submodule (here idlelib.help) instead of the intended
28+
top-level module. Patch by Serhiy Storchaka and Claude Code.
29+
30+
gh-152738: Fix a rare crash in the IDLE editor when the completion
31+
window is closed: deleting a key binding for a sequence that is not
32+
bound to the virtual event is now ignored instead of raising a
33+
ValueError. Patch by Serhiy Storchaka and Claude Code.
34+
35+
gh-152737: Fix Replace All in the IDLE editor's Replace dialog when the
36+
search direction is "Up" and "Wrap around" is off: it now replaces all
37+
matches above the current position instead of only the first one.
38+
Patch by Serhiy Storchaka and Claude Code.
39+
40+
gh-152733: For X11 window managers, set toplevel window classes to
41+
"Idle". Patch by Serhiy Storchaka and Claude Code.
42+
43+
gh-152728: Move functions run.fix_scaling, editor.fixwordbreaks
44+
(as 'fix_word_breaks') and pyshell.fix_x11_paste to module util.
45+
Patch by Terry J. Reedy.
46+
747
gh-85320: IDLE now reads and writes its configuration files and the
848
breakpoints file using UTF-8 instead of the locale encoding.
949
Files with non-ASCII characters and non-UTF-8 encoding may need

Lib/idlelib/configdialog.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2265,7 +2265,11 @@ def make_callback(var, config):
22652265
"Return default callback function to add values to changes instance."
22662266
def default_callback(*params):
22672267
"Add config values to changes instance."
2268-
changes.add_option(*config, var.get())
2268+
value = var.get()
2269+
# A blanked int entry is an empty string; do not save it as an
2270+
# invalid config value (gh-83653).
2271+
if value != '':
2272+
changes.add_option(*config, value)
22692273
return default_callback
22702274

22712275
def attach(self):

Lib/idlelib/editor.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,19 +1704,10 @@ def get_accelerator(keydefs, eventname):
17041704
return s
17051705

17061706

1707-
def fixwordbreaks(root):
1708-
# On Windows, tcl/tk breaks 'words' only on spaces, as in Command Prompt.
1709-
# We want Motif style everywhere. See #21474, msg218992 and followup.
1710-
tk = root.tk
1711-
tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
1712-
tk.call('set', 'tcl_wordchars', r'\w')
1713-
tk.call('set', 'tcl_nonwordchars', r'\W')
1714-
1715-
1716-
def _editor_window(parent): # htest #
1717-
# error if close master window first - timer event, after script
1718-
root = parent
1719-
fixwordbreaks(root)
1707+
def _editor_window(root): # htest #
1708+
# Error if close master window first - timer event, after script
1709+
from util import fix_word_breaks
1710+
fix_word_breaks(root)
17201711
if sys.argv[1:]:
17211712
filename = sys.argv[1]
17221713
else:

Lib/idlelib/filelist.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,12 @@ def canonize(self, filename):
112112

113113

114114
def _test(): # TODO check and convert to htest
115+
# Maybe redundant with test_filelist.FileListTest.test_new_empty.
115116
from tkinter import Tk
116-
from idlelib.editor import fixwordbreaks
117-
from idlelib.run import fix_scaling
117+
from idlelib.util import fix_scaling, fix_word_breaks
118118
root = Tk()
119119
fix_scaling(root)
120-
fixwordbreaks(root)
120+
fix_word_breaks(root)
121121
root.withdraw()
122122
flist = FileList(root)
123123
flist.new()

Lib/idlelib/grep.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,20 @@ def grep(text, io=None, flist=None):
4040
dialog.open(text, searchphrase, io)
4141

4242

43+
def default_glob(path):
44+
"""Return the initial "In files:" pattern for a file path (gh-80504).
45+
46+
Always include a full directory so that grep output shows which
47+
directory was searched.
48+
"""
49+
dir, base = os.path.split(path)
50+
dir = os.path.abspath(dir) # An empty dir becomes the current directory.
51+
head, tail = os.path.splitext(base)
52+
if not tail:
53+
tail = ".py"
54+
return os.path.join(dir, "*" + tail)
55+
56+
4357
def walk_error(msg):
4458
"Handle os.walk error."
4559
print(msg)
@@ -103,11 +117,7 @@ def open(self, text, searchphrase, io=None):
103117
path = io.filename or ""
104118
else:
105119
path = ""
106-
dir, base = os.path.split(path)
107-
head, tail = os.path.splitext(base)
108-
if not tail:
109-
tail = ".py"
110-
self.globvar.set(os.path.join(dir, "*" + tail))
120+
self.globvar.set(default_glob(path))
111121

112122
def create_entries(self):
113123
"Create base entry widgets and add widget for search path."

Lib/idlelib/idle_test/test_configdialog.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,6 +1544,17 @@ def test_make_callback(self):
15441544
self.assertEqual(changes['main']['section']['option'], '42')
15451545
changes.clear()
15461546

1547+
# gh-83653: a blank int entry is not saved as bad config data.
1548+
sv = StringVar(root)
1549+
cb = self.tracers.make_callback(sv, ('main', 'section', 'option'))
1550+
sv.set('')
1551+
cb()
1552+
self.assertNotIn('section', changes['main'])
1553+
sv.set('5')
1554+
cb()
1555+
self.assertEqual(changes['main']['section']['option'], '5')
1556+
changes.clear()
1557+
15471558
def test_attach_detach(self):
15481559
tr = self.tracers
15491560
iv = tr.add(self.iv, self.var_changed_increment)

Lib/idlelib/idle_test/test_editmenu.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import tkinter as tk
88
from tkinter import ttk
99
import unittest
10-
from idlelib import pyshell
10+
from idlelib.util import fix_x11_paste
1111

1212
class PasteTest(unittest.TestCase):
1313
'''Test pasting into widgets that allow pasting.
@@ -18,7 +18,7 @@ class PasteTest(unittest.TestCase):
1818
def setUpClass(cls):
1919
cls.root = root = tk.Tk()
2020
cls.root.withdraw()
21-
pyshell.fix_x11_paste(root)
21+
fix_x11_paste(root)
2222
cls.text = tk.Text(root)
2323
cls.entry = tk.Entry(root)
2424
cls.tentry = ttk.Entry(root)

Lib/idlelib/idle_test/test_grep.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,25 @@ def close(self): # gui method
3737
_grep = Dummy_grep()
3838

3939

40+
class DefaultGlobTest(unittest.TestCase):
41+
42+
def test_no_path(self):
43+
# gh-80504: an unsaved editor or the Shell has no path, so the
44+
# pattern uses the current directory, not just '*.py'.
45+
self.assertEqual(grep.default_glob(''),
46+
os.path.join(os.getcwd(), '*.py'))
47+
48+
def test_full_path(self):
49+
path = os.path.join(os.path.abspath(os.sep), 'ab', 'foo.py')
50+
self.assertEqual(grep.default_glob(path),
51+
os.path.join(os.path.dirname(path), '*.py'))
52+
53+
def test_other_extension(self):
54+
path = os.path.join(os.path.abspath(os.sep), 'ab', 'foo.txt')
55+
self.assertEqual(grep.default_glob(path),
56+
os.path.join(os.path.dirname(path), '*.txt'))
57+
58+
4059
class FindfilesTest(unittest.TestCase):
4160

4261
@classmethod

Lib/idlelib/idle_test/test_multicall.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,22 @@ def test_yview(self):
4343
mctext = self.mc(self.root)
4444
self.assertIs(mctext.yview.__func__, Text.yview)
4545

46+
def test_event_delete_unbound_sequence(self):
47+
# gh-89360: deleting a sequence that was not added to a virtual
48+
# event is ignored instead of raising ValueError.
49+
mctext = self.mc(self.root)
50+
mctext.event_add('<<tester>>', '<Control-Key-a>')
51+
info = mctext.event_info('<<tester>>')
52+
self.assertEqual(len(info), 1)
53+
54+
# A different sequence, never added: a no-op, not an error.
55+
mctext.event_delete('<<tester>>', '<Control-Key-b>')
56+
self.assertEqual(mctext.event_info('<<tester>>'), info)
57+
58+
# The added sequence can still be deleted normally.
59+
mctext.event_delete('<<tester>>', '<Control-Key-a>')
60+
self.assertNotIn(info[0], mctext.event_info('<<tester>>'))
61+
4662

4763
if __name__ == '__main__':
4864
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)