aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xLib/idlelib/pyshell.py4
-rw-r--r--Lib/test/test_idle.py2
-rw-r--r--Lib/tkinter/__init__.py51
-rw-r--r--Lib/tkinter/commondialog.py4
-rw-r--r--Lib/tkinter/font.py6
-rw-r--r--Lib/tkinter/simpledialog.py19
-rw-r--r--Lib/tkinter/test/support.py27
-rw-r--r--Lib/tkinter/test/test_tkinter/test_font.py34
-rw-r--r--Lib/tkinter/test/test_tkinter/test_images.py45
-rw-r--r--Lib/tkinter/test/test_tkinter/test_misc.py82
-rw-r--r--Lib/tkinter/test/test_tkinter/test_simpledialog.py25
-rw-r--r--Lib/tkinter/test/test_tkinter/test_variables.py17
-rw-r--r--Lib/tkinter/test/test_tkinter/test_widgets.py14
-rw-r--r--Lib/tkinter/test/test_ttk/test_extensions.py26
-rw-r--r--Lib/tkinter/test/test_ttk/test_widgets.py14
-rw-r--r--Lib/tkinter/tix.py9
-rw-r--r--Lib/tkinter/ttk.py7
-rw-r--r--Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst4
-rw-r--r--Tools/pynche/PyncheWidget.py12
19 files changed, 315 insertions, 87 deletions
diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py
index c3ecdc7b1b0..abe8a85952b 100755
--- a/Lib/idlelib/pyshell.py
+++ b/Lib/idlelib/pyshell.py
@@ -1061,8 +1061,10 @@ class PyShell(OutputWindow):
(sys.version, sys.platform, self.COPYRIGHT, nosub))
self.text.focus_force()
self.showprompt()
+ # User code should use separate default Tk root window
import tkinter
- tkinter._default_root = None # 03Jan04 KBK What's this?
+ tkinter._support_default_root = True
+ tkinter._default_root = None
return True
def stop_readline(self):
diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py
index b205d356498..8756b766334 100644
--- a/Lib/test/test_idle.py
+++ b/Lib/test/test_idle.py
@@ -20,5 +20,5 @@ from idlelib.idle_test import load_tests
if __name__ == '__main__':
tk.NoDefaultRoot()
unittest.main(exit=False)
- tk._support_default_root = 1
+ tk._support_default_root = True
tk._default_root = None
diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py
index 3bfeb7a0179..1cc18704613 100644
--- a/Lib/tkinter/__init__.py
+++ b/Lib/tkinter/__init__.py
@@ -270,7 +270,7 @@ class Event:
)
-_support_default_root = 1
+_support_default_root = True
_default_root = None
@@ -280,13 +280,26 @@ def NoDefaultRoot():
Call this function to inhibit that the first instance of
Tk is used for windows without an explicit parent window.
"""
- global _support_default_root
- _support_default_root = 0
- global _default_root
+ global _support_default_root, _default_root
+ _support_default_root = False
+ # Delete, so any use of _default_root will immediately raise an exception.
+ # Rebind before deletion, so repeated calls will not fail.
_default_root = None
del _default_root
+def _get_default_root(what=None):
+ if not _support_default_root:
+ raise RuntimeError("No master specified and tkinter is "
+ "configured to not support default root")
+ if not _default_root:
+ if what:
+ raise RuntimeError(f"Too early to {what}: no default root window")
+ root = Tk()
+ assert _default_root is root
+ return _default_root
+
+
def _tkerror(err):
"""Internal function."""
pass
@@ -330,7 +343,7 @@ class Variable:
raise TypeError("name must be a string")
global _varnum
if not master:
- master = _default_root
+ master = _get_default_root('create variable')
self._root = master._root()
self._tk = master.tk
if name:
@@ -591,7 +604,7 @@ class BooleanVar(Variable):
def mainloop(n=0):
"""Run the main loop of Tcl."""
- _default_root.tk.mainloop(n)
+ _get_default_root('run the main loop').tk.mainloop(n)
getint = int
@@ -600,9 +613,9 @@ getdouble = float
def getboolean(s):
- """Convert true and false to integer values 1 and 0."""
+ """Convert Tcl object to True or False."""
try:
- return _default_root.tk.getboolean(s)
+ return _get_default_root('use getboolean()').tk.getboolean(s)
except TclError:
raise ValueError("invalid literal for getboolean()")
@@ -2248,7 +2261,7 @@ class Tk(Misc, Wm):
is the name of the widget class."""
self.master = None
self.children = {}
- self._tkloaded = 0
+ self._tkloaded = False
# to avoid recursions in the getattr code in case of failure, we
# ensure that self.tk is always _something_.
self.tk = None
@@ -2272,7 +2285,7 @@ class Tk(Misc, Wm):
self._loadtk()
def _loadtk(self):
- self._tkloaded = 1
+ self._tkloaded = True
global _default_root
# Version sanity checks
tk_version = self.tk.getvar('tk_version')
@@ -2521,12 +2534,8 @@ class BaseWidget(Misc):
def _setup(self, master, cnf):
"""Internal function. Sets up information about children."""
- if _support_default_root:
- global _default_root
- if not master:
- if not _default_root:
- _default_root = Tk()
- master = _default_root
+ if not master:
+ master = _get_default_root()
self.master = master
self.tk = master.tk
name = None
@@ -3990,9 +3999,7 @@ class Image:
def __init__(self, imgtype, name=None, cnf={}, master=None, **kw):
self.name = None
if not master:
- master = _default_root
- if not master:
- raise RuntimeError('Too early to create image')
+ master = _get_default_root('create image')
self.tk = getattr(master, 'tk', master)
if not name:
Image._last_id += 1
@@ -4146,11 +4153,13 @@ class BitmapImage(Image):
def image_names():
- return _default_root.tk.splitlist(_default_root.tk.call('image', 'names'))
+ tk = _get_default_root('use image_names()').tk
+ return tk.splitlist(tk.call('image', 'names'))
def image_types():
- return _default_root.tk.splitlist(_default_root.tk.call('image', 'types'))
+ tk = _get_default_root('use image_types()').tk
+ return tk.splitlist(tk.call('image', 'types'))
class Spinbox(Widget, XView):
diff --git a/Lib/tkinter/commondialog.py b/Lib/tkinter/commondialog.py
index e56b5baf7d1..cc3069842c3 100644
--- a/Lib/tkinter/commondialog.py
+++ b/Lib/tkinter/commondialog.py
@@ -18,10 +18,10 @@ class Dialog:
command = None
def __init__(self, master=None, **options):
+ if not master:
+ master = options.get('parent')
self.master = master
self.options = options
- if not master and options.get('parent'):
- self.master = options['parent']
def _fixoptions(self):
pass # hook
diff --git a/Lib/tkinter/font.py b/Lib/tkinter/font.py
index a9f79d8e456..c051162bd29 100644
--- a/Lib/tkinter/font.py
+++ b/Lib/tkinter/font.py
@@ -69,7 +69,7 @@ class Font:
def __init__(self, root=None, font=None, name=None, exists=False,
**options):
if not root:
- root = tkinter._default_root
+ root = tkinter._get_default_root('use font')
tk = getattr(root, 'tk', root)
if font:
# get actual settings corresponding to the given font
@@ -184,7 +184,7 @@ class Font:
def families(root=None, displayof=None):
"Get font families (as a tuple)"
if not root:
- root = tkinter._default_root
+ root = tkinter._get_default_root('use font.families()')
args = ()
if displayof:
args = ('-displayof', displayof)
@@ -194,7 +194,7 @@ def families(root=None, displayof=None):
def names(root=None):
"Get names of defined fonts (as a tuple)"
if not root:
- root = tkinter._default_root
+ root = tkinter._get_default_root('use font.names()')
return root.tk.splitlist(root.tk.call("font", "names"))
diff --git a/Lib/tkinter/simpledialog.py b/Lib/tkinter/simpledialog.py
index 85244171117..b882d47c961 100644
--- a/Lib/tkinter/simpledialog.py
+++ b/Lib/tkinter/simpledialog.py
@@ -24,9 +24,7 @@ askstring -- get a string from the user
"""
from tkinter import *
-from tkinter import messagebox
-
-import tkinter # used at _QueryDialog for tkinter._default_root
+from tkinter import messagebox, _get_default_root
class SimpleDialog:
@@ -128,13 +126,17 @@ class Dialog(Toplevel):
title -- the dialog title
'''
- Toplevel.__init__(self, parent)
+ master = parent
+ if not master:
+ master = _get_default_root('create dialog window')
+
+ Toplevel.__init__(self, master)
self.withdraw() # remain invisible for now
- # If the master is not viewable, don't
+ # If the parent is not viewable, don't
# make the child transient, or else it
# would be opened withdrawn
- if parent.winfo_viewable():
+ if parent is not None and parent.winfo_viewable():
self.transient(parent)
if title:
@@ -155,7 +157,7 @@ class Dialog(Toplevel):
self.protocol("WM_DELETE_WINDOW", self.cancel)
- if self.parent is not None:
+ if parent is not None:
self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
parent.winfo_rooty()+50))
@@ -259,9 +261,6 @@ class _QueryDialog(Dialog):
minvalue = None, maxvalue = None,
parent = None):
- if not parent:
- parent = tkinter._default_root
-
self.prompt = prompt
self.minvalue = minvalue
self.maxvalue = maxvalue
diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py
index 467a0b66c26..dbc47a81e65 100644
--- a/Lib/tkinter/test/support.py
+++ b/Lib/tkinter/test/support.py
@@ -36,6 +36,33 @@ class AbstractTkTest:
w.destroy()
self.root.withdraw()
+
+class AbstractDefaultRootTest:
+
+ def setUp(self):
+ self._old_support_default_root = tkinter._support_default_root
+ destroy_default_root()
+ tkinter._support_default_root = True
+ self.wantobjects = tkinter.wantobjects
+
+ def tearDown(self):
+ destroy_default_root()
+ tkinter._default_root = None
+ tkinter._support_default_root = self._old_support_default_root
+
+ def _test_widget(self, constructor):
+ # no master passing
+ x = constructor()
+ self.assertIsNotNone(tkinter._default_root)
+ self.assertIs(x.master, tkinter._default_root)
+ self.assertIs(x.tk, tkinter._default_root.tk)
+ x.destroy()
+ destroy_default_root()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, constructor)
+ self.assertFalse(hasattr(tkinter, '_default_root'))
+
+
def destroy_default_root():
if getattr(tkinter, '_default_root', None):
tkinter._default_root.update_idletasks()
diff --git a/Lib/tkinter/test/test_tkinter/test_font.py b/Lib/tkinter/test/test_tkinter/test_font.py
index 6d1eea44b4d..3f712090643 100644
--- a/Lib/tkinter/test/test_tkinter/test_font.py
+++ b/Lib/tkinter/test/test_tkinter/test_font.py
@@ -2,7 +2,7 @@ import unittest
import tkinter
from tkinter import font
from test.support import requires, run_unittest, gc_collect, ALWAYS_EQ
-from tkinter.test.support import AbstractTkTest
+from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest
requires('gui')
@@ -107,7 +107,37 @@ class FontTest(AbstractTkTest, unittest.TestCase):
)
-tests_gui = (FontTest, )
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+ def test_families(self):
+ self.assertRaises(RuntimeError, font.families)
+ root = tkinter.Tk()
+ families = font.families()
+ self.assertIsInstance(families, tuple)
+ self.assertTrue(families)
+ for family in families:
+ self.assertIsInstance(family, str)
+ self.assertTrue(family)
+ root.destroy()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, font.families)
+
+ def test_names(self):
+ self.assertRaises(RuntimeError, font.names)
+ root = tkinter.Tk()
+ names = font.names()
+ self.assertIsInstance(names, tuple)
+ self.assertTrue(names)
+ for name in names:
+ self.assertIsInstance(name, str)
+ self.assertTrue(name)
+ self.assertIn(fontname, names)
+ root.destroy()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, font.names)
+
+
+tests_gui = (FontTest, DefaultRootTest)
if __name__ == "__main__":
run_unittest(*tests_gui)
diff --git a/Lib/tkinter/test/test_tkinter/test_images.py b/Lib/tkinter/test/test_tkinter/test_images.py
index 6c6cb4e1485..2526e92200d 100644
--- a/Lib/tkinter/test/test_tkinter/test_images.py
+++ b/Lib/tkinter/test/test_tkinter/test_images.py
@@ -2,7 +2,7 @@ import unittest
import tkinter
from test import support
from test.support import os_helper
-from tkinter.test.support import AbstractTkTest, requires_tcl
+from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest, requires_tcl
support.requires('gui')
@@ -20,6 +20,47 @@ class MiscTest(AbstractTkTest, unittest.TestCase):
self.assertIsInstance(image_names, tuple)
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+ def test_image_types(self):
+ self.assertRaises(RuntimeError, tkinter.image_types)
+ root = tkinter.Tk()
+ image_types = tkinter.image_types()
+ self.assertIsInstance(image_types, tuple)
+ self.assertIn('photo', image_types)
+ self.assertIn('bitmap', image_types)
+ root.destroy()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, tkinter.image_types)
+
+ def test_image_names(self):
+ self.assertRaises(RuntimeError, tkinter.image_names)
+ root = tkinter.Tk()
+ image_names = tkinter.image_names()
+ self.assertIsInstance(image_names, tuple)
+ root.destroy()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, tkinter.image_names)
+
+ def test_image_create_bitmap(self):
+ self.assertRaises(RuntimeError, tkinter.BitmapImage)
+ root = tkinter.Tk()
+ image = tkinter.BitmapImage()
+ self.assertIn(image.name, tkinter.image_names())
+ root.destroy()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, tkinter.BitmapImage)
+
+ def test_image_create_photo(self):
+ self.assertRaises(RuntimeError, tkinter.PhotoImage)
+ root = tkinter.Tk()
+ image = tkinter.PhotoImage()
+ self.assertIn(image.name, tkinter.image_names())
+ root.destroy()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, tkinter.PhotoImage)
+
+
class BitmapImageTest(AbstractTkTest, unittest.TestCase):
@classmethod
@@ -331,7 +372,7 @@ class PhotoImageTest(AbstractTkTest, unittest.TestCase):
self.assertEqual(image.transparency_get(4, 6), False)
-tests_gui = (MiscTest, BitmapImageTest, PhotoImageTest,)
+tests_gui = (MiscTest, DefaultRootTest, BitmapImageTest, PhotoImageTest,)
if __name__ == "__main__":
support.run_unittest(*tests_gui)
diff --git a/Lib/tkinter/test/test_tkinter/test_misc.py b/Lib/tkinter/test/test_tkinter/test_misc.py
index b8eea2544f5..585d81ddf9f 100644
--- a/Lib/tkinter/test/test_tkinter/test_misc.py
+++ b/Lib/tkinter/test/test_tkinter/test_misc.py
@@ -1,7 +1,7 @@
import unittest
import tkinter
from test import support
-from tkinter.test.support import AbstractTkTest
+from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest
support.requires('gui')
@@ -241,7 +241,85 @@ class MiscTest(AbstractTkTest, unittest.TestCase):
" num=3 delta=-1 focus=True"
" x=10 y=20 width=300 height=200>")
-tests_gui = (MiscTest, )
+ def test_getboolean(self):
+ for v in 'true', 'yes', 'on', '1', 't', 'y', 1, True:
+ self.assertIs(self.root.getboolean(v), True)
+ for v in 'false', 'no', 'off', '0', 'f', 'n', 0, False:
+ self.assertIs(self.root.getboolean(v), False)
+ self.assertRaises(ValueError, self.root.getboolean, 'yea')
+ self.assertRaises(ValueError, self.root.getboolean, '')
+ self.assertRaises(TypeError, self.root.getboolean, None)
+ self.assertRaises(TypeError, self.root.getboolean, ())
+
+ def test_mainloop(self):
+ log = []
+ def callback():
+ log.append(1)
+ self.root.after(100, self.root.quit)
+ self.root.after(100, callback)
+ self.root.mainloop(1)
+ self.assertEqual(log, [])
+ self.root.mainloop(0)
+ self.assertEqual(log, [1])
+ self.assertTrue(self.root.winfo_exists())
+
+
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+ def test_default_root(self):
+ self.assertIs(tkinter._support_default_root, True)
+ self.assertIsNone(tkinter._default_root)
+ root = tkinter.Tk()
+ root2 = tkinter.Tk()
+ root3 = tkinter.Tk()
+ self.assertIs(tkinter._default_root, root)
+ root2.destroy()
+ self.assertIs(tkinter._default_root, root)
+ root.destroy()
+ self.assertIsNone(tkinter._default_root)
+ root3.destroy()
+ self.assertIsNone(tkinter._default_root)
+
+ def test_no_default_root(self):
+ self.assertIs(tkinter._support_default_root, True)
+ self.assertIsNone(tkinter._default_root)
+ root = tkinter.Tk()
+ self.assertIs(tkinter._default_root, root)
+ tkinter.NoDefaultRoot()
+ self.assertIs(tkinter._support_default_root, False)
+ self.assertFalse(hasattr(tkinter, '_default_root'))
+ # repeated call is no-op
+ tkinter.NoDefaultRoot()
+ self.assertIs(tkinter._support_default_root, False)
+ self.assertFalse(hasattr(tkinter, '_default_root'))
+ root.destroy()
+ self.assertIs(tkinter._support_default_root, False)
+ self.assertFalse(hasattr(tkinter, '_default_root'))
+ root = tkinter.Tk()
+ self.assertIs(tkinter._support_default_root, False)
+ self.assertFalse(hasattr(tkinter, '_default_root'))
+ root.destroy()
+
+ def test_getboolean(self):
+ self.assertRaises(RuntimeError, tkinter.getboolean, '1')
+ root = tkinter.Tk()
+ self.assertIs(tkinter.getboolean('1'), True)
+ self.assertRaises(ValueError, tkinter.getboolean, 'yea')
+ root.destroy()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, tkinter.getboolean, '1')
+
+ def test_mainloop(self):
+ self.assertRaises(RuntimeError, tkinter.mainloop)
+ root = tkinter.Tk()
+ root.after_idle(root.quit)
+ tkinter.mainloop()
+ root.destroy()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, tkinter.mainloop)
+
+
+tests_gui = (MiscTest, DefaultRootTest)
if __name__ == "__main__":
support.run_unittest(*tests_gui)
diff --git a/Lib/tkinter/test/test_tkinter/test_simpledialog.py b/Lib/tkinter/test/test_tkinter/test_simpledialog.py
new file mode 100644
index 00000000000..91191725880
--- /dev/null
+++ b/Lib/tkinter/test/test_tkinter/test_simpledialog.py
@@ -0,0 +1,25 @@
+import unittest
+import tkinter
+from test.support import requires, run_unittest, swap_attr
+from tkinter.test.support import AbstractDefaultRootTest
+from tkinter.simpledialog import Dialog, askinteger
+
+requires('gui')
+
+
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+ def test_askinteger(self):
+ self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
+ root = tkinter.Tk()
+ with swap_attr(Dialog, 'wait_window', lambda self, w: w.destroy()):
+ askinteger("Go To Line", "Line number")
+ root.destroy()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
+
+
+tests_gui = (DefaultRootTest,)
+
+if __name__ == "__main__":
+ run_unittest(*tests_gui)
diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py
index 08b7dedcaf9..63d7c21059e 100644
--- a/Lib/tkinter/test/test_tkinter/test_variables.py
+++ b/Lib/tkinter/test/test_tkinter/test_variables.py
@@ -1,8 +1,10 @@
import unittest
import gc
+import tkinter
from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
TclError)
from test.support import ALWAYS_EQ
+from tkinter.test.support import AbstractDefaultRootTest
class Var(Variable):
@@ -308,8 +310,21 @@ class TestBooleanVar(TestBase):
v.get()
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+ def test_variable(self):
+ self.assertRaises(RuntimeError, Variable)
+ root = tkinter.Tk()
+ v = Variable()
+ v.set("value")
+ self.assertEqual(v.get(), "value")
+ root.destroy()
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, Variable)
+
+
tests_gui = (TestVariable, TestStringVar, TestIntVar,
- TestDoubleVar, TestBooleanVar)
+ TestDoubleVar, TestBooleanVar, DefaultRootTest)
if __name__ == "__main__":
diff --git a/Lib/tkinter/test/test_tkinter/test_widgets.py b/Lib/tkinter/test/test_tkinter/test_widgets.py
index 4b9b6ebdda0..54eddbf8216 100644
--- a/Lib/tkinter/test/test_tkinter/test_widgets.py
+++ b/Lib/tkinter/test/test_tkinter/test_widgets.py
@@ -5,7 +5,8 @@ import os
from test.support import requires
from tkinter.test.support import (tcl_version, requires_tcl,
- get_tk_patchlevel, widget_eq)
+ get_tk_patchlevel, widget_eq,
+ AbstractDefaultRootTest)
from tkinter.test.widget_tests import (
add_standard_options, noconv, pixels_round,
AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests,
@@ -1295,12 +1296,21 @@ class MessageTest(AbstractWidgetTest, unittest.TestCase):
self.checkIntegerParam(widget, 'aspect', 250, 0, -300)
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+ def test_frame(self):
+ self._test_widget(tkinter.Frame)
+
+ def test_label(self):
+ self._test_widget(tkinter.Label)
+
+
tests_gui = (
ButtonTest, CanvasTest, CheckbuttonTest, EntryTest,
FrameTest, LabelFrameTest,LabelTest, ListboxTest,
MenubuttonTest, MenuTest, MessageTest, OptionMenuTest,
PanedWindowTest, RadiobuttonTest, ScaleTest, ScrollbarTest,
- SpinboxTest, TextTest, ToplevelTest,
+ SpinboxTest, TextTest, ToplevelTest, DefaultRootTest,
)
if __name__ == '__main__':
diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py
index 6937ba1ca9b..1a70e0befe6 100644
--- a/Lib/tkinter/test/test_ttk/test_extensions.py
+++ b/Lib/tkinter/test/test_ttk/test_extensions.py
@@ -2,8 +2,8 @@ import sys
import unittest
import tkinter
from tkinter import ttk
-from test.support import requires, run_unittest, swap_attr
-from tkinter.test.support import AbstractTkTest, destroy_default_root
+from test.support import requires, run_unittest
+from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest
requires('gui')
@@ -46,20 +46,6 @@ class LabeledScaleTest(AbstractTkTest, unittest.TestCase):
if hasattr(sys, 'last_type'):
self.assertNotEqual(sys.last_type, tkinter.TclError)
-
- def test_initialization_no_master(self):
- # no master passing
- with swap_attr(tkinter, '_default_root', None), \
- swap_attr(tkinter, '_support_default_root', True):
- try:
- x = ttk.LabeledScale()
- self.assertIsNotNone(tkinter._default_root)
- self.assertEqual(x.master, tkinter._default_root)
- self.assertEqual(x.tk, tkinter._default_root.tk)
- x.destroy()
- finally:
- destroy_default_root()
-
def test_initialization(self):
# master passing
master = tkinter.Frame(self.root)
@@ -311,7 +297,13 @@ class OptionMenuTest(AbstractTkTest, unittest.TestCase):
optmenu2.destroy()
-tests_gui = (LabeledScaleTest, OptionMenuTest)
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+ def test_labeledscale(self):
+ self._test_widget(ttk.LabeledScale)
+
+
+tests_gui = (LabeledScaleTest, OptionMenuTest, DefaultRootTest)
if __name__ == "__main__":
run_unittest(*tests_gui)
diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py
index 157ef0e8f87..de30e2476b4 100644
--- a/Lib/tkinter/test/test_ttk/test_widgets.py
+++ b/Lib/tkinter/test/test_ttk/test_widgets.py
@@ -6,7 +6,7 @@ import sys
from tkinter.test.test_ttk.test_functions import MockTclObj
from tkinter.test.support import (AbstractTkTest, tcl_version, get_tk_patchlevel,
- simulate_mouse_click)
+ simulate_mouse_click, AbstractDefaultRootTest)
from tkinter.test.widget_tests import (add_standard_options, noconv,
AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests,
setUpModule)
@@ -1860,12 +1860,22 @@ class SizegripTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return ttk.Sizegrip(self.root, **kwargs)
+
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+ def test_frame(self):
+ self._test_widget(ttk.Frame)
+
+ def test_label(self):
+ self._test_widget(ttk.Label)
+
+
tests_gui = (
ButtonTest, CheckbuttonTest, ComboboxTest, EntryTest,
FrameTest, LabelFrameTest, LabelTest, MenubuttonTest,
NotebookTest, PanedWindowTest, ProgressbarTest,
RadiobuttonTest, ScaleTest, ScrollbarTest, SeparatorTest,
- SizegripTest, SpinboxTest, TreeviewTest, WidgetTest,
+ SizegripTest, SpinboxTest, TreeviewTest, WidgetTest, DefaultRootTest,
)
if __name__ == "__main__":
diff --git a/Lib/tkinter/tix.py b/Lib/tkinter/tix.py
index ac545502e45..ef1e7406bc1 100644
--- a/Lib/tkinter/tix.py
+++ b/Lib/tkinter/tix.py
@@ -387,9 +387,7 @@ class TixWidget(tkinter.Widget):
# These are missing from Tkinter
def image_create(self, imgtype, cnf={}, master=None, **kw):
if not master:
- master = tkinter._default_root
- if not master:
- raise RuntimeError('Too early to create image')
+ master = self
if kw and cnf: cnf = _cnfmerge((cnf, kw))
elif kw: cnf = kw
options = ()
@@ -475,10 +473,7 @@ class DisplayStyle:
elif 'refwindow' in cnf:
master = cnf['refwindow']
else:
- master = tkinter._default_root
- if not master:
- raise RuntimeError("Too early to create display style: "
- "no root window")
+ master = tkinter._get_default_root('create display style')
self.tk = master.tk
self.stylename = self.tk.call('tixDisplayStyle', itemtype,
*self._options(cnf,kw) )
diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py
index f3a2f7660f3..ab7aeb15e8f 100644
--- a/Lib/tkinter/ttk.py
+++ b/Lib/tkinter/ttk.py
@@ -349,12 +349,7 @@ def setup_master(master=None):
If it is not allowed to use the default root and master is None,
RuntimeError is raised."""
if master is None:
- if tkinter._support_default_root:
- master = tkinter._default_root or tkinter.Tk()
- else:
- raise RuntimeError(
- "No master specified and tkinter is "
- "configured to not support default root")
+ master = tkinter._get_default_root()
return master
diff --git a/Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst b/Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst
new file mode 100644
index 00000000000..4b4a520931f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-12-15-17-51-27.bpo-42630.jf4jBl.rst
@@ -0,0 +1,4 @@
+:mod:`tkinter` functions and constructors which need a default root window
+raise now :exc:`RuntimeError` with descriptive message instead of obscure
+:exc:`AttributeError` or :exc:`NameError` if it is not created yet or cannot
+be created automatically.
diff --git a/Tools/pynche/PyncheWidget.py b/Tools/pynche/PyncheWidget.py
index ef12198a218..ea456e577e1 100644
--- a/Tools/pynche/PyncheWidget.py
+++ b/Tools/pynche/PyncheWidget.py
@@ -36,15 +36,11 @@ class PyncheWidget:
else:
# Is there already a default root for Tk, say because we're
# running under Guido's IDE? :-) Two conditions say no, either the
- # import fails or _default_root is None.
- tkroot = None
- try:
- from Tkinter import _default_root
- tkroot = self.__tkroot = _default_root
- except ImportError:
- pass
+ # _default_root is None or it is unset.
+ tkroot = getattr(tkinter, '_default_root', None)
if not tkroot:
- tkroot = self.__tkroot = Tk(className='Pynche')
+ tkroot = Tk(className='Pynche')
+ self.__tkroot = tkroot
# but this isn't our top level widget, so make it invisible
tkroot.withdraw()
# create the menubar