mirror of
https://github.com/python/cpython.git
synced 2025-07-23 11:15:24 +00:00
bpo-42630: Improve error reporting in Tkinter for absent default root (GH-23781)
* Tkinter functions and constructors which need a default root window raise now RuntimeError with descriptive message instead of obscure AttributeError or NameError if it is not created yet or cannot be created automatically. * Add tests for all functions which use default root window. * Fix import in the pynche script.
This commit is contained in:
parent
1e27b57dbc
commit
3d569fd6dc
19 changed files with 315 additions and 87 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
25
Lib/tkinter/test/test_tkinter/test_simpledialog.py
Normal file
25
Lib/tkinter/test/test_tkinter/test_simpledialog.py
Normal file
|
@ -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)
|
|
@ -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__":
|
||||
|
|
|
@ -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__':
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue