New submission from Terry J. Reedy:

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.

----------
messages: 253671
nosy: markroseman, terry.reedy
priority: normal
severity: normal
stage: needs patch
status: open
title: IDLE: user code 'import tkinter; tkinter.font' should fail
type: behavior
versions: Python 2.7, Python 3.4, Python 3.5, Python 3.6

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue25507>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to