classification
Title: Improve tkinter 'import *' situation
Type: behavior Stage: resolved
Components: Tkinter Versions: Python 3.9
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: ceronman, eric.smith, ethan.furman, louielu, serhiy.storchaka, terry.reedy
Priority: normal Keywords: easy, patch

Created on 2017-02-04 21:24 by terry.reedy, last changed 2019-07-26 01:36 by terry.reedy. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 14864 merged flavianhautbois, 2019-07-19 15:59
PR 14919 merged terry.reedy, 2019-07-23 20:05
PR 14920 merged miss-islington, 2019-07-23 20:15
PR 14921 merged miss-islington, 2019-07-23 20:15
Messages (12)
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

...to 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
LGTM.
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

and

    import tkinter.ttk
    from tkinter import *

have different effects.
msg348188 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-07-19 18:08
I prefer Eric's approach. It excludes tkinter submodules (like tkinter.ttk). Currently the result of the star import depends on what submodules were imported before. I think it would be better to make it more stable.
msg348199 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2019-07-19 21:26
I agree that for python x.y, the names imported by 'import *' should be fixed and *not* depend on other imports.
msg348350 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2019-07-23 20:15
New changeset c6fd6c83b70df76421d05a7628367e64a2f83589 by Terry Jan Reedy in branch 'master':
bpo-29446: IDLE -- add explicit imports (GH-14919)
https://github.com/python/cpython/commit/c6fd6c83b70df76421d05a7628367e64a2f83589
msg348351 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2019-07-23 20:23
New changeset fc63d5a361f7d20282019cad84336a242c124267 by Terry Jan Reedy (Miss Islington (bot)) in branch '3.8':
bpo-29446: IDLE -- add explicit imports (GH-14919) (GH-14920)
https://github.com/python/cpython/commit/fc63d5a361f7d20282019cad84336a242c124267
msg348353 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2019-07-23 20:37
New changeset aee260f1c4d32bf67edec209d949294d4dc403c1 by Terry Jan Reedy (Miss Islington (bot)) in branch '3.7':
bpo-29446: IDLE -- add explicit imports (GH-14919) (#14921)
https://github.com/python/cpython/commit/aee260f1c4d32bf67edec209d949294d4dc403c1
msg348461 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2019-07-26 01:30
New changeset 76b645124b3aaa34bc664eece43707c01ef1b382 by Terry Jan Reedy (Flavian Hautbois) in branch 'master':
bpo-29446: tkinter 'import *' only imports what it should (GH-14864)
https://github.com/python/cpython/commit/76b645124b3aaa34bc664eece43707c01ef1b382
History
Date User Action Args
2019-07-26 01:36:33terry.reedysetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2019-07-26 01:30:42terry.reedysetmessages: + msg348461
2019-07-23 20:37:03terry.reedysetmessages: + msg348353
2019-07-23 20:23:47terry.reedysetmessages: + msg348351
2019-07-23 20:15:25miss-islingtonsetpull_requests: + pull_request14695
2019-07-23 20:15:18miss-islingtonsetpull_requests: + pull_request14694
2019-07-23 20:15:04terry.reedysetmessages: + msg348350
2019-07-23 20:05:55terry.reedysetpull_requests: + pull_request14693
2019-07-19 21:26:25terry.reedysetmessages: + msg348199
versions: + Python 3.9, - Python 2.7, Python 3.5, Python 3.6, Python 3.7
2019-07-19 18:08:32serhiy.storchakasetmessages: + msg348188
2019-07-19 15:59:23flavianhautboissetkeywords: + patch
stage: needs patch -> patch review
pull_requests: + pull_request14653
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