bpo-29446: tkinter 'import *' only imports what it should (GH-14864)

Add __all__ to tkinter.__init__ and submodules.  Replace 'import *'
with explicit imports in some submodules.
This commit is contained in:
Flavian Hautbois 2019-07-26 03:30:33 +02:00 committed by Terry Jan Reedy
parent c4cda4369f
commit 76b645124b
12 changed files with 52 additions and 15 deletions

View File

@ -32,13 +32,13 @@ tk.mainloop()
import enum import enum
import sys import sys
import types
import _tkinter # If this fails your Python may not be configured for Tk import _tkinter # If this fails your Python may not be configured for Tk
TclError = _tkinter.TclError TclError = _tkinter.TclError
from tkinter.constants import * from tkinter.constants import *
import re import re
wantobjects = 1 wantobjects = 1
TkVersion = float(_tkinter.TK_VERSION) TkVersion = float(_tkinter.TK_VERSION)
@ -4569,5 +4569,9 @@ def _test():
root.mainloop() root.mainloop()
__all__ = [name for name, obj in globals().items()
if not name.startswith('_') and not isinstance(obj, types.ModuleType)
and name not in {'wantobjects'}]
if __name__ == '__main__': if __name__ == '__main__':
_test() _test()

View File

@ -21,6 +21,8 @@
from tkinter.commondialog import Dialog from tkinter.commondialog import Dialog
__all__ = ["Chooser", "askcolor"]
# #
# color chooser class # color chooser class

View File

@ -8,15 +8,17 @@
# written by Fredrik Lundh, May 1997 # written by Fredrik Lundh, May 1997
# #
from tkinter import * __all__ = ["Dialog"]
from tkinter import Frame
class Dialog: class Dialog:
command = None command = None
def __init__(self, master=None, **options): def __init__(self, master=None, **options):
self.master = master self.master = master
self.options = options self.options = options
if not master and options.get('parent'): if not master and options.get('parent'):
self.master = options['parent'] self.master = options['parent']

View File

@ -1,7 +1,8 @@
# dialog.py -- Tkinter interface to the tk_dialog script. # dialog.py -- Tkinter interface to the tk_dialog script.
from tkinter import * from tkinter import _cnfmerge, Widget, TclError, Button, Pack
from tkinter import _cnfmerge
__all__ = ["Dialog"]
DIALOG_ICON = 'questhead' DIALOG_ICON = 'questhead'

View File

@ -99,9 +99,10 @@ active; it will never call dnd_commit().
""" """
import tkinter import tkinter
__all__ = ["dnd_start", "DndHandler"]
# The factory function # The factory function

View File

@ -11,14 +11,20 @@ to the native file dialogues available in Tk 4.2 and newer, and the
directory dialogue available in Tk 8.3 and newer. directory dialogue available in Tk 8.3 and newer.
These interfaces were written by Fredrik Lundh, May 1997. These interfaces were written by Fredrik Lundh, May 1997.
""" """
__all__ = ["FileDialog", "LoadFileDialog", "SaveFileDialog",
"Open", "SaveAs", "Directory",
"askopenfilename", "asksaveasfilename", "askopenfilenames",
"askopenfile", "askopenfiles", "asksaveasfile", "askdirectory"]
from tkinter import * import fnmatch
import os
from tkinter import (
Frame, LEFT, YES, BOTTOM, Entry, TOP, Button, Tk, X,
Toplevel, RIGHT, Y, END, Listbox, BOTH, Scrollbar,
)
from tkinter.dialog import Dialog from tkinter.dialog import Dialog
from tkinter import commondialog from tkinter import commondialog
import os
import fnmatch
dialogstates = {} dialogstates = {}

View File

@ -3,11 +3,12 @@
# written by Fredrik Lundh, February 1998 # written by Fredrik Lundh, February 1998
# #
__version__ = "0.9"
import itertools import itertools
import tkinter import tkinter
__version__ = "0.9"
__all__ = ["NORMAL", "ROMAN", "BOLD", "ITALIC",
"nametofont", "Font", "families", "names"]
# weight/slant # weight/slant
NORMAL = "normal" NORMAL = "normal"

View File

@ -24,6 +24,10 @@
from tkinter.commondialog import Dialog from tkinter.commondialog import Dialog
__all__ = ["showinfo", "showwarning", "showerror",
"askquestion", "askokcancel", "askyesno",
"askyesnocancel", "askretrycancel"]
# #
# constants # constants

View File

@ -11,11 +11,11 @@ Most methods calls are inherited from the Text widget; Pack, Grid and
Place methods are redirected to the Frame widget however. Place methods are redirected to the Frame widget however.
""" """
__all__ = ['ScrolledText']
from tkinter import Frame, Text, Scrollbar, Pack, Grid, Place from tkinter import Frame, Text, Scrollbar, Pack, Grid, Place
from tkinter.constants import RIGHT, LEFT, Y, BOTH from tkinter.constants import RIGHT, LEFT, Y, BOTH
__all__ = ['ScrolledText']
class ScrolledText(Text): class ScrolledText(Text):
def __init__(self, master=None, **kw): def __init__(self, master=None, **kw):

View File

@ -7,6 +7,20 @@ support.requires('gui')
class MiscTest(AbstractTkTest, unittest.TestCase): class MiscTest(AbstractTkTest, unittest.TestCase):
def test_all(self):
self.assertIn("Widget", tkinter.__all__)
# Check that variables from tkinter.constants are also in tkinter.__all__
self.assertIn("CASCADE", tkinter.__all__)
self.assertIsNotNone(tkinter.CASCADE)
# Check that sys, re, and constants are not in tkinter.__all__
self.assertNotIn("re", tkinter.__all__)
self.assertNotIn("sys", tkinter.__all__)
self.assertNotIn("constants", tkinter.__all__)
# Check that an underscored functions is not in tkinter.__all__
self.assertNotIn("_tkerror", tkinter.__all__)
# Check that wantobjects is not in tkinter.__all__
self.assertNotIn("wantobjects", tkinter.__all__)
def test_repr(self): def test_repr(self):
t = tkinter.Toplevel(self.root, name='top') t = tkinter.Toplevel(self.root, name='top')
f = tkinter.Frame(t, name='child') f = tkinter.Frame(t, name='child')

View File

@ -649,6 +649,7 @@ Zac Hatfield-Dodds
Shane Hathaway Shane Hathaway
Michael Haubenwallner Michael Haubenwallner
Janko Hauser Janko Hauser
Flavian Hautbois
Rycharde Hawkes Rycharde Hawkes
Ben Hayden Ben Hayden
Jochen Hayek Jochen Hayek

View File

@ -0,0 +1 @@
Make `from tkinter import *` import only the expected objects.