Author terry.reedy
Recipients markroseman, terry.reedy
Date 2015-10-29.10:10:41
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1446113442.78.0.389498275803.issue25507@psf.upfronthosting.co.za>
In-reply-to
Content
In python, 'import tkinter; tkinter.font' fails with AttributeError.  In IDLE, it does not, which is a bug,  This lead to a Stackoverflow question 'Why does my code run in IDLE but not with Python'?

The issue is that importing modules in a package has the side-effect of adding the module name to the package namespace.  IDLE's user process runs idlelib/run.py.  While *run* does not import tkinter submodules, it imports other modules that do, and the net effect is to add colorchooser, commondialog, dialog, filedialog, font, messagebox, and simpledialog to the tkinter namespace, linked to the corresponding module objects.  None are needed in normal operation.

My first thought was to refactor so that the additions, which run does not need, are not added.  My second thought seemed simpler.  Delete them (in run.py) after the imports.  But it turns out that after deleting a submodule attribute re-import does not work right; the name addition only happens when a module is created, not when found in the sys.modules cache.

>>> import tkinter; import tkinter.font  # imagine this in run.py
>>> tkinter.font
<module tkinter.font...>
>>> del tkinter.font  # and this in run also, after all imports
>>> import tkinter.font  # imagine this in user code
>>> tkinter.font  # and then this
Traceback (most recent call last):  # it does not work as it should
  File "<stdin>", line 1, in <module>
AttributeError: module 'tkinter' has no attribute 'font'

Scratch that idea, and return to refactoring.  An obvious culprit in run.py is the import of PyShell.  This leads to the import of nearly all of idlelib.  However, there are only 4 shared objects actually used, and I believe they could just as well be defined in run (or even in rpc.py or something) and imported from run into PyShell.  Then the PyShell import could be deleted.  I still need to look at the other imports.

On startup, user sys.modules also has about 50 other (non-idlelib) stdlib modules not imported by python itself.  Not importing PyShell in the 2nd process should reduce this number and speed up IDLE startup, which takes several seconds, first time after boot up, on Windows.  It would be good to only import into the user process what is actually needed.

(Initially importing into the idle process only what is needed to start would also be good, but a separate issue.)

In 2.7, Tkinter is not a package, so I do not believe it is directly affected by this issue.  On the other hand, it also imports too much.  So backporting changes to keep things mostly synchronized should benefit 2.7 startup time also.
History
Date User Action Args
2015-10-29 10:10:42terry.reedysetrecipients: + terry.reedy, markroseman
2015-10-29 10:10:42terry.reedysetmessageid: <1446113442.78.0.389498275803.issue25507@psf.upfronthosting.co.za>
2015-10-29 10:10:42terry.reedylinkissue25507 messages
2015-10-29 10:10:41terry.reedycreate