-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
bpo-29446: Improve tkinter 'import *' situation #14864
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-29446: Improve tkinter 'import *' situation #14864
Conversation
55f563e
to
d3916dd
Compare
7cf43f0
to
76c8d35
Compare
Lib/tkinter/__init__.py
Outdated
|
||
__all__internals_used_in_submodules = [ | ||
"_cnfmerge", # Used in tkinter.dialog | ||
"_default_root", # Used in tkinter.simpledialog |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_default_root
should never be imported, neither implicitly, nor implicitly.
_cnfmerge
should not be imported implicitly since it is an internal function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_default_root
is already imported in tkinter.simpledialog and _cnfmerge
is used in dialog.py
For _cnfmerge
the change is straightforward: I just have to omit it in __all__
and the import in dialog.py will work just fine
For _default_root
I don't know how to remove it from simpledialog.py
without affecting the behaviour of _QueryDialog
. I can't leave parent
as None if no parent is passed because then the line if parent.winfo_viewable():
will fail.
Same in font.py
.
I updated the PR to not export _cnfmerge
and _default_root
in __all__
, but could not prevent _default_root
from being used elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it is not imported, but is accessed as an attribute of tkinter
.
The difference is that its value is changed after importing. When you import the submodule, it is None. After creating a root widget it keeps a reference to it, which can be used as a default parent in _QueryDialog
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the clarification!
Lib/tkinter/constants.py
Outdated
@@ -1,110 +1,110 @@ | |||
# Symbolic constants for Tk | |||
|
|||
# Booleans | |||
NO=FALSE=OFF=0 | |||
YES=TRUE=ON=1 | |||
NO = FALSE = OFF = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an unrelated change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, I dismissed those changes. Can I open a new PR to add this change?
Lib/tkinter/filedialog.py
Outdated
Toplevel, | ||
commondialog, | ||
) | ||
from tkinter.constants import ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could not this be written in one line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was unsure about the code style here. What's the standard?
I reworked the imports though, so there might not be any problem any more
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flavian, thank you for making a start on this; As for changes, I pretty much agree with Serhiy.
1 Use Eric's suggestion for things defined in .__init__
and exclude submodules.
2. Make lists horizontal, with multiple items per line (this is pretty standard).
3. Put PEP 8 style changes in another PR, or even another issue; but only after asking Serhiy if he wants them, or at least would merge them.
4. I never wrote about submodules, but __all__
for each, except Tix (leave alone), would be nice.
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
With respect to the list in your initial comment: The 'Var's are absolutely essential. Without checking idlelib, I presume the other non-underscore names you list there are used also. |
94460f3
to
7037f85
Compare
I have made the requested changes; please review again |
Thanks for making the requested changes! @terryjreedy: please review the changes made to this pull request. |
0cdd92a
to
5180d87
Compare
import itertools | ||
import tkinter | ||
|
||
__version__ = "0.9" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to move __version__
here to abide to PEP8 also
@serhiy-storchaka All your comments should now be addressed! |
@terryjreedy @serhiy-storchaka Anything blocking? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Serhiy is responsible for final details of tkinter/* changes.
The expression `from tkinter import *` actually imports re, enum, sys, as well as tkinter functions and classesreserved for internal use. This commit dismisses most of those names by defining the __all__ variable in accordance with the documentation in tkinter and its submodules.
7ea2ce5
to
2345535
Compare
2345535
to
e9cae4f
Compare
@terryjreedy I had to remove your commit "Move editor.py changes to another PR for full backport" because it was undoing your own changes when I rebased on master ;) |
Serhiy, as near as I can tell, this is ready to go. If you agree, it would be nice to get it into a3, due next Monday. |
Lib/tkinter/font.py
Outdated
import itertools | ||
import tkinter | ||
|
||
__version__ = "0.9" | ||
__all__ = ["NORMAL", "ROMAN", "BOLD", "ITALIC", "nametofont", "Font", "families", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would break a line after "ITALIC"
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing. What is your rule for line breaks? I'd like to automate it in my IDE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is hard to automate. Semantically the first four names in this list are names of constants.
Lib/tkinter/messagebox.py
Outdated
@@ -24,6 +24,9 @@ | |||
|
|||
from tkinter.commondialog import Dialog | |||
|
|||
__all__ = ["showinfo", "showwarning", "showerror", "askquestion", "askokcancel", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to break a line after "showerror"
.
Lib/tkinter/filedialog.py
Outdated
@@ -11,14 +11,19 @@ | |||
directory dialogue available in Tk 8.3 and newer. | |||
These interfaces were written by Fredrik Lundh, May 1997. | |||
""" | |||
__all__ = ["FileDialog", "LoadFileDialog", "SaveFileDialog", "Open", "SaveAs", | |||
"Directory", "askopenfilename", "asksaveasfilename", "askopenfilenames", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is longer then PEP 8 limit. I would format the list like:
__all__ = ["FileDialog", "LoadFileDialog", "SaveFileDialog",
"Open", "SaveAs", "Directory",
"askopenfilename", "asksaveasfilename", "askopenfilenames",
"askopenfile", "askopenfiles", "asksaveasfile", "askdirectory"]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the 79-character line length to my IDE's configuration for cPython
@serhiy-storchaka Changes done ;) |
@terryjreedy up to you :) |
It doesn't really matter which of us merges. I presume that this should not be backported to 3.8 because b3 is too late for new features, even all. There must be other code that will break with this change, just like IDLE did. Thank you for sticking with this. |
…4864) Add __all__ to tkinter.__init__ and submodules. Replace 'import *' with explicit imports in some submodules.
…4864) Add __all__ to tkinter.__init__ and submodules. Replace 'import *' with explicit imports in some submodules.
…4864) Add __all__ to tkinter.__init__ and submodules. Replace 'import *' with explicit imports in some submodules.
A pull request for this issue.
@ericvsmith recommended using
__all__ = [name for name, obj in globals().items() if not name.startswith('_') and not isinstance(obj, types.ModuleType) and name not in {'wantobjects'}]
.Also added all in submodules of tkinter.
Side note: Interestingly,
idlelib/editor.py
was usingsys
andre
fromtkinter
instead of importing them. There may be more modules that use "from tkinter import *"https://bugs.python.org/issue29446