Skip to content

Commit eac1dcf

Browse files
[3.14] gh-156896: Stop scrubbing tkinter submodules upon idlelib.run import (GH-156915) (#156959)
gh-156896: Stop scrubbing tkinter submodules upon idlelib.run import (#156915) Instead, invoke the scrubbing within run.main, which is called after the import when starting the IDLE user process. To manually test that scrub_tkinter_submodules is called when proper, start (or restart) Shell, enter `import tkinter; dir(tkinter), and check that that font, messagebox, ttk, and the dialog modules are missing. It is obvious from the code that the function is not otherwise called. To test anyway, continue with `import tkinter.ttk; import idlelib.run; tkinter.ttk` and check for proper output. (cherry picked from commit e50d233) Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
1 parent 113ad29 commit eac1dcf

2 files changed

Lines changed: 18 additions & 10 deletions

File tree

Lib/idlelib/run.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
""" idlelib.run
22
3-
Simplified, pyshell.ModifiedInterpreter spawns a subprocess with
3+
Simplified: pyshell.ModifiedInterpreter spawns a subprocess with
44
f'''{sys.executable} -c "__import__('idlelib.run').run.main()"'''
55
'.run' is needed because __import__ returns idlelib, not idlelib.run.
66
"""
@@ -26,18 +26,23 @@
2626
from idlelib import rpc # multiple objects
2727
from idlelib import stackviewer # StackTreeItem
2828
from idlelib import util # fix_scaling
29-
import __main__
29+
import __main__ # self.locals in Executive.__init__.
3030

3131
import tkinter # Use tcl and, if startup fails, messagebox.
32-
if not hasattr(sys.modules['idlelib.run'], 'firstrun'):
33-
# Undo modifications of tkinter by idlelib imports; see bpo-25507.
32+
33+
def scrub_tkinter_submodules(): # Call in main when starting user process.
34+
# Undo modifications of tkinter by idlelib imports; see gh-69693.
35+
# Which of these submodules got imported (and thus added as a tkinter
36+
# attribute) depends on what idlelib pulled in, so tolerate missing
37+
# ones rather than assuming a fixed set; see gh-59396.
3438
for mod in ('simpledialog', 'messagebox', 'font',
3539
'dialog', 'filedialog', 'commondialog',
3640
'ttk'):
37-
delattr(tkinter, mod)
38-
del sys.modules['tkinter.' + mod]
39-
# Avoid AttributeError if run again; see bpo-37038.
40-
sys.modules['idlelib.run'].firstrun = False
41+
try:
42+
delattr(tkinter, mod)
43+
del sys.modules['tkinter.' + mod]
44+
except (AttributeError, KeyError):
45+
pass
4146

4247
LOCALHOST = '127.0.0.1'
4348

@@ -133,6 +138,9 @@ def main(del_exitfunc=False):
133138
register and unregister themselves.
134139
135140
"""
141+
142+
scrub_tkinter_submodules()
143+
136144
global exit_now
137145
global quitting
138146
global no_exitfunc
@@ -699,8 +707,7 @@ def stackviewer(self, flist_oid=None):
699707
item = stackviewer.StackTreeItem(exc, flist)
700708
return debugobj_r.remote_object_tree_item(item)
701709

702-
703-
if __name__ == '__main__':
710+
if __name__ == '__main__': # __name__ is 'idlelib.run' in user subprocess.
704711
from unittest import main
705712
main('idlelib.idle_test.test_run', verbosity=2)
706713

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Stop deleting tkinter submodules when idlelib.run is imported.

0 commit comments

Comments
 (0)