Title: Improve tkinter 'import *' situation
Type: behavior Stage: needs patch
Components: Tkinter Versions: Python 3.7, Python 3.6, Python 3.5, Python 2.7
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: ceronman, eric.smith, ethan.furman, louielu, serhiy.storchaka, terry.reedy
Priority: normal Keywords: easy

Created on 2017-02-04 21:24 by terry.reedy, last changed 2019-02-24 20:53 by ceronman.

Messages (6)
msg286996 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2017-02-04 21:24
Tkinter naming was designed so that 'from tkinter import *' can work, in the sense of not conflicting with built-in and stdlib module names.  But there are currently two problems.

1. The current doc use Tkinter all you need is a simple import statement:
  import tkinter
Or, more often:
  from tkinter import * 

over-promotes 'import *' as the common and therefore normal import (as opposed to a convenience for interactive use).  It neglects the alternatives 'import tkinter as tk' or 'from tkinter import Tk, ...', and consequently makes no mention of the relative advantages.

2. The current code does not define __all__.  So the stdlib imports of enum, re, and sys get carried over with 'import *'.  Guido recommends defining __all__ to prevent this.*  Since tkinter defines about 160 names, and since there are only 3 names to block, and there are used pretty sparingly, I prefer the uglier alternative of renaming with underscores: 'import enum as _enum', etc.

I will work on patches.  Since the doc change can apply to all current versions while the code change might be restricted to 3.7, I will keep then separate.

* From pydev thread 'Imports with underscores', 2017-1-9:

"I would focus on changing habits to discourage "import *" rather than
uglifying all new code with this "os as _os" pattern. Very occasionally
one designs a module to explicitly support "import *", and that usually
entails using __all__ (like it or not), making the problem go away
without uglifying the code."
msg286997 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-02-04 22:20
There is yet one name that doesn't make sense to import -- wantobjects. It can't be renamed.
msg287028 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2017-02-05 01:14
This issue is spun-off from #29162, which was about idlelib.pyshell depending on import * importing sys.

'wantobjects' does not have the same bug potential as stdlib imports.  But, Serhiy, if you care about it or otherwise prefer __all__,

__all__ = [name for name in globals() if not name.startswith('_') and name not in {'enum', 're', 'sys', 'wantobjects'}]

should work if placed near the end of the file, just before 'def _test'.  Except for the exclusion set, I presume that 'import *' does essentially the same iteration
msg287041 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-02-05 08:06
msg287049 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2017-02-05 15:35
Instead of:
__all__ = [name for name in globals() if not name.startswith('_') and name not in {'enum', 're', 'sys', 'wantobjects'}]

Maybe this would be less fragile:
import types
__all__ = [name for name, obj in globals().items() if not name.startswith('_') and not isinstance(obj, types.ModuleType) and name not in {'wantobjects'}]

That is, exclude all modules. Admittedly, I had to import types, but there are other ways to do this test without that import.
msg287052 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-02-05 15:45
This also excludes "constants" implicitly added by importing names from tkinter.constants. I don't know whether this is good or bad.

Interesting, but

    from tkinter import *
    import tkinter.ttk


    import tkinter.ttk
    from tkinter import *

have different effects.
Date User Action Args
2019-02-24 20:53:15ceronmansetnosy: + ceronman
2017-04-05 05:12:47louielusetnosy: + louielu
2017-04-02 05:30:14serhiy.storchakasetkeywords: + easy
stage: test needed -> needs patch
versions: + Python 2.7, Python 3.5, Python 3.6
2017-02-05 15:45:37serhiy.storchakasetmessages: + msg287052
2017-02-05 15:35:45eric.smithsetnosy: + eric.smith
messages: + msg287049
2017-02-05 08:06:09serhiy.storchakasetmessages: + msg287041
2017-02-05 01:14:25terry.reedysetmessages: + msg287028
2017-02-04 22:20:40serhiy.storchakasetmessages: + msg286997
2017-02-04 21:38:32ethan.furmansetnosy: + ethan.furman
2017-02-04 21:24:25terry.reedycreate