https://github.com/python/cpython/commit/e076f9c5f89422f2a92d370d052007e936a0e0ab
commit: e076f9c5f89422f2a92d370d052007e936a0e0ab
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: terryjreedy <[email protected]>
date: 2026-07-01T02:10:03-04:00
summary:

[3.13] gh-152728: IDLE - move 3 toplevel fix_xyz functions to idlelb.util 
(GH-152729) (#152732)

gh-152728: IDLE - move 3 toplevel fix_xyz functions to idlelb.util (GH-152729)

IDLE - move 3 toplevel fix_xyz functions to idlelb.util

Move idlelib functions run.fix_scaling, editor.fixwordbreaks
(as fix_word_breaks).  All are used in at least 3 modules.
(cherry picked from commit 53ca52ddb0c2725a1c34e4eb2245339cd3dcaa84)

Co-authored-by: Terry Jan Reedy <[email protected]>

files:
A Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst
M Lib/idlelib/News3.txt
M Lib/idlelib/editor.py
M Lib/idlelib/filelist.py
M Lib/idlelib/idle_test/test_editmenu.py
M Lib/idlelib/idle_test/test_sidebar.py
M Lib/idlelib/pyshell.py
M Lib/idlelib/run.py
M Lib/idlelib/util.py

diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt
index 306b494e5f04515..3b1c1fe45a37ed9 100644
--- a/Lib/idlelib/News3.txt
+++ b/Lib/idlelib/News3.txt
@@ -4,6 +4,9 @@ Released after 2024-10-07
 =========================
 
 
+gh-152728: Move functions run.fix_scaling, editor.fixwordbreaks (as 
fix_word_breaks)
+and pyshell.fix_x11_paste to module util. Patch by Terry J. Reedy.
+
 gh-85320: IDLE now reads and writes its configuration files and the
 breakpoints file using UTF-8 instead of the locale encoding.
 Files with non-ASCII characters and non-UTF-8 encoding may need
diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py
index 3128934763a1c08..e618ac9ce0d4d23 100644
--- a/Lib/idlelib/editor.py
+++ b/Lib/idlelib/editor.py
@@ -1685,19 +1685,10 @@ def get_accelerator(keydefs, eventname):
     return s
 
 
-def fixwordbreaks(root):
-    # On Windows, tcl/tk breaks 'words' only on spaces, as in Command Prompt.
-    # We want Motif style everywhere. See #21474, msg218992 and followup.
-    tk = root.tk
-    tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
-    tk.call('set', 'tcl_wordchars', r'\w')
-    tk.call('set', 'tcl_nonwordchars', r'\W')
-
-
-def _editor_window(parent):  # htest #
-    # error if close master window first - timer event, after script
-    root = parent
-    fixwordbreaks(root)
+def _editor_window(root):  # htest #
+    # Error if close master window first - timer event, after script
+    from util import fix_word_breaks
+    fix_word_breaks(root)
     if sys.argv[1:]:
         filename = sys.argv[1]
     else:
diff --git a/Lib/idlelib/filelist.py b/Lib/idlelib/filelist.py
index e27e5d32a0ff633..384908f911f5153 100644
--- a/Lib/idlelib/filelist.py
+++ b/Lib/idlelib/filelist.py
@@ -112,12 +112,12 @@ def canonize(self, filename):
 
 
 def _test():  # TODO check and convert to htest
+    # Maybe redundant with test_filelist.FileListTest.test_new_empty.
     from tkinter import Tk
-    from idlelib.editor import fixwordbreaks
-    from idlelib.run import fix_scaling
+    from idlelib.util import fix_scaling, fix_word_breaks
     root = Tk()
     fix_scaling(root)
-    fixwordbreaks(root)
+    fix_word_breaks(root)
     root.withdraw()
     flist = FileList(root)
     flist.new()
diff --git a/Lib/idlelib/idle_test/test_editmenu.py 
b/Lib/idlelib/idle_test/test_editmenu.py
index 17478473a3d1b27..0d1eb9054918da7 100644
--- a/Lib/idlelib/idle_test/test_editmenu.py
+++ b/Lib/idlelib/idle_test/test_editmenu.py
@@ -7,7 +7,7 @@
 import tkinter as tk
 from tkinter import ttk
 import unittest
-from idlelib import pyshell
+from idlelib.util import fix_x11_paste
 
 class PasteTest(unittest.TestCase):
     '''Test pasting into widgets that allow pasting.
@@ -18,7 +18,7 @@ class PasteTest(unittest.TestCase):
     def setUpClass(cls):
         cls.root = root = tk.Tk()
         cls.root.withdraw()
-        pyshell.fix_x11_paste(root)
+        fix_x11_paste(root)
         cls.text = tk.Text(root)
         cls.entry = tk.Entry(root)
         cls.tentry = ttk.Entry(root)
diff --git a/Lib/idlelib/idle_test/test_sidebar.py 
b/Lib/idlelib/idle_test/test_sidebar.py
index 3e854561a0f5b97..4b3429a270d7b87 100644
--- a/Lib/idlelib/idle_test/test_sidebar.py
+++ b/Lib/idlelib/idle_test/test_sidebar.py
@@ -11,11 +11,10 @@
 from idlelib.idle_test.tkinter_testing_utils import run_in_tk_mainloop
 
 from idlelib.delegator import Delegator
-from idlelib.editor import fixwordbreaks
 from idlelib.percolator import Percolator
 import idlelib.pyshell
-from idlelib.pyshell import fix_x11_paste, PyShell, PyShellFileList
-from idlelib.run import fix_scaling
+from idlelib.pyshell import PyShell, PyShellFileList
+from idlelib.util import fix_scaling, fix_word_breaks, fix_x11_paste
 import idlelib.sidebar
 from idlelib.sidebar import get_end_linenumber, get_lineno
 
@@ -403,7 +402,7 @@ def setUpClass(cls):
         root.withdraw()
 
         fix_scaling(root)
-        fixwordbreaks(root)
+        fix_word_breaks(root)
         fix_x11_paste(root)
 
         cls.flist = flist = PyShellFileList(root)
diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py
index 68d2002c85e17a8..2e8435cd17fe618 100755
--- a/Lib/idlelib/pyshell.py
+++ b/Lib/idlelib/pyshell.py
@@ -36,13 +36,14 @@
 from idlelib.delegator import Delegator
 from idlelib import debugger
 from idlelib import debugger_r
-from idlelib.editor import EditorWindow, fixwordbreaks
+from idlelib.editor import EditorWindow
 from idlelib.filelist import FileList
 from idlelib.outwin import OutputWindow
 from idlelib import replace
 from idlelib import rpc
 from idlelib.run import idle_formatwarning, StdInputFile, StdOutputFile
 from idlelib.undo import UndoDelegator
+from idlelib.util import fix_word_breaks
 
 # Default for testing; defaults to True in main() for running.
 use_subprocess = False
@@ -882,9 +883,9 @@ def __init__(self, flist=None):
         if ms[2][0] != "shell":
             ms.insert(2, ("shell", "She_ll"))
         self.interp = ModifiedInterpreter(self)
-        if flist is None:
+        if flist is None:  # TODO possible? root and flist in main.
             root = Tk()
-            fixwordbreaks(root)
+            fix_word_breaks(root)
             root.withdraw()
             flist = PyShellFileList(root)
 
@@ -1453,17 +1454,6 @@ def on_squeezed_expand(self, index, text, tags):
         self.shell_sidebar.update_sidebar()
 
 
-def fix_x11_paste(root):
-    "Make paste replace selection on x11.  See issue #5124."
-    if root._windowingsystem == 'x11':
-        for cls in 'Text', 'Entry', 'Spinbox':
-            root.bind_class(
-                cls,
-                '<<Paste>>',
-                'catch {%W delete sel.first sel.last}\n' +
-                        root.bind_class(cls, '<<Paste>>'))
-
-
 usage_msg = """\
 
 USAGE: idle  [-deins] [-t title] [file]*
@@ -1523,6 +1513,7 @@ def main():
     from platform import system
     from idlelib import testing  # bool value
     from idlelib import macosx
+    from idlelib.util import fix_scaling, fix_x11_paste
 
     global flist, root, use_subprocess
 
@@ -1608,7 +1599,6 @@ def main():
         NoDefaultRoot()
     root = Tk(className="Idle")
     root.withdraw()
-    from idlelib.run import fix_scaling
     fix_scaling(root)
 
     # set application icon
@@ -1630,7 +1620,7 @@ def main():
         root.wm_iconphoto(True, *icons)
 
     # start editor and/or shell windows:
-    fixwordbreaks(root)
+    fix_word_breaks(root)
     fix_x11_paste(root)
     flist = PyShellFileList(root)
     macosx.setupApp(root, flist)
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index a30db99a619a93b..30f9484ff325308 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -25,6 +25,7 @@
 from idlelib import iomenu  # encoding
 from idlelib import rpc  # multiple objects
 from idlelib import stackviewer  # StackTreeItem
+from idlelib import util  # fix_scaling
 import __main__
 
 import tkinter  # Use tcl and, if startup fails, messagebox.
@@ -216,7 +217,7 @@ def show_socket_error(err, address):
     import tkinter
     from tkinter.messagebox import showerror
     root = tkinter.Tk()
-    fix_scaling(root)
+    util.fix_scaling(root)
     root.withdraw()
     showerror(
             "Subprocess Connection Error",
@@ -326,16 +327,6 @@ def exit():
     sys.exit(0)
 
 
-def fix_scaling(root):
-    """Scale fonts on HiDPI displays."""
-    import tkinter.font
-    scaling = float(root.tk.call('tk', 'scaling'))
-    if scaling > 1.4:
-        for name in tkinter.font.names(root):
-            font = tkinter.font.Font(root=root, name=name, exists=True)
-            size = int(font['size'])
-            if size < 0:
-                font['size'] = round(-0.75*size)
 
 
 def fixdoc(fun, text):
diff --git a/Lib/idlelib/util.py b/Lib/idlelib/util.py
index e05604ab4853f6d..bf88c905e1d177d 100644
--- a/Lib/idlelib/util.py
+++ b/Lib/idlelib/util.py
@@ -19,6 +19,20 @@
 py_extensions = ('.py', '.pyw', '.pyi')
 
 
+# fix_x functions seem only needed once per process.
+
+def fix_scaling(root):  # Called in filelist _test, pyshell, and run.
+    """Scale fonts on HiDPI displays, once per process."""
+    import tkinter.font
+    scaling = float(root.tk.call('tk', 'scaling'))
+    if scaling > 1.4:
+        for name in tkinter.font.names(root):
+            font = tkinter.font.Font(root=root, name=name, exists=True)
+            size = int(font['size'])
+            if size < 0:
+                font['size'] = round(-0.75*size)
+
+
 # Fix for HiDPI screens on Windows.  CALL BEFORE ANY TK OPERATIONS!
 # URL for arguments for the ...Awareness call below.
 # 
https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx
@@ -31,6 +45,25 @@ def fix_win_hidpi():  # Called in pyshell and turtledemo.
         except (ImportError, AttributeError, OSError):
             pass
 
+def fix_word_breaks(root):  # Called in editor htest, filelist _test, pyshell.
+    # On Windows, tcl/tk breaks 'words' only on spaces, as in Command Prompt.
+    # We want Motif style everywhere. See #21474, msg218992 and followup.
+    tk = root.tk
+    tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
+    tk.call('set', 'tcl_wordchars', r'\w')
+    tk.call('set', 'tcl_nonwordchars', r'\W')
+
+
+def fix_x11_paste(root):
+    "Make paste replace selection on x11.  See issue #5124."
+    if root._windowingsystem == 'x11':
+        for cls in 'Text', 'Entry', 'Spinbox':
+            root.bind_class(
+                cls,
+                '<<Paste>>',
+                'catch {%W delete sel.first sel.last}\n' +
+                        root.bind_class(cls, '<<Paste>>'))
+
 
 if __name__ == '__main__':
     from unittest import main
diff --git 
a/Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst 
b/Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst
new file mode 100644
index 000000000000000..d73512a615c1898
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2026-07-01-00-15-58.gh-issue-152728.yxIhMN.rst
@@ -0,0 +1,2 @@
+Move functions run.fix_scaling, editor.fixwordbreaks (as fix_word_breaks)
+and pyshell.fix_x11_paste to idlelib.util.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to