From c1fb12e5afa09aca3134a9bc0116c31dbcccc5e9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 22 Jun 2022 22:23:37 +0200 Subject: gh-54781: Move Lib/tkinter/test/test_ttk/ to Lib/test/test_ttk/ (#94070) * Move Lib/tkinter/test/test_tkinter/ to Lib/test/test_tkinter/. * Move Lib/tkinter/test/test_ttk/ to Lib/test/test_ttk/. * Add Lib/test/test_ttk/__init__.py based on test_ttk_guionly.py. * Add Lib/test/test_tkinter/__init__.py * Remove old Lib/test/test_tk.py. * Remove old Lib/test/test_ttk_guionly.py. * Add __main__ sub-modules. * Update imports and update references to rename files. --- Lib/test/test_tk.py | 20 - Lib/test/test_tkinter/README | 14 + Lib/test/test_tkinter/__init__.py | 18 + Lib/test/test_tkinter/__main__.py | 4 + Lib/test/test_tkinter/support.py | 135 ++ Lib/test/test_tkinter/test_colorchooser.py | 68 + Lib/test/test_tkinter/test_font.py | 163 ++ Lib/test/test_tkinter/test_geometry_managers.py | 899 ++++++++++ Lib/test/test_tkinter/test_images.py | 380 ++++ Lib/test/test_tkinter/test_loadtk.py | 46 + Lib/test/test_tkinter/test_messagebox.py | 36 + Lib/test/test_tkinter/test_misc.py | 430 +++++ Lib/test/test_tkinter/test_simpledialog.py | 35 + Lib/test/test_tkinter/test_text.py | 45 + Lib/test/test_tkinter/test_variables.py | 342 ++++ Lib/test/test_tkinter/test_widgets.py | 1292 ++++++++++++++ Lib/test/test_tkinter/widget_tests.py | 519 ++++++ Lib/test/test_ttk/__init__.py | 39 + Lib/test/test_ttk/__main__.py | 4 + Lib/test/test_ttk/test_extensions.py | 328 ++++ Lib/test/test_ttk/test_style.py | 181 ++ Lib/test/test_ttk/test_widgets.py | 1858 ++++++++++++++++++++ Lib/test/test_ttk_guionly.py | 40 - Lib/tkinter/test/README | 14 - Lib/tkinter/test/__init__.py | 0 Lib/tkinter/test/support.py | 135 -- Lib/tkinter/test/test_tkinter/__init__.py | 0 Lib/tkinter/test/test_tkinter/test_colorchooser.py | 68 - Lib/tkinter/test/test_tkinter/test_font.py | 163 -- .../test/test_tkinter/test_geometry_managers.py | 899 ---------- Lib/tkinter/test/test_tkinter/test_images.py | 380 ---- Lib/tkinter/test/test_tkinter/test_loadtk.py | 46 - Lib/tkinter/test/test_tkinter/test_messagebox.py | 36 - Lib/tkinter/test/test_tkinter/test_misc.py | 430 ----- Lib/tkinter/test/test_tkinter/test_simpledialog.py | 35 - Lib/tkinter/test/test_tkinter/test_text.py | 45 - Lib/tkinter/test/test_tkinter/test_variables.py | 342 ---- Lib/tkinter/test/test_tkinter/test_widgets.py | 1292 -------------- Lib/tkinter/test/test_ttk/__init__.py | 0 Lib/tkinter/test/test_ttk/test_extensions.py | 328 ---- Lib/tkinter/test/test_ttk/test_style.py | 181 -- Lib/tkinter/test/test_ttk/test_widgets.py | 1858 -------------------- Lib/tkinter/test/widget_tests.py | 519 ------ Makefile.pre.in | 6 +- .../2022-06-21-17-37-46.gh-issue-54781.BjVAVg.rst | 2 + PCbuild/lib.pyproj | 93 +- Tools/wasm/wasm_assets.py | 13 +- 47 files changed, 6886 insertions(+), 6895 deletions(-) delete mode 100644 Lib/test/test_tk.py create mode 100644 Lib/test/test_tkinter/README create mode 100644 Lib/test/test_tkinter/__init__.py create mode 100644 Lib/test/test_tkinter/__main__.py create mode 100644 Lib/test/test_tkinter/support.py create mode 100644 Lib/test/test_tkinter/test_colorchooser.py create mode 100644 Lib/test/test_tkinter/test_font.py create mode 100644 Lib/test/test_tkinter/test_geometry_managers.py create mode 100644 Lib/test/test_tkinter/test_images.py create mode 100644 Lib/test/test_tkinter/test_loadtk.py create mode 100644 Lib/test/test_tkinter/test_messagebox.py create mode 100644 Lib/test/test_tkinter/test_misc.py create mode 100644 Lib/test/test_tkinter/test_simpledialog.py create mode 100644 Lib/test/test_tkinter/test_text.py create mode 100644 Lib/test/test_tkinter/test_variables.py create mode 100644 Lib/test/test_tkinter/test_widgets.py create mode 100644 Lib/test/test_tkinter/widget_tests.py create mode 100644 Lib/test/test_ttk/__init__.py create mode 100644 Lib/test/test_ttk/__main__.py create mode 100644 Lib/test/test_ttk/test_extensions.py create mode 100644 Lib/test/test_ttk/test_style.py create mode 100644 Lib/test/test_ttk/test_widgets.py delete mode 100644 Lib/test/test_ttk_guionly.py delete mode 100644 Lib/tkinter/test/README delete mode 100644 Lib/tkinter/test/__init__.py delete mode 100644 Lib/tkinter/test/support.py delete mode 100644 Lib/tkinter/test/test_tkinter/__init__.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_colorchooser.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_font.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_geometry_managers.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_images.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_loadtk.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_messagebox.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_misc.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_simpledialog.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_text.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_variables.py delete mode 100644 Lib/tkinter/test/test_tkinter/test_widgets.py delete mode 100644 Lib/tkinter/test/test_ttk/__init__.py delete mode 100644 Lib/tkinter/test/test_ttk/test_extensions.py delete mode 100644 Lib/tkinter/test/test_ttk/test_style.py delete mode 100644 Lib/tkinter/test/test_ttk/test_widgets.py delete mode 100644 Lib/tkinter/test/widget_tests.py create mode 100644 Misc/NEWS.d/next/Tests/2022-06-21-17-37-46.gh-issue-54781.BjVAVg.rst diff --git a/Lib/test/test_tk.py b/Lib/test/test_tk.py deleted file mode 100644 index 8f90cba..0000000 --- a/Lib/test/test_tk.py +++ /dev/null @@ -1,20 +0,0 @@ -import unittest -from test import support -from test.support import import_helper -from test.support import check_sanitizer - -if check_sanitizer(address=True, memory=True): - raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds") - -# Skip test if _tkinter wasn't built. -import_helper.import_module('_tkinter') - -# Skip test if tk cannot be initialized. -support.requires('gui') - -def load_tests(loader, tests, pattern): - return loader.discover('tkinter.test.test_tkinter') - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_tkinter/README b/Lib/test/test_tkinter/README new file mode 100644 index 0000000..79cd16c --- /dev/null +++ b/Lib/test/test_tkinter/README @@ -0,0 +1,14 @@ +Writing new tests +================= + +Precaution +---------- + + New tests should always use only one Tk window at once, like all the + current tests do. This means that you have to destroy the current window + before creating another one, and clean up after the test. The motivation + behind this is that some tests may depend on having its window focused + while it is running to work properly, and it may be hard to force focus + on your window across platforms (right now only test_traversal at + test_ttk.test_widgets.NotebookTest depends on this). + diff --git a/Lib/test/test_tkinter/__init__.py b/Lib/test/test_tkinter/__init__.py new file mode 100644 index 0000000..edcb449 --- /dev/null +++ b/Lib/test/test_tkinter/__init__.py @@ -0,0 +1,18 @@ +import os.path +import unittest +from test import support +from test.support import import_helper + + +if support.check_sanitizer(address=True, memory=True): + raise unittest.SkipTest("Tests involving libX11 can SEGFAULT on ASAN/MSAN builds") + +# Skip test if _tkinter wasn't built. +import_helper.import_module('_tkinter') + +# Skip test if tk cannot be initialized. +support.requires('gui') + + +def load_tests(*args): + return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tkinter/__main__.py b/Lib/test/test_tkinter/__main__.py new file mode 100644 index 0000000..40a23a2 --- /dev/null +++ b/Lib/test/test_tkinter/__main__.py @@ -0,0 +1,4 @@ +from . import load_tests +import unittest + +unittest.main() diff --git a/Lib/test/test_tkinter/support.py b/Lib/test/test_tkinter/support.py new file mode 100644 index 0000000..9154eba --- /dev/null +++ b/Lib/test/test_tkinter/support.py @@ -0,0 +1,135 @@ +import functools +import tkinter +import unittest + +class AbstractTkTest: + + @classmethod + def setUpClass(cls): + cls._old_support_default_root = tkinter._support_default_root + destroy_default_root() + tkinter.NoDefaultRoot() + cls.root = tkinter.Tk() + cls.wantobjects = cls.root.wantobjects() + # De-maximize main window. + # Some window managers can maximize new windows. + cls.root.wm_state('normal') + try: + cls.root.wm_attributes('-zoomed', False) + except tkinter.TclError: + pass + + @classmethod + def tearDownClass(cls): + cls.root.update_idletasks() + cls.root.destroy() + del cls.root + tkinter._default_root = None + tkinter._support_default_root = cls._old_support_default_root + + def setUp(self): + self.root.deiconify() + + def tearDown(self): + for w in self.root.winfo_children(): + 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() + tkinter._default_root.destroy() + tkinter._default_root = None + +def simulate_mouse_click(widget, x, y): + """Generate proper events to click at the x, y position (tries to act + like an X server).""" + widget.event_generate('', x=0, y=0) + widget.event_generate('', x=x, y=y) + widget.event_generate('', x=x, y=y) + widget.event_generate('', x=x, y=y) + + +import _tkinter +tcl_version = tuple(map(int, _tkinter.TCL_VERSION.split('.'))) + +def requires_tcl(*version): + if len(version) <= 2: + return unittest.skipUnless(tcl_version >= version, + 'requires Tcl version >= ' + '.'.join(map(str, version))) + + def deco(test): + @functools.wraps(test) + def newtest(self): + if get_tk_patchlevel() < version: + self.skipTest('requires Tcl version >= ' + + '.'.join(map(str, version))) + test(self) + return newtest + return deco + +_tk_patchlevel = None +def get_tk_patchlevel(): + global _tk_patchlevel + if _tk_patchlevel is None: + tcl = tkinter.Tcl() + _tk_patchlevel = tcl.info_patchlevel() + return _tk_patchlevel + +units = { + 'c': 72 / 2.54, # centimeters + 'i': 72, # inches + 'm': 72 / 25.4, # millimeters + 'p': 1, # points +} + +def pixels_conv(value): + return float(value[:-1]) * units[value[-1:]] + +def tcl_obj_eq(actual, expected): + if actual == expected: + return True + if isinstance(actual, _tkinter.Tcl_Obj): + if isinstance(expected, str): + return str(actual) == expected + if isinstance(actual, tuple): + if isinstance(expected, tuple): + return (len(actual) == len(expected) and + all(tcl_obj_eq(act, exp) + for act, exp in zip(actual, expected))) + return False + +def widget_eq(actual, expected): + if actual == expected: + return True + if isinstance(actual, (str, tkinter.Widget)): + if isinstance(expected, (str, tkinter.Widget)): + return str(actual) == str(expected) + return False diff --git a/Lib/test/test_tkinter/test_colorchooser.py b/Lib/test/test_tkinter/test_colorchooser.py new file mode 100644 index 0000000..9bba213 --- /dev/null +++ b/Lib/test/test_tkinter/test_colorchooser.py @@ -0,0 +1,68 @@ +import unittest +import tkinter +from test.support import requires, swap_attr +from test.test_tkinter.support import AbstractDefaultRootTest, AbstractTkTest +from tkinter import colorchooser +from tkinter.colorchooser import askcolor +from tkinter.commondialog import Dialog + +requires('gui') + + +class ChooserTest(AbstractTkTest, unittest.TestCase): + + @classmethod + def setUpClass(cls): + AbstractTkTest.setUpClass.__func__(cls) + cls.cc = colorchooser.Chooser(initialcolor='dark blue slate') + + def test_fixoptions(self): + cc = self.cc + cc._fixoptions() + self.assertEqual(cc.options['initialcolor'], 'dark blue slate') + + cc.options['initialcolor'] = '#D2D269691E1E' + cc._fixoptions() + self.assertEqual(cc.options['initialcolor'], '#D2D269691E1E') + + cc.options['initialcolor'] = (210, 105, 30) + cc._fixoptions() + self.assertEqual(cc.options['initialcolor'], '#d2691e') + + def test_fixresult(self): + cc = self.cc + self.assertEqual(cc._fixresult(self.root, ()), (None, None)) + self.assertEqual(cc._fixresult(self.root, ''), (None, None)) + self.assertEqual(cc._fixresult(self.root, 'chocolate'), + ((210, 105, 30), 'chocolate')) + self.assertEqual(cc._fixresult(self.root, '#4a3c8c'), + ((74, 60, 140), '#4a3c8c')) + + +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_askcolor(self): + def test_callback(dialog, master): + nonlocal ismapped + master.update() + ismapped = master.winfo_ismapped() + raise ZeroDivisionError + + with swap_attr(Dialog, '_test_callback', test_callback): + ismapped = None + self.assertRaises(ZeroDivisionError, askcolor) + #askcolor() + self.assertEqual(ismapped, False) + + root = tkinter.Tk() + ismapped = None + self.assertRaises(ZeroDivisionError, askcolor) + self.assertEqual(ismapped, True) + root.destroy() + + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, askcolor) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_tkinter/test_font.py b/Lib/test/test_tkinter/test_font.py new file mode 100644 index 0000000..563707d --- /dev/null +++ b/Lib/test/test_tkinter/test_font.py @@ -0,0 +1,163 @@ +import unittest +import tkinter +from tkinter import font +from test.support import requires, gc_collect, ALWAYS_EQ +from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest + +requires('gui') + +fontname = "TkDefaultFont" + +class FontTest(AbstractTkTest, unittest.TestCase): + + @classmethod + def setUpClass(cls): + AbstractTkTest.setUpClass.__func__(cls) + try: + cls.font = font.Font(root=cls.root, name=fontname, exists=True) + except tkinter.TclError: + cls.font = font.Font(root=cls.root, name=fontname, exists=False) + + def test_configure(self): + options = self.font.configure() + self.assertGreaterEqual(set(options), + {'family', 'size', 'weight', 'slant', 'underline', 'overstrike'}) + for key in options: + self.assertEqual(self.font.cget(key), options[key]) + self.assertEqual(self.font[key], options[key]) + for key in 'family', 'weight', 'slant': + self.assertIsInstance(options[key], str) + self.assertIsInstance(self.font.cget(key), str) + self.assertIsInstance(self.font[key], str) + sizetype = int if self.wantobjects else str + for key in 'size', 'underline', 'overstrike': + self.assertIsInstance(options[key], sizetype) + self.assertIsInstance(self.font.cget(key), sizetype) + self.assertIsInstance(self.font[key], sizetype) + + def test_unicode_family(self): + family = 'MS \u30b4\u30b7\u30c3\u30af' + try: + f = font.Font(root=self.root, family=family, exists=True) + except tkinter.TclError: + f = font.Font(root=self.root, family=family, exists=False) + self.assertEqual(f.cget('family'), family) + del f + gc_collect() + + def test_actual(self): + options = self.font.actual() + self.assertGreaterEqual(set(options), + {'family', 'size', 'weight', 'slant', 'underline', 'overstrike'}) + for key in options: + self.assertEqual(self.font.actual(key), options[key]) + for key in 'family', 'weight', 'slant': + self.assertIsInstance(options[key], str) + self.assertIsInstance(self.font.actual(key), str) + sizetype = int if self.wantobjects else str + for key in 'size', 'underline', 'overstrike': + self.assertIsInstance(options[key], sizetype) + self.assertIsInstance(self.font.actual(key), sizetype) + + def test_name(self): + self.assertEqual(self.font.name, fontname) + self.assertEqual(str(self.font), fontname) + + def test_equality(self): + font1 = font.Font(root=self.root, name=fontname, exists=True) + font2 = font.Font(root=self.root, name=fontname, exists=True) + self.assertIsNot(font1, font2) + self.assertEqual(font1, font2) + self.assertNotEqual(font1, font1.copy()) + + self.assertNotEqual(font1, 0) + self.assertEqual(font1, ALWAYS_EQ) + + root2 = tkinter.Tk() + self.addCleanup(root2.destroy) + font3 = font.Font(root=root2, name=fontname, exists=True) + self.assertEqual(str(font1), str(font3)) + self.assertNotEqual(font1, font3) + + def test_measure(self): + self.assertIsInstance(self.font.measure('abc'), int) + + def test_metrics(self): + metrics = self.font.metrics() + self.assertGreaterEqual(set(metrics), + {'ascent', 'descent', 'linespace', 'fixed'}) + for key in metrics: + self.assertEqual(self.font.metrics(key), metrics[key]) + self.assertIsInstance(metrics[key], int) + self.assertIsInstance(self.font.metrics(key), int) + + def test_families(self): + families = font.families(self.root) + self.assertIsInstance(families, tuple) + self.assertTrue(families) + for family in families: + self.assertIsInstance(family, str) + self.assertTrue(family) + + def test_names(self): + names = font.names(self.root) + self.assertIsInstance(names, tuple) + self.assertTrue(names) + for name in names: + self.assertIsInstance(name, str) + self.assertTrue(name) + self.assertIn(fontname, names) + + def test_nametofont(self): + testfont = font.nametofont(fontname, root=self.root) + self.assertIsInstance(testfont, font.Font) + self.assertEqual(testfont.name, fontname) + + def test_repr(self): + self.assertEqual( + repr(self.font), f'' + ) + + +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) + + def test_nametofont(self): + self.assertRaises(RuntimeError, font.nametofont, fontname) + root = tkinter.Tk() + testfont = font.nametofont(fontname) + self.assertIsInstance(testfont, font.Font) + self.assertEqual(testfont.name, fontname) + root.destroy() + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, font.nametofont, fontname) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py new file mode 100644 index 0000000..3663048 --- /dev/null +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -0,0 +1,899 @@ +import unittest +import re +import tkinter +from tkinter import TclError +from test.support import requires + +from test.test_tkinter.support import pixels_conv +from test.test_tkinter.widget_tests import AbstractWidgetTest + +requires('gui') + + +class PackTest(AbstractWidgetTest, unittest.TestCase): + + test_keys = None + + def create2(self): + pack = tkinter.Toplevel(self.root, name='pack') + pack.wm_geometry('300x200+0+0') + pack.wm_minsize(1, 1) + a = tkinter.Frame(pack, name='a', width=20, height=40, bg='red') + b = tkinter.Frame(pack, name='b', width=50, height=30, bg='blue') + c = tkinter.Frame(pack, name='c', width=80, height=80, bg='green') + d = tkinter.Frame(pack, name='d', width=40, height=30, bg='yellow') + return pack, a, b, c, d + + def test_pack_configure_after(self): + pack, a, b, c, d = self.create2() + with self.assertRaisesRegex(TclError, 'window "%s" isn\'t packed' % b): + a.pack_configure(after=b) + with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'): + a.pack_configure(after='.foo') + a.pack_configure(side='top') + b.pack_configure(side='top') + c.pack_configure(side='top') + d.pack_configure(side='top') + self.assertEqual(pack.pack_slaves(), [a, b, c, d]) + a.pack_configure(after=b) + self.assertEqual(pack.pack_slaves(), [b, a, c, d]) + a.pack_configure(after=a) + self.assertEqual(pack.pack_slaves(), [b, a, c, d]) + + def test_pack_configure_anchor(self): + pack, a, b, c, d = self.create2() + def check(anchor, geom): + a.pack_configure(side='top', ipadx=5, padx=10, ipady=15, pady=20, + expand=True, anchor=anchor) + self.root.update() + self.assertEqual(a.winfo_geometry(), geom) + check('n', '30x70+135+20') + check('ne', '30x70+260+20') + check('e', '30x70+260+65') + check('se', '30x70+260+110') + check('s', '30x70+135+110') + check('sw', '30x70+10+110') + check('w', '30x70+10+65') + check('nw', '30x70+10+20') + check('center', '30x70+135+65') + + def test_pack_configure_before(self): + pack, a, b, c, d = self.create2() + with self.assertRaisesRegex(TclError, 'window "%s" isn\'t packed' % b): + a.pack_configure(before=b) + with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'): + a.pack_configure(before='.foo') + a.pack_configure(side='top') + b.pack_configure(side='top') + c.pack_configure(side='top') + d.pack_configure(side='top') + self.assertEqual(pack.pack_slaves(), [a, b, c, d]) + a.pack_configure(before=d) + self.assertEqual(pack.pack_slaves(), [b, c, a, d]) + a.pack_configure(before=a) + self.assertEqual(pack.pack_slaves(), [b, c, a, d]) + + def test_pack_configure_expand(self): + pack, a, b, c, d = self.create2() + def check(*geoms): + self.root.update() + self.assertEqual(a.winfo_geometry(), geoms[0]) + self.assertEqual(b.winfo_geometry(), geoms[1]) + self.assertEqual(c.winfo_geometry(), geoms[2]) + self.assertEqual(d.winfo_geometry(), geoms[3]) + a.pack_configure(side='left') + b.pack_configure(side='top') + c.pack_configure(side='right') + d.pack_configure(side='bottom') + check('20x40+0+80', '50x30+135+0', '80x80+220+75', '40x30+100+170') + a.pack_configure(side='left', expand='yes') + b.pack_configure(side='top', expand='on') + c.pack_configure(side='right', expand=True) + d.pack_configure(side='bottom', expand=1) + check('20x40+40+80', '50x30+175+35', '80x80+180+110', '40x30+100+135') + a.pack_configure(side='left', expand='yes', fill='both') + b.pack_configure(side='top', expand='on', fill='both') + c.pack_configure(side='right', expand=True, fill='both') + d.pack_configure(side='bottom', expand=1, fill='both') + check('100x200+0+0', '200x100+100+0', '160x100+140+100', '40x100+100+100') + + def test_pack_configure_in(self): + pack, a, b, c, d = self.create2() + a.pack_configure(side='top') + b.pack_configure(side='top') + c.pack_configure(side='top') + d.pack_configure(side='top') + a.pack_configure(in_=pack) + self.assertEqual(pack.pack_slaves(), [b, c, d, a]) + a.pack_configure(in_=c) + self.assertEqual(pack.pack_slaves(), [b, c, d]) + self.assertEqual(c.pack_slaves(), [a]) + with self.assertRaisesRegex(TclError, + 'can\'t pack %s inside itself' % (a,)): + a.pack_configure(in_=a) + with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'): + a.pack_configure(in_='.foo') + + def test_pack_configure_padx_ipadx_fill(self): + pack, a, b, c, d = self.create2() + def check(geom1, geom2, **kwargs): + a.pack_forget() + b.pack_forget() + a.pack_configure(**kwargs) + b.pack_configure(expand=True, fill='both') + self.root.update() + self.assertEqual(a.winfo_geometry(), geom1) + self.assertEqual(b.winfo_geometry(), geom2) + check('20x40+260+80', '240x200+0+0', side='right', padx=20) + check('20x40+250+80', '240x200+0+0', side='right', padx=(10, 30)) + check('60x40+240+80', '240x200+0+0', side='right', ipadx=20) + check('30x40+260+80', '250x200+0+0', side='right', ipadx=5, padx=10) + check('20x40+260+80', '240x200+0+0', side='right', padx=20, fill='x') + check('20x40+249+80', '240x200+0+0', + side='right', padx=(9, 31), fill='x') + check('60x40+240+80', '240x200+0+0', side='right', ipadx=20, fill='x') + check('30x40+260+80', '250x200+0+0', + side='right', ipadx=5, padx=10, fill='x') + check('30x40+255+80', '250x200+0+0', + side='right', ipadx=5, padx=(5, 15), fill='x') + check('20x40+140+0', '300x160+0+40', side='top', padx=20) + check('20x40+120+0', '300x160+0+40', side='top', padx=(0, 40)) + check('60x40+120+0', '300x160+0+40', side='top', ipadx=20) + check('30x40+135+0', '300x160+0+40', side='top', ipadx=5, padx=10) + check('30x40+130+0', '300x160+0+40', side='top', ipadx=5, padx=(5, 15)) + check('260x40+20+0', '300x160+0+40', side='top', padx=20, fill='x') + check('260x40+25+0', '300x160+0+40', + side='top', padx=(25, 15), fill='x') + check('300x40+0+0', '300x160+0+40', side='top', ipadx=20, fill='x') + check('280x40+10+0', '300x160+0+40', + side='top', ipadx=5, padx=10, fill='x') + check('280x40+5+0', '300x160+0+40', + side='top', ipadx=5, padx=(5, 15), fill='x') + a.pack_configure(padx='1c') + self.assertEqual(a.pack_info()['padx'], + self._str(pack.winfo_pixels('1c'))) + a.pack_configure(ipadx='1c') + self.assertEqual(a.pack_info()['ipadx'], + self._str(pack.winfo_pixels('1c'))) + + def test_pack_configure_pady_ipady_fill(self): + pack, a, b, c, d = self.create2() + def check(geom1, geom2, **kwargs): + a.pack_forget() + b.pack_forget() + a.pack_configure(**kwargs) + b.pack_configure(expand=True, fill='both') + self.root.update() + self.assertEqual(a.winfo_geometry(), geom1) + self.assertEqual(b.winfo_geometry(), geom2) + check('20x40+280+80', '280x200+0+0', side='right', pady=20) + check('20x40+280+70', '280x200+0+0', side='right', pady=(10, 30)) + check('20x80+280+60', '280x200+0+0', side='right', ipady=20) + check('20x50+280+75', '280x200+0+0', side='right', ipady=5, pady=10) + check('20x40+280+80', '280x200+0+0', side='right', pady=20, fill='x') + check('20x40+280+69', '280x200+0+0', + side='right', pady=(9, 31), fill='x') + check('20x80+280+60', '280x200+0+0', side='right', ipady=20, fill='x') + check('20x50+280+75', '280x200+0+0', + side='right', ipady=5, pady=10, fill='x') + check('20x50+280+70', '280x200+0+0', + side='right', ipady=5, pady=(5, 15), fill='x') + check('20x40+140+20', '300x120+0+80', side='top', pady=20) + check('20x40+140+0', '300x120+0+80', side='top', pady=(0, 40)) + check('20x80+140+0', '300x120+0+80', side='top', ipady=20) + check('20x50+140+10', '300x130+0+70', side='top', ipady=5, pady=10) + check('20x50+140+5', '300x130+0+70', side='top', ipady=5, pady=(5, 15)) + check('300x40+0+20', '300x120+0+80', side='top', pady=20, fill='x') + check('300x40+0+25', '300x120+0+80', + side='top', pady=(25, 15), fill='x') + check('300x80+0+0', '300x120+0+80', side='top', ipady=20, fill='x') + check('300x50+0+10', '300x130+0+70', + side='top', ipady=5, pady=10, fill='x') + check('300x50+0+5', '300x130+0+70', + side='top', ipady=5, pady=(5, 15), fill='x') + a.pack_configure(pady='1c') + self.assertEqual(a.pack_info()['pady'], + self._str(pack.winfo_pixels('1c'))) + a.pack_configure(ipady='1c') + self.assertEqual(a.pack_info()['ipady'], + self._str(pack.winfo_pixels('1c'))) + + def test_pack_configure_side(self): + pack, a, b, c, d = self.create2() + def check(side, geom1, geom2): + a.pack_configure(side=side) + self.assertEqual(a.pack_info()['side'], side) + b.pack_configure(expand=True, fill='both') + self.root.update() + self.assertEqual(a.winfo_geometry(), geom1) + self.assertEqual(b.winfo_geometry(), geom2) + check('top', '20x40+140+0', '300x160+0+40') + check('bottom', '20x40+140+160', '300x160+0+0') + check('left', '20x40+0+80', '280x200+20+0') + check('right', '20x40+280+80', '280x200+0+0') + + def test_pack_forget(self): + pack, a, b, c, d = self.create2() + a.pack_configure() + b.pack_configure() + c.pack_configure() + self.assertEqual(pack.pack_slaves(), [a, b, c]) + b.pack_forget() + self.assertEqual(pack.pack_slaves(), [a, c]) + b.pack_forget() + self.assertEqual(pack.pack_slaves(), [a, c]) + d.pack_forget() + + def test_pack_info(self): + pack, a, b, c, d = self.create2() + with self.assertRaisesRegex(TclError, 'window "%s" isn\'t packed' % a): + a.pack_info() + a.pack_configure() + b.pack_configure(side='right', in_=a, anchor='s', expand=True, fill='x', + ipadx=5, padx=10, ipady=2, pady=(5, 15)) + info = a.pack_info() + self.assertIsInstance(info, dict) + self.assertEqual(info['anchor'], 'center') + self.assertEqual(info['expand'], self._str(0)) + self.assertEqual(info['fill'], 'none') + self.assertEqual(info['in'], pack) + self.assertEqual(info['ipadx'], self._str(0)) + self.assertEqual(info['ipady'], self._str(0)) + self.assertEqual(info['padx'], self._str(0)) + self.assertEqual(info['pady'], self._str(0)) + self.assertEqual(info['side'], 'top') + info = b.pack_info() + self.assertIsInstance(info, dict) + self.assertEqual(info['anchor'], 's') + self.assertEqual(info['expand'], self._str(1)) + self.assertEqual(info['fill'], 'x') + self.assertEqual(info['in'], a) + self.assertEqual(info['ipadx'], self._str(5)) + self.assertEqual(info['ipady'], self._str(2)) + self.assertEqual(info['padx'], self._str(10)) + self.assertEqual(info['pady'], self._str((5, 15))) + self.assertEqual(info['side'], 'right') + + def test_pack_propagate(self): + pack, a, b, c, d = self.create2() + pack.configure(width=300, height=200) + a.pack_configure() + pack.pack_propagate(False) + self.root.update() + self.assertEqual(pack.winfo_reqwidth(), 300) + self.assertEqual(pack.winfo_reqheight(), 200) + pack.pack_propagate(True) + self.root.update() + self.assertEqual(pack.winfo_reqwidth(), 20) + self.assertEqual(pack.winfo_reqheight(), 40) + + def test_pack_slaves(self): + pack, a, b, c, d = self.create2() + self.assertEqual(pack.pack_slaves(), []) + a.pack_configure() + self.assertEqual(pack.pack_slaves(), [a]) + b.pack_configure() + self.assertEqual(pack.pack_slaves(), [a, b]) + + +class PlaceTest(AbstractWidgetTest, unittest.TestCase): + + test_keys = None + + def create2(self): + t = tkinter.Toplevel(self.root, width=300, height=200, bd=0) + t.wm_geometry('300x200+0+0') + f = tkinter.Frame(t, width=154, height=84, bd=2, relief='raised') + f.place_configure(x=48, y=38) + f2 = tkinter.Frame(t, width=30, height=60, bd=2, relief='raised') + self.root.update() + return t, f, f2 + + def test_place_configure_in(self): + t, f, f2 = self.create2() + self.assertEqual(f2.winfo_manager(), '') + with self.assertRaisesRegex(TclError, "can't place %s relative to " + "itself" % re.escape(str(f2))): + f2.place_configure(in_=f2) + self.assertEqual(f2.winfo_manager(), '') + with self.assertRaisesRegex(TclError, 'bad window path name'): + f2.place_configure(in_='spam') + f2.place_configure(in_=f) + self.assertEqual(f2.winfo_manager(), 'place') + + def test_place_configure_x(self): + t, f, f2 = self.create2() + f2.place_configure(in_=f) + self.assertEqual(f2.place_info()['x'], '0') + self.root.update() + self.assertEqual(f2.winfo_x(), 50) + f2.place_configure(x=100) + self.assertEqual(f2.place_info()['x'], '100') + self.root.update() + self.assertEqual(f2.winfo_x(), 150) + f2.place_configure(x=-10, relx=1) + self.assertEqual(f2.place_info()['x'], '-10') + self.root.update() + self.assertEqual(f2.winfo_x(), 190) + with self.assertRaisesRegex(TclError, 'bad screen distance "spam"'): + f2.place_configure(in_=f, x='spam') + + def test_place_configure_y(self): + t, f, f2 = self.create2() + f2.place_configure(in_=f) + self.assertEqual(f2.place_info()['y'], '0') + self.root.update() + self.assertEqual(f2.winfo_y(), 40) + f2.place_configure(y=50) + self.assertEqual(f2.place_info()['y'], '50') + self.root.update() + self.assertEqual(f2.winfo_y(), 90) + f2.place_configure(y=-10, rely=1) + self.assertEqual(f2.place_info()['y'], '-10') + self.root.update() + self.assertEqual(f2.winfo_y(), 110) + with self.assertRaisesRegex(TclError, 'bad screen distance "spam"'): + f2.place_configure(in_=f, y='spam') + + def test_place_configure_relx(self): + t, f, f2 = self.create2() + f2.place_configure(in_=f) + self.assertEqual(f2.place_info()['relx'], '0') + self.root.update() + self.assertEqual(f2.winfo_x(), 50) + f2.place_configure(relx=0.5) + self.assertEqual(f2.place_info()['relx'], '0.5') + self.root.update() + self.assertEqual(f2.winfo_x(), 125) + f2.place_configure(relx=1) + self.assertEqual(f2.place_info()['relx'], '1') + self.root.update() + self.assertEqual(f2.winfo_x(), 200) + with self.assertRaisesRegex(TclError, 'expected floating-point number ' + 'but got "spam"'): + f2.place_configure(in_=f, relx='spam') + + def test_place_configure_rely(self): + t, f, f2 = self.create2() + f2.place_configure(in_=f) + self.assertEqual(f2.place_info()['rely'], '0') + self.root.update() + self.assertEqual(f2.winfo_y(), 40) + f2.place_configure(rely=0.5) + self.assertEqual(f2.place_info()['rely'], '0.5') + self.root.update() + self.assertEqual(f2.winfo_y(), 80) + f2.place_configure(rely=1) + self.assertEqual(f2.place_info()['rely'], '1') + self.root.update() + self.assertEqual(f2.winfo_y(), 120) + with self.assertRaisesRegex(TclError, 'expected floating-point number ' + 'but got "spam"'): + f2.place_configure(in_=f, rely='spam') + + def test_place_configure_anchor(self): + f = tkinter.Frame(self.root) + with self.assertRaisesRegex(TclError, 'bad anchor "j"'): + f.place_configure(anchor='j') + with self.assertRaisesRegex(TclError, 'ambiguous anchor ""'): + f.place_configure(anchor='') + for value in 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center': + f.place_configure(anchor=value) + self.assertEqual(f.place_info()['anchor'], value) + + def test_place_configure_width(self): + t, f, f2 = self.create2() + f2.place_configure(in_=f, width=120) + self.root.update() + self.assertEqual(f2.winfo_width(), 120) + f2.place_configure(width='') + self.root.update() + self.assertEqual(f2.winfo_width(), 30) + with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'): + f2.place_configure(width='abcd') + + def test_place_configure_height(self): + t, f, f2 = self.create2() + f2.place_configure(in_=f, height=120) + self.root.update() + self.assertEqual(f2.winfo_height(), 120) + f2.place_configure(height='') + self.root.update() + self.assertEqual(f2.winfo_height(), 60) + with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'): + f2.place_configure(height='abcd') + + def test_place_configure_relwidth(self): + t, f, f2 = self.create2() + f2.place_configure(in_=f, relwidth=0.5) + self.root.update() + self.assertEqual(f2.winfo_width(), 75) + f2.place_configure(relwidth='') + self.root.update() + self.assertEqual(f2.winfo_width(), 30) + with self.assertRaisesRegex(TclError, 'expected floating-point number ' + 'but got "abcd"'): + f2.place_configure(relwidth='abcd') + + def test_place_configure_relheight(self): + t, f, f2 = self.create2() + f2.place_configure(in_=f, relheight=0.5) + self.root.update() + self.assertEqual(f2.winfo_height(), 40) + f2.place_configure(relheight='') + self.root.update() + self.assertEqual(f2.winfo_height(), 60) + with self.assertRaisesRegex(TclError, 'expected floating-point number ' + 'but got "abcd"'): + f2.place_configure(relheight='abcd') + + def test_place_configure_bordermode(self): + f = tkinter.Frame(self.root) + with self.assertRaisesRegex(TclError, 'bad bordermode "j"'): + f.place_configure(bordermode='j') + with self.assertRaisesRegex(TclError, 'ambiguous bordermode ""'): + f.place_configure(bordermode='') + for value in 'inside', 'outside', 'ignore': + f.place_configure(bordermode=value) + self.assertEqual(f.place_info()['bordermode'], value) + + def test_place_forget(self): + foo = tkinter.Frame(self.root) + foo.place_configure(width=50, height=50) + self.root.update() + foo.place_forget() + self.root.update() + self.assertFalse(foo.winfo_ismapped()) + with self.assertRaises(TypeError): + foo.place_forget(0) + + def test_place_info(self): + t, f, f2 = self.create2() + f2.place_configure(in_=f, x=1, y=2, width=3, height=4, + relx=0.1, rely=0.2, relwidth=0.3, relheight=0.4, + anchor='se', bordermode='outside') + info = f2.place_info() + self.assertIsInstance(info, dict) + self.assertEqual(info['x'], '1') + self.assertEqual(info['y'], '2') + self.assertEqual(info['width'], '3') + self.assertEqual(info['height'], '4') + self.assertEqual(info['relx'], '0.1') + self.assertEqual(info['rely'], '0.2') + self.assertEqual(info['relwidth'], '0.3') + self.assertEqual(info['relheight'], '0.4') + self.assertEqual(info['anchor'], 'se') + self.assertEqual(info['bordermode'], 'outside') + self.assertEqual(info['x'], '1') + self.assertEqual(info['x'], '1') + with self.assertRaises(TypeError): + f2.place_info(0) + + def test_place_slaves(self): + foo = tkinter.Frame(self.root) + bar = tkinter.Frame(self.root) + self.assertEqual(foo.place_slaves(), []) + bar.place_configure(in_=foo) + self.assertEqual(foo.place_slaves(), [bar]) + with self.assertRaises(TypeError): + foo.place_slaves(0) + + +class GridTest(AbstractWidgetTest, unittest.TestCase): + + test_keys = None + + def tearDown(self): + cols, rows = self.root.grid_size() + for i in range(cols + 1): + self.root.grid_columnconfigure(i, weight=0, minsize=0, pad=0, uniform='') + for i in range(rows + 1): + self.root.grid_rowconfigure(i, weight=0, minsize=0, pad=0, uniform='') + self.root.grid_propagate(1) + self.root.grid_anchor('nw') + super().tearDown() + + def test_grid_configure(self): + b = tkinter.Button(self.root) + self.assertEqual(b.grid_info(), {}) + b.grid_configure() + self.assertEqual(b.grid_info()['in'], self.root) + self.assertEqual(b.grid_info()['column'], self._str(0)) + self.assertEqual(b.grid_info()['row'], self._str(0)) + b.grid_configure({'column': 1}, row=2) + self.assertEqual(b.grid_info()['column'], self._str(1)) + self.assertEqual(b.grid_info()['row'], self._str(2)) + + def test_grid_configure_column(self): + b = tkinter.Button(self.root) + with self.assertRaisesRegex(TclError, 'bad column value "-1": ' + 'must be a non-negative integer'): + b.grid_configure(column=-1) + b.grid_configure(column=2) + self.assertEqual(b.grid_info()['column'], self._str(2)) + + def test_grid_configure_columnspan(self): + b = tkinter.Button(self.root) + with self.assertRaisesRegex(TclError, 'bad columnspan value "0": ' + 'must be a positive integer'): + b.grid_configure(columnspan=0) + b.grid_configure(columnspan=2) + self.assertEqual(b.grid_info()['columnspan'], self._str(2)) + + def test_grid_configure_in(self): + f = tkinter.Frame(self.root) + b = tkinter.Button(self.root) + self.assertEqual(b.grid_info(), {}) + b.grid_configure() + self.assertEqual(b.grid_info()['in'], self.root) + b.grid_configure(in_=f) + self.assertEqual(b.grid_info()['in'], f) + b.grid_configure({'in': self.root}) + self.assertEqual(b.grid_info()['in'], self.root) + + def test_grid_configure_ipadx(self): + b = tkinter.Button(self.root) + with self.assertRaisesRegex(TclError, 'bad ipadx value "-1": ' + 'must be positive screen distance'): + b.grid_configure(ipadx=-1) + b.grid_configure(ipadx=1) + self.assertEqual(b.grid_info()['ipadx'], self._str(1)) + b.grid_configure(ipadx='.5c') + self.assertEqual(b.grid_info()['ipadx'], + self._str(round(pixels_conv('.5c') * self.scaling))) + + def test_grid_configure_ipady(self): + b = tkinter.Button(self.root) + with self.assertRaisesRegex(TclError, 'bad ipady value "-1": ' + 'must be positive screen distance'): + b.grid_configure(ipady=-1) + b.grid_configure(ipady=1) + self.assertEqual(b.grid_info()['ipady'], self._str(1)) + b.grid_configure(ipady='.5c') + self.assertEqual(b.grid_info()['ipady'], + self._str(round(pixels_conv('.5c') * self.scaling))) + + def test_grid_configure_padx(self): + b = tkinter.Button(self.root) + with self.assertRaisesRegex(TclError, 'bad pad value "-1": ' + 'must be positive screen distance'): + b.grid_configure(padx=-1) + b.grid_configure(padx=1) + self.assertEqual(b.grid_info()['padx'], self._str(1)) + b.grid_configure(padx=(10, 5)) + self.assertEqual(b.grid_info()['padx'], self._str((10, 5))) + b.grid_configure(padx='.5c') + self.assertEqual(b.grid_info()['padx'], + self._str(round(pixels_conv('.5c') * self.scaling))) + + def test_grid_configure_pady(self): + b = tkinter.Button(self.root) + with self.assertRaisesRegex(TclError, 'bad pad value "-1": ' + 'must be positive screen distance'): + b.grid_configure(pady=-1) + b.grid_configure(pady=1) + self.assertEqual(b.grid_info()['pady'], self._str(1)) + b.grid_configure(pady=(10, 5)) + self.assertEqual(b.grid_info()['pady'], self._str((10, 5))) + b.grid_configure(pady='.5c') + self.assertEqual(b.grid_info()['pady'], + self._str(round(pixels_conv('.5c') * self.scaling))) + + def test_grid_configure_row(self): + b = tkinter.Button(self.root) + with self.assertRaisesRegex(TclError, 'bad (row|grid) value "-1": ' + 'must be a non-negative integer'): + b.grid_configure(row=-1) + b.grid_configure(row=2) + self.assertEqual(b.grid_info()['row'], self._str(2)) + + def test_grid_configure_rownspan(self): + b = tkinter.Button(self.root) + with self.assertRaisesRegex(TclError, 'bad rowspan value "0": ' + 'must be a positive integer'): + b.grid_configure(rowspan=0) + b.grid_configure(rowspan=2) + self.assertEqual(b.grid_info()['rowspan'], self._str(2)) + + def test_grid_configure_sticky(self): + f = tkinter.Frame(self.root, bg='red') + with self.assertRaisesRegex(TclError, 'bad stickyness value "glue"'): + f.grid_configure(sticky='glue') + f.grid_configure(sticky='ne') + self.assertEqual(f.grid_info()['sticky'], 'ne') + f.grid_configure(sticky='n,s,e,w') + self.assertEqual(f.grid_info()['sticky'], 'nesw') + + def test_grid_columnconfigure(self): + with self.assertRaises(TypeError): + self.root.grid_columnconfigure() + self.assertEqual(self.root.grid_columnconfigure(0), + {'minsize': 0, 'pad': 0, 'uniform': None, 'weight': 0}) + with self.assertRaisesRegex(TclError, 'bad option "-foo"'): + self.root.grid_columnconfigure(0, 'foo') + self.root.grid_columnconfigure((0, 3), weight=2) + with self.assertRaisesRegex(TclError, + 'must specify a single element on retrieval'): + self.root.grid_columnconfigure((0, 3)) + b = tkinter.Button(self.root) + b.grid_configure(column=0, row=0) + self.root.grid_columnconfigure('all', weight=3) + with self.assertRaisesRegex(TclError, 'expected integer but got "all"'): + self.root.grid_columnconfigure('all') + self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 3) + self.assertEqual(self.root.grid_columnconfigure(3, 'weight'), 2) + self.assertEqual(self.root.grid_columnconfigure(265, 'weight'), 0) + self.root.grid_columnconfigure(b, weight=4) + self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 4) + + def test_grid_columnconfigure_minsize(self): + with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + self.root.grid_columnconfigure(0, minsize='foo') + self.root.grid_columnconfigure(0, minsize=10) + self.assertEqual(self.root.grid_columnconfigure(0, 'minsize'), 10) + self.assertEqual(self.root.grid_columnconfigure(0)['minsize'], 10) + + def test_grid_columnconfigure_weight(self): + with self.assertRaisesRegex(TclError, 'expected integer but got "bad"'): + self.root.grid_columnconfigure(0, weight='bad') + with self.assertRaisesRegex(TclError, 'invalid arg "-weight": ' + 'should be non-negative'): + self.root.grid_columnconfigure(0, weight=-3) + self.root.grid_columnconfigure(0, weight=3) + self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 3) + self.assertEqual(self.root.grid_columnconfigure(0)['weight'], 3) + + def test_grid_columnconfigure_pad(self): + with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + self.root.grid_columnconfigure(0, pad='foo') + with self.assertRaisesRegex(TclError, 'invalid arg "-pad": ' + 'should be non-negative'): + self.root.grid_columnconfigure(0, pad=-3) + self.root.grid_columnconfigure(0, pad=3) + self.assertEqual(self.root.grid_columnconfigure(0, 'pad'), 3) + self.assertEqual(self.root.grid_columnconfigure(0)['pad'], 3) + + def test_grid_columnconfigure_uniform(self): + self.root.grid_columnconfigure(0, uniform='foo') + self.assertEqual(self.root.grid_columnconfigure(0, 'uniform'), 'foo') + self.assertEqual(self.root.grid_columnconfigure(0)['uniform'], 'foo') + + def test_grid_rowconfigure(self): + with self.assertRaises(TypeError): + self.root.grid_rowconfigure() + self.assertEqual(self.root.grid_rowconfigure(0), + {'minsize': 0, 'pad': 0, 'uniform': None, 'weight': 0}) + with self.assertRaisesRegex(TclError, 'bad option "-foo"'): + self.root.grid_rowconfigure(0, 'foo') + self.root.grid_rowconfigure((0, 3), weight=2) + with self.assertRaisesRegex(TclError, + 'must specify a single element on retrieval'): + self.root.grid_rowconfigure((0, 3)) + b = tkinter.Button(self.root) + b.grid_configure(column=0, row=0) + self.root.grid_rowconfigure('all', weight=3) + with self.assertRaisesRegex(TclError, 'expected integer but got "all"'): + self.root.grid_rowconfigure('all') + self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 3) + self.assertEqual(self.root.grid_rowconfigure(3, 'weight'), 2) + self.assertEqual(self.root.grid_rowconfigure(265, 'weight'), 0) + self.root.grid_rowconfigure(b, weight=4) + self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 4) + + def test_grid_rowconfigure_minsize(self): + with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + self.root.grid_rowconfigure(0, minsize='foo') + self.root.grid_rowconfigure(0, minsize=10) + self.assertEqual(self.root.grid_rowconfigure(0, 'minsize'), 10) + self.assertEqual(self.root.grid_rowconfigure(0)['minsize'], 10) + + def test_grid_rowconfigure_weight(self): + with self.assertRaisesRegex(TclError, 'expected integer but got "bad"'): + self.root.grid_rowconfigure(0, weight='bad') + with self.assertRaisesRegex(TclError, 'invalid arg "-weight": ' + 'should be non-negative'): + self.root.grid_rowconfigure(0, weight=-3) + self.root.grid_rowconfigure(0, weight=3) + self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 3) + self.assertEqual(self.root.grid_rowconfigure(0)['weight'], 3) + + def test_grid_rowconfigure_pad(self): + with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + self.root.grid_rowconfigure(0, pad='foo') + with self.assertRaisesRegex(TclError, 'invalid arg "-pad": ' + 'should be non-negative'): + self.root.grid_rowconfigure(0, pad=-3) + self.root.grid_rowconfigure(0, pad=3) + self.assertEqual(self.root.grid_rowconfigure(0, 'pad'), 3) + self.assertEqual(self.root.grid_rowconfigure(0)['pad'], 3) + + def test_grid_rowconfigure_uniform(self): + self.root.grid_rowconfigure(0, uniform='foo') + self.assertEqual(self.root.grid_rowconfigure(0, 'uniform'), 'foo') + self.assertEqual(self.root.grid_rowconfigure(0)['uniform'], 'foo') + + def test_grid_forget(self): + b = tkinter.Button(self.root) + c = tkinter.Button(self.root) + b.grid_configure(row=2, column=2, rowspan=2, columnspan=2, + padx=3, pady=4, sticky='ns') + self.assertEqual(self.root.grid_slaves(), [b]) + b.grid_forget() + c.grid_forget() + self.assertEqual(self.root.grid_slaves(), []) + self.assertEqual(b.grid_info(), {}) + b.grid_configure(row=0, column=0) + info = b.grid_info() + self.assertEqual(info['row'], self._str(0)) + self.assertEqual(info['column'], self._str(0)) + self.assertEqual(info['rowspan'], self._str(1)) + self.assertEqual(info['columnspan'], self._str(1)) + self.assertEqual(info['padx'], self._str(0)) + self.assertEqual(info['pady'], self._str(0)) + self.assertEqual(info['sticky'], '') + + def test_grid_remove(self): + b = tkinter.Button(self.root) + c = tkinter.Button(self.root) + b.grid_configure(row=2, column=2, rowspan=2, columnspan=2, + padx=3, pady=4, sticky='ns') + self.assertEqual(self.root.grid_slaves(), [b]) + b.grid_remove() + c.grid_remove() + self.assertEqual(self.root.grid_slaves(), []) + self.assertEqual(b.grid_info(), {}) + b.grid_configure(row=0, column=0) + info = b.grid_info() + self.assertEqual(info['row'], self._str(0)) + self.assertEqual(info['column'], self._str(0)) + self.assertEqual(info['rowspan'], self._str(2)) + self.assertEqual(info['columnspan'], self._str(2)) + self.assertEqual(info['padx'], self._str(3)) + self.assertEqual(info['pady'], self._str(4)) + self.assertEqual(info['sticky'], 'ns') + + def test_grid_info(self): + b = tkinter.Button(self.root) + self.assertEqual(b.grid_info(), {}) + b.grid_configure(row=2, column=2, rowspan=2, columnspan=2, + padx=3, pady=4, sticky='ns') + info = b.grid_info() + self.assertIsInstance(info, dict) + self.assertEqual(info['in'], self.root) + self.assertEqual(info['row'], self._str(2)) + self.assertEqual(info['column'], self._str(2)) + self.assertEqual(info['rowspan'], self._str(2)) + self.assertEqual(info['columnspan'], self._str(2)) + self.assertEqual(info['padx'], self._str(3)) + self.assertEqual(info['pady'], self._str(4)) + self.assertEqual(info['sticky'], 'ns') + + def test_grid_anchor(self): + with self.assertRaisesRegex(TclError, 'bad anchor "x"'): + self.root.grid_anchor('x') + with self.assertRaisesRegex(TclError, 'ambiguous anchor ""'): + self.root.grid_anchor('') + with self.assertRaises(TypeError): + self.root.grid_anchor('se', 'nw') + self.root.grid_anchor('se') + self.assertEqual(self.root.tk.call('grid', 'anchor', self.root), 'se') + + def test_grid_bbox(self): + self.assertEqual(self.root.grid_bbox(), (0, 0, 0, 0)) + self.assertEqual(self.root.grid_bbox(0, 0), (0, 0, 0, 0)) + self.assertEqual(self.root.grid_bbox(0, 0, 1, 1), (0, 0, 0, 0)) + with self.assertRaisesRegex(TclError, 'expected integer but got "x"'): + self.root.grid_bbox('x', 0) + with self.assertRaisesRegex(TclError, 'expected integer but got "x"'): + self.root.grid_bbox(0, 'x') + with self.assertRaisesRegex(TclError, 'expected integer but got "x"'): + self.root.grid_bbox(0, 0, 'x', 0) + with self.assertRaisesRegex(TclError, 'expected integer but got "x"'): + self.root.grid_bbox(0, 0, 0, 'x') + with self.assertRaises(TypeError): + self.root.grid_bbox(0, 0, 0, 0, 0) + t = self.root + # de-maximize + t.wm_geometry('1x1+0+0') + t.wm_geometry('') + f1 = tkinter.Frame(t, width=75, height=75, bg='red') + f2 = tkinter.Frame(t, width=90, height=90, bg='blue') + f1.grid_configure(row=0, column=0) + f2.grid_configure(row=1, column=1) + self.root.update() + self.assertEqual(t.grid_bbox(), (0, 0, 165, 165)) + self.assertEqual(t.grid_bbox(0, 0), (0, 0, 75, 75)) + self.assertEqual(t.grid_bbox(0, 0, 1, 1), (0, 0, 165, 165)) + self.assertEqual(t.grid_bbox(1, 1), (75, 75, 90, 90)) + self.assertEqual(t.grid_bbox(10, 10, 0, 0), (0, 0, 165, 165)) + self.assertEqual(t.grid_bbox(-2, -2, -1, -1), (0, 0, 0, 0)) + self.assertEqual(t.grid_bbox(10, 10, 12, 12), (165, 165, 0, 0)) + + def test_grid_location(self): + with self.assertRaises(TypeError): + self.root.grid_location() + with self.assertRaises(TypeError): + self.root.grid_location(0) + with self.assertRaises(TypeError): + self.root.grid_location(0, 0, 0) + with self.assertRaisesRegex(TclError, 'bad screen distance "x"'): + self.root.grid_location('x', 'y') + with self.assertRaisesRegex(TclError, 'bad screen distance "y"'): + self.root.grid_location('1c', 'y') + t = self.root + # de-maximize + t.wm_geometry('1x1+0+0') + t.wm_geometry('') + f = tkinter.Frame(t, width=200, height=100, + highlightthickness=0, bg='red') + self.assertEqual(f.grid_location(10, 10), (-1, -1)) + f.grid_configure() + self.root.update() + self.assertEqual(t.grid_location(-10, -10), (-1, -1)) + self.assertEqual(t.grid_location(-10, 0), (-1, 0)) + self.assertEqual(t.grid_location(-1, 0), (-1, 0)) + self.assertEqual(t.grid_location(0, -10), (0, -1)) + self.assertEqual(t.grid_location(0, -1), (0, -1)) + self.assertEqual(t.grid_location(0, 0), (0, 0)) + self.assertEqual(t.grid_location(200, 0), (0, 0)) + self.assertEqual(t.grid_location(201, 0), (1, 0)) + self.assertEqual(t.grid_location(0, 100), (0, 0)) + self.assertEqual(t.grid_location(0, 101), (0, 1)) + self.assertEqual(t.grid_location(201, 101), (1, 1)) + + def test_grid_propagate(self): + self.assertEqual(self.root.grid_propagate(), True) + with self.assertRaises(TypeError): + self.root.grid_propagate(False, False) + self.root.grid_propagate(False) + self.assertFalse(self.root.grid_propagate()) + f = tkinter.Frame(self.root, width=100, height=100, bg='red') + f.grid_configure(row=0, column=0) + self.root.update() + self.assertEqual(f.winfo_width(), 100) + self.assertEqual(f.winfo_height(), 100) + f.grid_propagate(False) + g = tkinter.Frame(self.root, width=75, height=85, bg='green') + g.grid_configure(in_=f, row=0, column=0) + self.root.update() + self.assertEqual(f.winfo_width(), 100) + self.assertEqual(f.winfo_height(), 100) + f.grid_propagate(True) + self.root.update() + self.assertEqual(f.winfo_width(), 75) + self.assertEqual(f.winfo_height(), 85) + + def test_grid_size(self): + with self.assertRaises(TypeError): + self.root.grid_size(0) + self.assertEqual(self.root.grid_size(), (0, 0)) + f = tkinter.Scale(self.root) + f.grid_configure(row=0, column=0) + self.assertEqual(self.root.grid_size(), (1, 1)) + f.grid_configure(row=4, column=5) + self.assertEqual(self.root.grid_size(), (6, 5)) + + def test_grid_slaves(self): + self.assertEqual(self.root.grid_slaves(), []) + a = tkinter.Label(self.root) + a.grid_configure(row=0, column=1) + b = tkinter.Label(self.root) + b.grid_configure(row=1, column=0) + c = tkinter.Label(self.root) + c.grid_configure(row=1, column=1) + d = tkinter.Label(self.root) + d.grid_configure(row=1, column=1) + self.assertEqual(self.root.grid_slaves(), [d, c, b, a]) + self.assertEqual(self.root.grid_slaves(row=0), [a]) + self.assertEqual(self.root.grid_slaves(row=1), [d, c, b]) + self.assertEqual(self.root.grid_slaves(column=0), [b]) + self.assertEqual(self.root.grid_slaves(column=1), [d, c, a]) + self.assertEqual(self.root.grid_slaves(row=1, column=1), [d, c]) + + +tests_gui = ( + PackTest, PlaceTest, GridTest, +) + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_tkinter/test_images.py b/Lib/test/test_tkinter/test_images.py new file mode 100644 index 0000000..b6f8b79 --- /dev/null +++ b/Lib/test/test_tkinter/test_images.py @@ -0,0 +1,380 @@ +import unittest +import tkinter +from test import support +from test.support import os_helper +from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest, requires_tcl + +support.requires('gui') + + +class MiscTest(AbstractTkTest, unittest.TestCase): + + def test_image_types(self): + image_types = self.root.image_types() + self.assertIsInstance(image_types, tuple) + self.assertIn('photo', image_types) + self.assertIn('bitmap', image_types) + + def test_image_names(self): + image_names = self.root.image_names() + 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 + def setUpClass(cls): + AbstractTkTest.setUpClass.__func__(cls) + cls.testfile = support.findfile('python.xbm', subdir='imghdrdata') + + def test_create_from_file(self): + image = tkinter.BitmapImage('::img::test', master=self.root, + foreground='yellow', background='blue', + file=self.testfile) + self.assertEqual(str(image), '::img::test') + self.assertEqual(image.type(), 'bitmap') + self.assertEqual(image.width(), 16) + self.assertEqual(image.height(), 16) + self.assertIn('::img::test', self.root.image_names()) + del image + support.gc_collect() # For PyPy or other GCs. + self.assertNotIn('::img::test', self.root.image_names()) + + def test_create_from_data(self): + with open(self.testfile, 'rb') as f: + data = f.read() + image = tkinter.BitmapImage('::img::test', master=self.root, + foreground='yellow', background='blue', + data=data) + self.assertEqual(str(image), '::img::test') + self.assertEqual(image.type(), 'bitmap') + self.assertEqual(image.width(), 16) + self.assertEqual(image.height(), 16) + self.assertIn('::img::test', self.root.image_names()) + del image + support.gc_collect() # For PyPy or other GCs. + self.assertNotIn('::img::test', self.root.image_names()) + + def assertEqualStrList(self, actual, expected): + self.assertIsInstance(actual, str) + self.assertEqual(self.root.splitlist(actual), expected) + + def test_configure_data(self): + image = tkinter.BitmapImage('::img::test', master=self.root) + self.assertEqual(image['data'], '-data {} {} {} {}') + with open(self.testfile, 'rb') as f: + data = f.read() + image.configure(data=data) + self.assertEqualStrList(image['data'], + ('-data', '', '', '', data.decode('ascii'))) + self.assertEqual(image.width(), 16) + self.assertEqual(image.height(), 16) + + self.assertEqual(image['maskdata'], '-maskdata {} {} {} {}') + image.configure(maskdata=data) + self.assertEqualStrList(image['maskdata'], + ('-maskdata', '', '', '', data.decode('ascii'))) + + def test_configure_file(self): + image = tkinter.BitmapImage('::img::test', master=self.root) + self.assertEqual(image['file'], '-file {} {} {} {}') + image.configure(file=self.testfile) + self.assertEqualStrList(image['file'], + ('-file', '', '', '',self.testfile)) + self.assertEqual(image.width(), 16) + self.assertEqual(image.height(), 16) + + self.assertEqual(image['maskfile'], '-maskfile {} {} {} {}') + image.configure(maskfile=self.testfile) + self.assertEqualStrList(image['maskfile'], + ('-maskfile', '', '', '', self.testfile)) + + def test_configure_background(self): + image = tkinter.BitmapImage('::img::test', master=self.root) + self.assertEqual(image['background'], '-background {} {} {} {}') + image.configure(background='blue') + self.assertEqual(image['background'], '-background {} {} {} blue') + + def test_configure_foreground(self): + image = tkinter.BitmapImage('::img::test', master=self.root) + self.assertEqual(image['foreground'], + '-foreground {} {} #000000 #000000') + image.configure(foreground='yellow') + self.assertEqual(image['foreground'], + '-foreground {} {} #000000 yellow') + + +class PhotoImageTest(AbstractTkTest, unittest.TestCase): + + @classmethod + def setUpClass(cls): + AbstractTkTest.setUpClass.__func__(cls) + cls.testfile = support.findfile('python.gif', subdir='imghdrdata') + + def create(self): + return tkinter.PhotoImage('::img::test', master=self.root, + file=self.testfile) + + def colorlist(self, *args): + if tkinter.TkVersion >= 8.6 and self.wantobjects: + return args + else: + return tkinter._join(args) + + def check_create_from_file(self, ext): + testfile = support.findfile('python.' + ext, subdir='imghdrdata') + image = tkinter.PhotoImage('::img::test', master=self.root, + file=testfile) + self.assertEqual(str(image), '::img::test') + self.assertEqual(image.type(), 'photo') + self.assertEqual(image.width(), 16) + self.assertEqual(image.height(), 16) + self.assertEqual(image['data'], '') + self.assertEqual(image['file'], testfile) + self.assertIn('::img::test', self.root.image_names()) + del image + support.gc_collect() # For PyPy or other GCs. + self.assertNotIn('::img::test', self.root.image_names()) + + def check_create_from_data(self, ext): + testfile = support.findfile('python.' + ext, subdir='imghdrdata') + with open(testfile, 'rb') as f: + data = f.read() + image = tkinter.PhotoImage('::img::test', master=self.root, + data=data) + self.assertEqual(str(image), '::img::test') + self.assertEqual(image.type(), 'photo') + self.assertEqual(image.width(), 16) + self.assertEqual(image.height(), 16) + self.assertEqual(image['data'], data if self.wantobjects + else data.decode('latin1')) + self.assertEqual(image['file'], '') + self.assertIn('::img::test', self.root.image_names()) + del image + support.gc_collect() # For PyPy or other GCs. + self.assertNotIn('::img::test', self.root.image_names()) + + def test_create_from_ppm_file(self): + self.check_create_from_file('ppm') + + def test_create_from_ppm_data(self): + self.check_create_from_data('ppm') + + def test_create_from_pgm_file(self): + self.check_create_from_file('pgm') + + def test_create_from_pgm_data(self): + self.check_create_from_data('pgm') + + def test_create_from_gif_file(self): + self.check_create_from_file('gif') + + def test_create_from_gif_data(self): + self.check_create_from_data('gif') + + @requires_tcl(8, 6) + def test_create_from_png_file(self): + self.check_create_from_file('png') + + @requires_tcl(8, 6) + def test_create_from_png_data(self): + self.check_create_from_data('png') + + def test_configure_data(self): + image = tkinter.PhotoImage('::img::test', master=self.root) + self.assertEqual(image['data'], '') + with open(self.testfile, 'rb') as f: + data = f.read() + image.configure(data=data) + self.assertEqual(image['data'], data if self.wantobjects + else data.decode('latin1')) + self.assertEqual(image.width(), 16) + self.assertEqual(image.height(), 16) + + def test_configure_format(self): + image = tkinter.PhotoImage('::img::test', master=self.root) + self.assertEqual(image['format'], '') + image.configure(file=self.testfile, format='gif') + self.assertEqual(image['format'], ('gif',) if self.wantobjects + else 'gif') + self.assertEqual(image.width(), 16) + self.assertEqual(image.height(), 16) + + def test_configure_file(self): + image = tkinter.PhotoImage('::img::test', master=self.root) + self.assertEqual(image['file'], '') + image.configure(file=self.testfile) + self.assertEqual(image['file'], self.testfile) + self.assertEqual(image.width(), 16) + self.assertEqual(image.height(), 16) + + def test_configure_gamma(self): + image = tkinter.PhotoImage('::img::test', master=self.root) + self.assertEqual(image['gamma'], '1.0') + image.configure(gamma=2.0) + self.assertEqual(image['gamma'], '2.0') + + def test_configure_width_height(self): + image = tkinter.PhotoImage('::img::test', master=self.root) + self.assertEqual(image['width'], '0') + self.assertEqual(image['height'], '0') + image.configure(width=20) + image.configure(height=10) + self.assertEqual(image['width'], '20') + self.assertEqual(image['height'], '10') + self.assertEqual(image.width(), 20) + self.assertEqual(image.height(), 10) + + def test_configure_palette(self): + image = tkinter.PhotoImage('::img::test', master=self.root) + self.assertEqual(image['palette'], '') + image.configure(palette=256) + self.assertEqual(image['palette'], '256') + image.configure(palette='3/4/2') + self.assertEqual(image['palette'], '3/4/2') + + def test_blank(self): + image = self.create() + image.blank() + self.assertEqual(image.width(), 16) + self.assertEqual(image.height(), 16) + self.assertEqual(image.get(4, 6), self.colorlist(0, 0, 0)) + + def test_copy(self): + image = self.create() + image2 = image.copy() + self.assertEqual(image2.width(), 16) + self.assertEqual(image2.height(), 16) + self.assertEqual(image.get(4, 6), image.get(4, 6)) + + def test_subsample(self): + image = self.create() + image2 = image.subsample(2, 3) + self.assertEqual(image2.width(), 8) + self.assertEqual(image2.height(), 6) + self.assertEqual(image2.get(2, 2), image.get(4, 6)) + + image2 = image.subsample(2) + self.assertEqual(image2.width(), 8) + self.assertEqual(image2.height(), 8) + self.assertEqual(image2.get(2, 3), image.get(4, 6)) + + def test_zoom(self): + image = self.create() + image2 = image.zoom(2, 3) + self.assertEqual(image2.width(), 32) + self.assertEqual(image2.height(), 48) + self.assertEqual(image2.get(8, 18), image.get(4, 6)) + self.assertEqual(image2.get(9, 20), image.get(4, 6)) + + image2 = image.zoom(2) + self.assertEqual(image2.width(), 32) + self.assertEqual(image2.height(), 32) + self.assertEqual(image2.get(8, 12), image.get(4, 6)) + self.assertEqual(image2.get(9, 13), image.get(4, 6)) + + def test_put(self): + image = self.create() + image.put('{red green} {blue yellow}', to=(4, 6)) + self.assertEqual(image.get(4, 6), self.colorlist(255, 0, 0)) + self.assertEqual(image.get(5, 6), + self.colorlist(0, 128 if tkinter.TkVersion >= 8.6 + else 255, 0)) + self.assertEqual(image.get(4, 7), self.colorlist(0, 0, 255)) + self.assertEqual(image.get(5, 7), self.colorlist(255, 255, 0)) + + image.put((('#f00', '#00ff00'), ('#000000fff', '#ffffffff0000'))) + self.assertEqual(image.get(0, 0), self.colorlist(255, 0, 0)) + self.assertEqual(image.get(1, 0), self.colorlist(0, 255, 0)) + self.assertEqual(image.get(0, 1), self.colorlist(0, 0, 255)) + self.assertEqual(image.get(1, 1), self.colorlist(255, 255, 0)) + + def test_get(self): + image = self.create() + self.assertEqual(image.get(4, 6), self.colorlist(62, 116, 162)) + self.assertEqual(image.get(0, 0), self.colorlist(0, 0, 0)) + self.assertEqual(image.get(15, 15), self.colorlist(0, 0, 0)) + self.assertRaises(tkinter.TclError, image.get, -1, 0) + self.assertRaises(tkinter.TclError, image.get, 0, -1) + self.assertRaises(tkinter.TclError, image.get, 16, 15) + self.assertRaises(tkinter.TclError, image.get, 15, 16) + + def test_write(self): + image = self.create() + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + + image.write(os_helper.TESTFN) + image2 = tkinter.PhotoImage('::img::test2', master=self.root, + format='ppm', + file=os_helper.TESTFN) + self.assertEqual(str(image2), '::img::test2') + self.assertEqual(image2.type(), 'photo') + self.assertEqual(image2.width(), 16) + self.assertEqual(image2.height(), 16) + self.assertEqual(image2.get(0, 0), image.get(0, 0)) + self.assertEqual(image2.get(15, 8), image.get(15, 8)) + + image.write(os_helper.TESTFN, format='gif', from_coords=(4, 6, 6, 9)) + image3 = tkinter.PhotoImage('::img::test3', master=self.root, + format='gif', + file=os_helper.TESTFN) + self.assertEqual(str(image3), '::img::test3') + self.assertEqual(image3.type(), 'photo') + self.assertEqual(image3.width(), 2) + self.assertEqual(image3.height(), 3) + self.assertEqual(image3.get(0, 0), image.get(4, 6)) + self.assertEqual(image3.get(1, 2), image.get(5, 8)) + + def test_transparency(self): + image = self.create() + self.assertEqual(image.transparency_get(0, 0), True) + self.assertEqual(image.transparency_get(4, 6), False) + image.transparency_set(4, 6, True) + self.assertEqual(image.transparency_get(4, 6), True) + image.transparency_set(4, 6, False) + self.assertEqual(image.transparency_get(4, 6), False) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_tkinter/test_loadtk.py b/Lib/test/test_tkinter/test_loadtk.py new file mode 100644 index 0000000..61b0eda --- /dev/null +++ b/Lib/test/test_tkinter/test_loadtk.py @@ -0,0 +1,46 @@ +import os +import sys +import unittest +import test.support as test_support +from test.support import os_helper +from tkinter import Tcl, TclError + +test_support.requires('gui') + +class TkLoadTest(unittest.TestCase): + + @unittest.skipIf('DISPLAY' not in os.environ, 'No $DISPLAY set.') + def testLoadTk(self): + tcl = Tcl() + self.assertRaises(TclError,tcl.winfo_geometry) + tcl.loadtk() + self.assertEqual('1x1+0+0', tcl.winfo_geometry()) + tcl.destroy() + + def testLoadTkFailure(self): + old_display = None + if sys.platform.startswith(('win', 'darwin', 'cygwin')): + # no failure possible on windows? + + # XXX Maybe on tk older than 8.4.13 it would be possible, + # see tkinter.h. + return + with os_helper.EnvironmentVarGuard() as env: + if 'DISPLAY' in os.environ: + del env['DISPLAY'] + # on some platforms, deleting environment variables + # doesn't actually carry through to the process level + # because they don't support unsetenv + # If that's the case, abort. + with os.popen('echo $DISPLAY') as pipe: + display = pipe.read().strip() + if display: + return + + tcl = Tcl() + self.assertRaises(TclError, tcl.winfo_geometry) + self.assertRaises(TclError, tcl.loadtk) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_tkinter/test_messagebox.py b/Lib/test/test_tkinter/test_messagebox.py new file mode 100644 index 0000000..f41bdc9 --- /dev/null +++ b/Lib/test/test_tkinter/test_messagebox.py @@ -0,0 +1,36 @@ +import unittest +import tkinter +from test.support import requires, swap_attr +from test.test_tkinter.support import AbstractDefaultRootTest +from tkinter.commondialog import Dialog +from tkinter.messagebox import showinfo + +requires('gui') + + +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_showinfo(self): + def test_callback(dialog, master): + nonlocal ismapped + master.update() + ismapped = master.winfo_ismapped() + raise ZeroDivisionError + + with swap_attr(Dialog, '_test_callback', test_callback): + ismapped = None + self.assertRaises(ZeroDivisionError, showinfo, "Spam", "Egg Information") + self.assertEqual(ismapped, False) + + root = tkinter.Tk() + ismapped = None + self.assertRaises(ZeroDivisionError, showinfo, "Spam", "Egg Information") + self.assertEqual(ismapped, True) + root.destroy() + + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, showinfo, "Spam", "Egg Information") + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py new file mode 100644 index 0000000..d1aca58 --- /dev/null +++ b/Lib/test/test_tkinter/test_misc.py @@ -0,0 +1,430 @@ +import functools +import unittest +import tkinter +import enum +from test import support +from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest + +support.requires('gui') + +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): + t = tkinter.Toplevel(self.root, name='top') + f = tkinter.Frame(t, name='child') + self.assertEqual(repr(f), '') + + def test_generated_names(self): + t = tkinter.Toplevel(self.root) + f = tkinter.Frame(t) + f2 = tkinter.Frame(t) + b = tkinter.Button(f2) + for name in str(b).split('.'): + self.assertFalse(name.isidentifier(), msg=repr(name)) + + def test_tk_setPalette(self): + root = self.root + root.tk_setPalette('black') + self.assertEqual(root['background'], 'black') + root.tk_setPalette('white') + self.assertEqual(root['background'], 'white') + self.assertRaisesRegex(tkinter.TclError, + '^unknown color name "spam"$', + root.tk_setPalette, 'spam') + + root.tk_setPalette(background='black') + self.assertEqual(root['background'], 'black') + root.tk_setPalette(background='blue', highlightColor='yellow') + self.assertEqual(root['background'], 'blue') + self.assertEqual(root['highlightcolor'], 'yellow') + root.tk_setPalette(background='yellow', highlightColor='blue') + self.assertEqual(root['background'], 'yellow') + self.assertEqual(root['highlightcolor'], 'blue') + self.assertRaisesRegex(tkinter.TclError, + '^unknown color name "spam"$', + root.tk_setPalette, background='spam') + self.assertRaisesRegex(tkinter.TclError, + '^must specify a background color$', + root.tk_setPalette, spam='white') + self.assertRaisesRegex(tkinter.TclError, + '^must specify a background color$', + root.tk_setPalette, highlightColor='blue') + + def test_after(self): + root = self.root + + def callback(start=0, step=1): + nonlocal count + count = start + step + + # Without function, sleeps for ms. + self.assertIsNone(root.after(1)) + + # Set up with callback with no args. + count = 0 + timer1 = root.after(0, callback) + self.assertIn(timer1, root.tk.call('after', 'info')) + (script, _) = root.tk.splitlist(root.tk.call('after', 'info', timer1)) + root.update() # Process all pending events. + self.assertEqual(count, 1) + with self.assertRaises(tkinter.TclError): + root.tk.call(script) + + # Set up with callback with args. + count = 0 + timer1 = root.after(0, callback, 42, 11) + root.update() # Process all pending events. + self.assertEqual(count, 53) + + # Cancel before called. + timer1 = root.after(1000, callback) + self.assertIn(timer1, root.tk.call('after', 'info')) + (script, _) = root.tk.splitlist(root.tk.call('after', 'info', timer1)) + root.after_cancel(timer1) # Cancel this event. + self.assertEqual(count, 53) + with self.assertRaises(tkinter.TclError): + root.tk.call(script) + + # Call with a callable class + count = 0 + timer1 = root.after(0, functools.partial(callback, 42, 11)) + root.update() # Process all pending events. + self.assertEqual(count, 53) + + def test_after_idle(self): + root = self.root + + def callback(start=0, step=1): + nonlocal count + count = start + step + + # Set up with callback with no args. + count = 0 + idle1 = root.after_idle(callback) + self.assertIn(idle1, root.tk.call('after', 'info')) + (script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1)) + root.update_idletasks() # Process all pending events. + self.assertEqual(count, 1) + with self.assertRaises(tkinter.TclError): + root.tk.call(script) + + # Set up with callback with args. + count = 0 + idle1 = root.after_idle(callback, 42, 11) + root.update_idletasks() # Process all pending events. + self.assertEqual(count, 53) + + # Cancel before called. + idle1 = root.after_idle(callback) + self.assertIn(idle1, root.tk.call('after', 'info')) + (script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1)) + root.after_cancel(idle1) # Cancel this event. + self.assertEqual(count, 53) + with self.assertRaises(tkinter.TclError): + root.tk.call(script) + + def test_after_cancel(self): + root = self.root + + def callback(): + nonlocal count + count += 1 + + timer1 = root.after(5000, callback) + idle1 = root.after_idle(callback) + + # No value for id raises a ValueError. + with self.assertRaises(ValueError): + root.after_cancel(None) + + # Cancel timer event. + count = 0 + (script, _) = root.tk.splitlist(root.tk.call('after', 'info', timer1)) + root.tk.call(script) + self.assertEqual(count, 1) + root.after_cancel(timer1) + with self.assertRaises(tkinter.TclError): + root.tk.call(script) + self.assertEqual(count, 1) + with self.assertRaises(tkinter.TclError): + root.tk.call('after', 'info', timer1) + + # Cancel same event - nothing happens. + root.after_cancel(timer1) + + # Cancel idle event. + count = 0 + (script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1)) + root.tk.call(script) + self.assertEqual(count, 1) + root.after_cancel(idle1) + with self.assertRaises(tkinter.TclError): + root.tk.call(script) + self.assertEqual(count, 1) + with self.assertRaises(tkinter.TclError): + root.tk.call('after', 'info', idle1) + + def test_clipboard(self): + root = self.root + root.clipboard_clear() + root.clipboard_append('Ùñî') + self.assertEqual(root.clipboard_get(), 'Ùñî') + root.clipboard_append('çōđě') + self.assertEqual(root.clipboard_get(), 'Ùñîçōđě') + root.clipboard_clear() + with self.assertRaises(tkinter.TclError): + root.clipboard_get() + + def test_clipboard_astral(self): + root = self.root + root.clipboard_clear() + root.clipboard_append('𝔘𝔫𝔦') + self.assertEqual(root.clipboard_get(), '𝔘𝔫𝔦') + root.clipboard_append('𝔠𝔬𝔡𝔢') + self.assertEqual(root.clipboard_get(), '𝔘𝔫𝔦𝔠𝔬𝔡𝔢') + root.clipboard_clear() + with self.assertRaises(tkinter.TclError): + root.clipboard_get() + + def test_winfo_rgb(self): + + def assertApprox(col1, col2): + # A small amount of flexibility is required (bpo-45496) + # 33 is ~0.05% of 65535, which is a reasonable margin + for col1_channel, col2_channel in zip(col1, col2): + self.assertAlmostEqual(col1_channel, col2_channel, delta=33) + + root = self.root + rgb = root.winfo_rgb + + # Color name. + self.assertEqual(rgb('red'), (65535, 0, 0)) + self.assertEqual(rgb('dark slate blue'), (18504, 15677, 35723)) + # #RGB - extends each 4-bit hex value to be 16-bit. + self.assertEqual(rgb('#F0F'), (0xFFFF, 0x0000, 0xFFFF)) + # #RRGGBB - extends each 8-bit hex value to be 16-bit. + assertApprox(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c)) + # #RRRRGGGGBBBB + assertApprox(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939)) + # Invalid string. + with self.assertRaises(tkinter.TclError): + rgb('#123456789a') + # RGB triplet is invalid input. + with self.assertRaises(tkinter.TclError): + rgb((111, 78, 55)) + + def test_event_repr_defaults(self): + e = tkinter.Event() + e.serial = 12345 + e.num = '??' + e.height = '??' + e.keycode = '??' + e.state = 0 + e.time = 123456789 + e.width = '??' + e.x = '??' + e.y = '??' + e.char = '' + e.keysym = '??' + e.keysym_num = '??' + e.type = '100' + e.widget = '??' + e.x_root = '??' + e.y_root = '??' + e.delta = 0 + self.assertEqual(repr(e), '<100 event>') + + def test_event_repr(self): + e = tkinter.Event() + e.serial = 12345 + e.num = 3 + e.focus = True + e.height = 200 + e.keycode = 65 + e.state = 0x30405 + e.time = 123456789 + e.width = 300 + e.x = 10 + e.y = 20 + e.char = 'A' + e.send_event = True + e.keysym = 'Key-A' + e.keysym_num = ord('A') + e.type = tkinter.EventType.Configure + e.widget = '.text' + e.x_root = 1010 + e.y_root = 1020 + e.delta = -1 + self.assertEqual(repr(e), + "") + + def test_eventtype_enum(self): + class CheckedEventType(enum.StrEnum): + KeyPress = '2' + Key = KeyPress + KeyRelease = '3' + ButtonPress = '4' + Button = ButtonPress + ButtonRelease = '5' + Motion = '6' + Enter = '7' + Leave = '8' + FocusIn = '9' + FocusOut = '10' + Keymap = '11' # undocumented + Expose = '12' + GraphicsExpose = '13' # undocumented + NoExpose = '14' # undocumented + Visibility = '15' + Create = '16' + Destroy = '17' + Unmap = '18' + Map = '19' + MapRequest = '20' + Reparent = '21' + Configure = '22' + ConfigureRequest = '23' + Gravity = '24' + ResizeRequest = '25' + Circulate = '26' + CirculateRequest = '27' + Property = '28' + SelectionClear = '29' # undocumented + SelectionRequest = '30' # undocumented + Selection = '31' # undocumented + Colormap = '32' + ClientMessage = '33' # undocumented + Mapping = '34' # undocumented + VirtualEvent = '35' # undocumented + Activate = '36' + Deactivate = '37' + MouseWheel = '38' + enum._test_simple_enum(CheckedEventType, tkinter.EventType) + + 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()) + + def test_info_patchlevel(self): + vi = self.root.info_patchlevel() + f = tkinter.Frame(self.root) + self.assertEqual(f.info_patchlevel(), vi) + # The following is almost a copy of tests for sys.version_info. + self.assertIsInstance(vi[:], tuple) + self.assertEqual(len(vi), 5) + self.assertIsInstance(vi[0], int) + self.assertIsInstance(vi[1], int) + self.assertIsInstance(vi[2], int) + self.assertIn(vi[3], ("alpha", "beta", "candidate", "final")) + self.assertIsInstance(vi[4], int) + self.assertIsInstance(vi.major, int) + self.assertIsInstance(vi.minor, int) + self.assertIsInstance(vi.micro, int) + self.assertIn(vi.releaselevel, ("alpha", "beta", "final")) + self.assertIsInstance(vi.serial, int) + self.assertEqual(vi[0], vi.major) + self.assertEqual(vi[1], vi.minor) + self.assertEqual(vi[2], vi.micro) + self.assertEqual(vi[3], vi.releaselevel) + self.assertEqual(vi[4], vi.serial) + self.assertTrue(vi > (1,0,0)) + if vi.releaselevel == 'final': + self.assertEqual(vi.serial, 0) + else: + self.assertEqual(vi.micro, 0) + self.assertTrue(str(vi).startswith(f'{vi.major}.{vi.minor}')) + + +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) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_tkinter/test_simpledialog.py b/Lib/test/test_tkinter/test_simpledialog.py new file mode 100644 index 0000000..502f7f7 --- /dev/null +++ b/Lib/test/test_tkinter/test_simpledialog.py @@ -0,0 +1,35 @@ +import unittest +import tkinter +from test.support import requires, swap_attr +from test.test_tkinter.support import AbstractDefaultRootTest +from tkinter.simpledialog import Dialog, askinteger + +requires('gui') + + +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_askinteger(self): + @staticmethod + def mock_wait_window(w): + nonlocal ismapped + ismapped = w.master.winfo_ismapped() + w.destroy() + + with swap_attr(Dialog, 'wait_window', mock_wait_window): + ismapped = None + askinteger("Go To Line", "Line number") + self.assertEqual(ismapped, False) + + root = tkinter.Tk() + ismapped = None + askinteger("Go To Line", "Line number") + self.assertEqual(ismapped, True) + root.destroy() + + tkinter.NoDefaultRoot() + self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number") + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py new file mode 100644 index 0000000..d1583f0 --- /dev/null +++ b/Lib/test/test_tkinter/test_text.py @@ -0,0 +1,45 @@ +import unittest +import tkinter +from test.support import requires +from test.test_tkinter.support import AbstractTkTest + +requires('gui') + +class TextTest(AbstractTkTest, unittest.TestCase): + + def setUp(self): + super().setUp() + self.text = tkinter.Text(self.root) + + def test_debug(self): + text = self.text + olddebug = text.debug() + try: + text.debug(0) + self.assertEqual(text.debug(), 0) + text.debug(1) + self.assertEqual(text.debug(), 1) + finally: + text.debug(olddebug) + self.assertEqual(text.debug(), olddebug) + + def test_search(self): + text = self.text + + # pattern and index are obligatory arguments. + self.assertRaises(tkinter.TclError, text.search, None, '1.0') + self.assertRaises(tkinter.TclError, text.search, 'a', None) + self.assertRaises(tkinter.TclError, text.search, None, None) + + # Invalid text index. + self.assertRaises(tkinter.TclError, text.search, '', 0) + + # Check if we are getting the indices as strings -- you are likely + # to get Tcl_Obj under Tk 8.5 if Tkinter doesn't convert it. + text.insert('1.0', 'hi-test') + self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') + self.assertEqual(text.search('test', '1.0', 'end'), '1.3') + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_tkinter/test_variables.py b/Lib/test/test_tkinter/test_variables.py new file mode 100644 index 0000000..c1d232e --- /dev/null +++ b/Lib/test/test_tkinter/test_variables.py @@ -0,0 +1,342 @@ +import unittest +from test import support + +import gc +import tkinter +from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl, + TclError) +from test.support import ALWAYS_EQ +from test.test_tkinter.support import AbstractDefaultRootTest + + +class Var(Variable): + + _default = "default" + side_effect = False + + def set(self, value): + self.side_effect = True + super().set(value) + + +class TestBase(unittest.TestCase): + + def setUp(self): + self.root = Tcl() + + def tearDown(self): + del self.root + + +class TestVariable(TestBase): + + def info_exists(self, *args): + return self.root.getboolean(self.root.call("info", "exists", *args)) + + def test_default(self): + v = Variable(self.root) + self.assertEqual("", v.get()) + self.assertRegex(str(v), r"^PY_VAR(\d+)$") + + def test_name_and_value(self): + v = Variable(self.root, "sample string", "varname") + self.assertEqual("sample string", v.get()) + self.assertEqual("varname", str(v)) + + def test___del__(self): + self.assertFalse(self.info_exists("varname")) + v = Variable(self.root, "sample string", "varname") + self.assertTrue(self.info_exists("varname")) + del v + support.gc_collect() # For PyPy or other GCs. + self.assertFalse(self.info_exists("varname")) + + def test_dont_unset_not_existing(self): + self.assertFalse(self.info_exists("varname")) + v1 = Variable(self.root, name="name") + v2 = Variable(self.root, name="name") + del v1 + support.gc_collect() # For PyPy or other GCs. + self.assertFalse(self.info_exists("name")) + # shouldn't raise exception + del v2 + support.gc_collect() # For PyPy or other GCs. + self.assertFalse(self.info_exists("name")) + + def test_equality(self): + # values doesn't matter, only class and name are checked + v1 = Variable(self.root, name="abc") + v2 = Variable(self.root, name="abc") + self.assertIsNot(v1, v2) + self.assertEqual(v1, v2) + + v3 = Variable(self.root, name="cba") + self.assertNotEqual(v1, v3) + + v4 = StringVar(self.root, name="abc") + self.assertEqual(str(v1), str(v4)) + self.assertNotEqual(v1, v4) + + V = type('Variable', (), {}) + self.assertNotEqual(v1, V()) + + self.assertNotEqual(v1, object()) + self.assertEqual(v1, ALWAYS_EQ) + + root2 = tkinter.Tk() + self.addCleanup(root2.destroy) + v5 = Variable(root2, name="abc") + self.assertEqual(str(v1), str(v5)) + self.assertNotEqual(v1, v5) + + def test_invalid_name(self): + with self.assertRaises(TypeError): + Variable(self.root, name=123) + + def test_null_in_name(self): + with self.assertRaises(ValueError): + Variable(self.root, name='var\x00name') + with self.assertRaises(ValueError): + self.root.globalsetvar('var\x00name', "value") + with self.assertRaises(ValueError): + self.root.globalsetvar(b'var\x00name', "value") + with self.assertRaises(ValueError): + self.root.setvar('var\x00name', "value") + with self.assertRaises(ValueError): + self.root.setvar(b'var\x00name', "value") + + def test_initialize(self): + v = Var(self.root) + self.assertFalse(v.side_effect) + v.set("value") + self.assertTrue(v.side_effect) + + def test_trace_old(self): + # Old interface + v = Variable(self.root) + vname = str(v) + trace = [] + def read_tracer(*args): + trace.append(('read',) + args) + def write_tracer(*args): + trace.append(('write',) + args) + cb1 = v.trace_variable('r', read_tracer) + cb2 = v.trace_variable('wu', write_tracer) + self.assertEqual(sorted(v.trace_vinfo()), [('r', cb1), ('wu', cb2)]) + self.assertEqual(trace, []) + + v.set('spam') + self.assertEqual(trace, [('write', vname, '', 'w')]) + + trace = [] + v.get() + self.assertEqual(trace, [('read', vname, '', 'r')]) + + trace = [] + info = sorted(v.trace_vinfo()) + v.trace_vdelete('w', cb1) # Wrong mode + self.assertEqual(sorted(v.trace_vinfo()), info) + with self.assertRaises(TclError): + v.trace_vdelete('r', 'spam') # Wrong command name + self.assertEqual(sorted(v.trace_vinfo()), info) + v.trace_vdelete('r', (cb1, 43)) # Wrong arguments + self.assertEqual(sorted(v.trace_vinfo()), info) + v.get() + self.assertEqual(trace, [('read', vname, '', 'r')]) + + trace = [] + v.trace_vdelete('r', cb1) + self.assertEqual(v.trace_vinfo(), [('wu', cb2)]) + v.get() + self.assertEqual(trace, []) + + trace = [] + del write_tracer + gc.collect() + v.set('eggs') + self.assertEqual(trace, [('write', vname, '', 'w')]) + + trace = [] + del v + gc.collect() + self.assertEqual(trace, [('write', vname, '', 'u')]) + + def test_trace(self): + v = Variable(self.root) + vname = str(v) + trace = [] + def read_tracer(*args): + trace.append(('read',) + args) + def write_tracer(*args): + trace.append(('write',) + args) + tr1 = v.trace_add('read', read_tracer) + tr2 = v.trace_add(['write', 'unset'], write_tracer) + self.assertEqual(sorted(v.trace_info()), [ + (('read',), tr1), + (('write', 'unset'), tr2)]) + self.assertEqual(trace, []) + + v.set('spam') + self.assertEqual(trace, [('write', vname, '', 'write')]) + + trace = [] + v.get() + self.assertEqual(trace, [('read', vname, '', 'read')]) + + trace = [] + info = sorted(v.trace_info()) + v.trace_remove('write', tr1) # Wrong mode + self.assertEqual(sorted(v.trace_info()), info) + with self.assertRaises(TclError): + v.trace_remove('read', 'spam') # Wrong command name + self.assertEqual(sorted(v.trace_info()), info) + v.get() + self.assertEqual(trace, [('read', vname, '', 'read')]) + + trace = [] + v.trace_remove('read', tr1) + self.assertEqual(v.trace_info(), [(('write', 'unset'), tr2)]) + v.get() + self.assertEqual(trace, []) + + trace = [] + del write_tracer + gc.collect() + v.set('eggs') + self.assertEqual(trace, [('write', vname, '', 'write')]) + + trace = [] + del v + gc.collect() + self.assertEqual(trace, [('write', vname, '', 'unset')]) + + +class TestStringVar(TestBase): + + def test_default(self): + v = StringVar(self.root) + self.assertEqual("", v.get()) + + def test_get(self): + v = StringVar(self.root, "abc", "name") + self.assertEqual("abc", v.get()) + self.root.globalsetvar("name", "value") + self.assertEqual("value", v.get()) + + def test_get_null(self): + v = StringVar(self.root, "abc\x00def", "name") + self.assertEqual("abc\x00def", v.get()) + self.root.globalsetvar("name", "val\x00ue") + self.assertEqual("val\x00ue", v.get()) + + +class TestIntVar(TestBase): + + def test_default(self): + v = IntVar(self.root) + self.assertEqual(0, v.get()) + + def test_get(self): + v = IntVar(self.root, 123, "name") + self.assertEqual(123, v.get()) + self.root.globalsetvar("name", "345") + self.assertEqual(345, v.get()) + self.root.globalsetvar("name", "876.5") + self.assertEqual(876, v.get()) + + def test_invalid_value(self): + v = IntVar(self.root, name="name") + self.root.globalsetvar("name", "value") + with self.assertRaises((ValueError, TclError)): + v.get() + + +class TestDoubleVar(TestBase): + + def test_default(self): + v = DoubleVar(self.root) + self.assertEqual(0.0, v.get()) + + def test_get(self): + v = DoubleVar(self.root, 1.23, "name") + self.assertAlmostEqual(1.23, v.get()) + self.root.globalsetvar("name", "3.45") + self.assertAlmostEqual(3.45, v.get()) + + def test_get_from_int(self): + v = DoubleVar(self.root, 1.23, "name") + self.assertAlmostEqual(1.23, v.get()) + self.root.globalsetvar("name", "3.45") + self.assertAlmostEqual(3.45, v.get()) + self.root.globalsetvar("name", "456") + self.assertAlmostEqual(456, v.get()) + + def test_invalid_value(self): + v = DoubleVar(self.root, name="name") + self.root.globalsetvar("name", "value") + with self.assertRaises((ValueError, TclError)): + v.get() + + +class TestBooleanVar(TestBase): + + def test_default(self): + v = BooleanVar(self.root) + self.assertIs(v.get(), False) + + def test_get(self): + v = BooleanVar(self.root, True, "name") + self.assertIs(v.get(), True) + self.root.globalsetvar("name", "0") + self.assertIs(v.get(), False) + self.root.globalsetvar("name", 42 if self.root.wantobjects() else 1) + self.assertIs(v.get(), True) + self.root.globalsetvar("name", 0) + self.assertIs(v.get(), False) + self.root.globalsetvar("name", "on") + self.assertIs(v.get(), True) + + def test_set(self): + true = 1 if self.root.wantobjects() else "1" + false = 0 if self.root.wantobjects() else "0" + v = BooleanVar(self.root, name="name") + v.set(True) + self.assertEqual(self.root.globalgetvar("name"), true) + v.set("0") + self.assertEqual(self.root.globalgetvar("name"), false) + v.set(42) + self.assertEqual(self.root.globalgetvar("name"), true) + v.set(0) + self.assertEqual(self.root.globalgetvar("name"), false) + v.set("on") + self.assertEqual(self.root.globalgetvar("name"), true) + + def test_invalid_value_domain(self): + false = 0 if self.root.wantobjects() else "0" + v = BooleanVar(self.root, name="name") + with self.assertRaises(TclError): + v.set("value") + self.assertEqual(self.root.globalgetvar("name"), false) + self.root.globalsetvar("name", "value") + with self.assertRaises(ValueError): + v.get() + self.root.globalsetvar("name", "1.0") + with self.assertRaises(ValueError): + 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) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py new file mode 100644 index 0000000..1cddbe1 --- /dev/null +++ b/Lib/test/test_tkinter/test_widgets.py @@ -0,0 +1,1292 @@ +import unittest +import tkinter +from tkinter import TclError +import os +from test.support import requires + +from test.test_tkinter.support import (requires_tcl, + get_tk_patchlevel, widget_eq, + AbstractDefaultRootTest) +from test.test_tkinter.widget_tests import ( + add_standard_options, + AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, + setUpModule) + +requires('gui') + + +def float_round(x): + return float(round(x)) + + +class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests): + _conv_pad_pixels = False + + def test_configure_class(self): + widget = self.create() + self.assertEqual(widget['class'], + widget.__class__.__name__.title()) + self.checkInvalidParam(widget, 'class', 'Foo', + errmsg="can't modify -class option after widget is created") + widget2 = self.create(class_='Foo') + self.assertEqual(widget2['class'], 'Foo') + + def test_configure_colormap(self): + widget = self.create() + self.assertEqual(widget['colormap'], '') + self.checkInvalidParam(widget, 'colormap', 'new', + errmsg="can't modify -colormap option after widget is created") + widget2 = self.create(colormap='new') + self.assertEqual(widget2['colormap'], 'new') + + def test_configure_container(self): + widget = self.create() + self.assertEqual(widget['container'], 0 if self.wantobjects else '0') + self.checkInvalidParam(widget, 'container', 1, + errmsg="can't modify -container option after widget is created") + widget2 = self.create(container=True) + self.assertEqual(widget2['container'], 1 if self.wantobjects else '1') + + def test_configure_visual(self): + widget = self.create() + self.assertEqual(widget['visual'], '') + self.checkInvalidParam(widget, 'visual', 'default', + errmsg="can't modify -visual option after widget is created") + widget2 = self.create(visual='default') + self.assertEqual(widget2['visual'], 'default') + + +@add_standard_options(StandardOptionsTests) +class ToplevelTest(AbstractToplevelTest, unittest.TestCase): + OPTIONS = ( + 'background', 'borderwidth', + 'class', 'colormap', 'container', 'cursor', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'menu', 'padx', 'pady', 'relief', 'screen', + 'takefocus', 'use', 'visual', 'width', + ) + + def create(self, **kwargs): + return tkinter.Toplevel(self.root, **kwargs) + + def test_configure_menu(self): + widget = self.create() + menu = tkinter.Menu(self.root) + self.checkParam(widget, 'menu', menu, eq=widget_eq) + self.checkParam(widget, 'menu', '') + + def test_configure_screen(self): + widget = self.create() + self.assertEqual(widget['screen'], '') + try: + display = os.environ['DISPLAY'] + except KeyError: + self.skipTest('No $DISPLAY set.') + self.checkInvalidParam(widget, 'screen', display, + errmsg="can't modify -screen option after widget is created") + widget2 = self.create(screen=display) + self.assertEqual(widget2['screen'], display) + + def test_configure_use(self): + widget = self.create() + self.assertEqual(widget['use'], '') + parent = self.create(container=True) + wid = hex(parent.winfo_id()) + with self.subTest(wid=wid): + widget2 = self.create(use=wid) + self.assertEqual(widget2['use'], wid) + + +@add_standard_options(StandardOptionsTests) +class FrameTest(AbstractToplevelTest, unittest.TestCase): + OPTIONS = ( + 'background', 'borderwidth', + 'class', 'colormap', 'container', 'cursor', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'padx', 'pady', 'relief', 'takefocus', 'visual', 'width', + ) + + def create(self, **kwargs): + return tkinter.Frame(self.root, **kwargs) + + +@add_standard_options(StandardOptionsTests) +class LabelFrameTest(AbstractToplevelTest, unittest.TestCase): + OPTIONS = ( + 'background', 'borderwidth', + 'class', 'colormap', 'container', 'cursor', + 'font', 'foreground', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'labelanchor', 'labelwidget', 'padx', 'pady', 'relief', + 'takefocus', 'text', 'visual', 'width', + ) + + def create(self, **kwargs): + return tkinter.LabelFrame(self.root, **kwargs) + + def test_configure_labelanchor(self): + widget = self.create() + self.checkEnumParam(widget, 'labelanchor', + 'e', 'en', 'es', 'n', 'ne', 'nw', + 's', 'se', 'sw', 'w', 'wn', 'ws') + self.checkInvalidParam(widget, 'labelanchor', 'center') + + def test_configure_labelwidget(self): + widget = self.create() + label = tkinter.Label(self.root, text='Mupp', name='foo') + self.checkParam(widget, 'labelwidget', label, expected='.foo') + label.destroy() + + +class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests): + _conv_pixels = False + + def test_configure_highlightthickness(self): + widget = self.create() + self.checkPixelsParam(widget, 'highlightthickness', + 0, 1.3, 2.6, 6, -2, '10p') + + +@add_standard_options(StandardOptionsTests) +class LabelTest(AbstractLabelTest, unittest.TestCase): + OPTIONS = ( + 'activebackground', 'activeforeground', 'anchor', + 'background', 'bitmap', 'borderwidth', 'compound', 'cursor', + 'disabledforeground', 'font', 'foreground', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'image', 'justify', 'padx', 'pady', 'relief', 'state', + 'takefocus', 'text', 'textvariable', + 'underline', 'width', 'wraplength', + ) + + def create(self, **kwargs): + return tkinter.Label(self.root, **kwargs) + + +@add_standard_options(StandardOptionsTests) +class ButtonTest(AbstractLabelTest, unittest.TestCase): + OPTIONS = ( + 'activebackground', 'activeforeground', 'anchor', + 'background', 'bitmap', 'borderwidth', + 'command', 'compound', 'cursor', 'default', + 'disabledforeground', 'font', 'foreground', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'image', 'justify', 'overrelief', 'padx', 'pady', 'relief', + 'repeatdelay', 'repeatinterval', + 'state', 'takefocus', 'text', 'textvariable', + 'underline', 'width', 'wraplength') + + def create(self, **kwargs): + return tkinter.Button(self.root, **kwargs) + + def test_configure_default(self): + widget = self.create() + self.checkEnumParam(widget, 'default', 'active', 'disabled', 'normal') + + +@add_standard_options(StandardOptionsTests) +class CheckbuttonTest(AbstractLabelTest, unittest.TestCase): + OPTIONS = ( + 'activebackground', 'activeforeground', 'anchor', + 'background', 'bitmap', 'borderwidth', + 'command', 'compound', 'cursor', + 'disabledforeground', 'font', 'foreground', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'image', 'indicatoron', 'justify', + 'offrelief', 'offvalue', 'onvalue', 'overrelief', + 'padx', 'pady', 'relief', 'selectcolor', 'selectimage', 'state', + 'takefocus', 'text', 'textvariable', + 'tristateimage', 'tristatevalue', + 'underline', 'variable', 'width', 'wraplength', + ) + + def create(self, **kwargs): + return tkinter.Checkbutton(self.root, **kwargs) + + + def test_configure_offvalue(self): + widget = self.create() + self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string') + + def test_configure_onvalue(self): + widget = self.create() + self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string') + + +@add_standard_options(StandardOptionsTests) +class RadiobuttonTest(AbstractLabelTest, unittest.TestCase): + OPTIONS = ( + 'activebackground', 'activeforeground', 'anchor', + 'background', 'bitmap', 'borderwidth', + 'command', 'compound', 'cursor', + 'disabledforeground', 'font', 'foreground', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'image', 'indicatoron', 'justify', 'offrelief', 'overrelief', + 'padx', 'pady', 'relief', 'selectcolor', 'selectimage', 'state', + 'takefocus', 'text', 'textvariable', + 'tristateimage', 'tristatevalue', + 'underline', 'value', 'variable', 'width', 'wraplength', + ) + + def create(self, **kwargs): + return tkinter.Radiobutton(self.root, **kwargs) + + def test_configure_value(self): + widget = self.create() + self.checkParams(widget, 'value', 1, 2.3, '', 'any string') + + +@add_standard_options(StandardOptionsTests) +class MenubuttonTest(AbstractLabelTest, unittest.TestCase): + OPTIONS = ( + 'activebackground', 'activeforeground', 'anchor', + 'background', 'bitmap', 'borderwidth', + 'compound', 'cursor', 'direction', + 'disabledforeground', 'font', 'foreground', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'image', 'indicatoron', 'justify', 'menu', + 'padx', 'pady', 'relief', 'state', + 'takefocus', 'text', 'textvariable', + 'underline', 'width', 'wraplength', + ) + _conv_pixels = round + + def create(self, **kwargs): + return tkinter.Menubutton(self.root, **kwargs) + + def test_configure_direction(self): + widget = self.create() + self.checkEnumParam(widget, 'direction', + 'above', 'below', 'flush', 'left', 'right') + + def test_configure_height(self): + widget = self.create() + self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str) + + test_configure_highlightthickness = \ + StandardOptionsTests.test_configure_highlightthickness + + def test_configure_image(self): + widget = self.create() + image = tkinter.PhotoImage(master=self.root, name='image1') + self.checkParam(widget, 'image', image, conv=str) + errmsg = 'image "spam" doesn\'t exist' + with self.assertRaises(tkinter.TclError) as cm: + widget['image'] = 'spam' + if errmsg is not None: + self.assertEqual(str(cm.exception), errmsg) + with self.assertRaises(tkinter.TclError) as cm: + widget.configure({'image': 'spam'}) + if errmsg is not None: + self.assertEqual(str(cm.exception), errmsg) + + def test_configure_menu(self): + widget = self.create() + menu = tkinter.Menu(widget, name='menu') + self.checkParam(widget, 'menu', menu, eq=widget_eq) + menu.destroy() + + def test_configure_padx(self): + widget = self.create() + self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m') + self.checkParam(widget, 'padx', -2, expected=0) + + def test_configure_pady(self): + widget = self.create() + self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m') + self.checkParam(widget, 'pady', -2, expected=0) + + def test_configure_width(self): + widget = self.create() + self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str) + + +class OptionMenuTest(MenubuttonTest, unittest.TestCase): + + def create(self, default='b', values=('a', 'b', 'c'), **kwargs): + return tkinter.OptionMenu(self.root, None, default, *values, **kwargs) + + def test_bad_kwarg(self): + with self.assertRaisesRegex(TclError, r"^unknown option -image$"): + tkinter.OptionMenu(self.root, None, 'b', image='') + + +@add_standard_options(IntegerSizeTests, StandardOptionsTests) +class EntryTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'background', 'borderwidth', 'cursor', + 'disabledbackground', 'disabledforeground', + 'exportselection', 'font', 'foreground', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'insertbackground', 'insertborderwidth', + 'insertofftime', 'insertontime', 'insertwidth', + 'invalidcommand', 'justify', 'readonlybackground', 'relief', + 'selectbackground', 'selectborderwidth', 'selectforeground', + 'show', 'state', 'takefocus', 'textvariable', + 'validate', 'validatecommand', 'width', 'xscrollcommand', + ) + + def create(self, **kwargs): + return tkinter.Entry(self.root, **kwargs) + + def test_configure_disabledbackground(self): + widget = self.create() + self.checkColorParam(widget, 'disabledbackground') + + def test_configure_insertborderwidth(self): + widget = self.create(insertwidth=100) + self.checkPixelsParam(widget, 'insertborderwidth', + 0, 1.3, 2.6, 6, -2, '10p') + # insertborderwidth is bounded above by a half of insertwidth. + self.checkParam(widget, 'insertborderwidth', 60, expected=100//2) + + def test_configure_insertwidth(self): + widget = self.create() + self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p') + self.checkParam(widget, 'insertwidth', 0.1, expected=2) + self.checkParam(widget, 'insertwidth', -2, expected=2) + self.checkParam(widget, 'insertwidth', 0.9, expected=1) + + def test_configure_invalidcommand(self): + widget = self.create() + self.checkCommandParam(widget, 'invalidcommand') + self.checkCommandParam(widget, 'invcmd') + + def test_configure_readonlybackground(self): + widget = self.create() + self.checkColorParam(widget, 'readonlybackground') + + def test_configure_show(self): + widget = self.create() + self.checkParam(widget, 'show', '*') + self.checkParam(widget, 'show', '') + self.checkParam(widget, 'show', ' ') + + def test_configure_state(self): + widget = self.create() + self.checkEnumParam(widget, 'state', + 'disabled', 'normal', 'readonly') + + def test_configure_validate(self): + widget = self.create() + self.checkEnumParam(widget, 'validate', + 'all', 'key', 'focus', 'focusin', 'focusout', 'none') + + def test_configure_validatecommand(self): + widget = self.create() + self.checkCommandParam(widget, 'validatecommand') + self.checkCommandParam(widget, 'vcmd') + + def test_selection_methods(self): + widget = self.create() + widget.insert(0, '12345') + self.assertFalse(widget.selection_present()) + widget.selection_range(0, 'end') + self.assertEqual(widget.selection_get(), '12345') + self.assertTrue(widget.selection_present()) + widget.selection_from(1) + widget.selection_to(2) + self.assertEqual(widget.selection_get(), '2') + widget.selection_range(3, 4) + self.assertEqual(widget.selection_get(), '4') + widget.selection_clear() + self.assertFalse(widget.selection_present()) + widget.selection_range(0, 'end') + widget.selection_adjust(4) + self.assertEqual(widget.selection_get(), '1234') + widget.selection_adjust(1) + self.assertEqual(widget.selection_get(), '234') + widget.selection_adjust(5) + self.assertEqual(widget.selection_get(), '2345') + widget.selection_adjust(0) + self.assertEqual(widget.selection_get(), '12345') + widget.selection_adjust(0) + + +@add_standard_options(StandardOptionsTests) +class SpinboxTest(EntryTest, unittest.TestCase): + OPTIONS = ( + 'activebackground', 'background', 'borderwidth', + 'buttonbackground', 'buttoncursor', 'buttondownrelief', 'buttonuprelief', + 'command', 'cursor', 'disabledbackground', 'disabledforeground', + 'exportselection', 'font', 'foreground', 'format', 'from', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'increment', + 'insertbackground', 'insertborderwidth', + 'insertofftime', 'insertontime', 'insertwidth', + 'invalidcommand', 'justify', 'relief', 'readonlybackground', + 'repeatdelay', 'repeatinterval', + 'selectbackground', 'selectborderwidth', 'selectforeground', + 'state', 'takefocus', 'textvariable', 'to', + 'validate', 'validatecommand', 'values', + 'width', 'wrap', 'xscrollcommand', + ) + + def create(self, **kwargs): + return tkinter.Spinbox(self.root, **kwargs) + + test_configure_show = None + + def test_configure_buttonbackground(self): + widget = self.create() + self.checkColorParam(widget, 'buttonbackground') + + def test_configure_buttoncursor(self): + widget = self.create() + self.checkCursorParam(widget, 'buttoncursor') + + def test_configure_buttondownrelief(self): + widget = self.create() + self.checkReliefParam(widget, 'buttondownrelief') + + def test_configure_buttonuprelief(self): + widget = self.create() + self.checkReliefParam(widget, 'buttonuprelief') + + def test_configure_format(self): + widget = self.create() + self.checkParam(widget, 'format', '%2f') + self.checkParam(widget, 'format', '%2.2f') + self.checkParam(widget, 'format', '%.2f') + self.checkParam(widget, 'format', '%2.f') + self.checkInvalidParam(widget, 'format', '%2e-1f') + self.checkInvalidParam(widget, 'format', '2.2') + self.checkInvalidParam(widget, 'format', '%2.-2f') + self.checkParam(widget, 'format', '%-2.02f') + self.checkParam(widget, 'format', '% 2.02f') + self.checkParam(widget, 'format', '% -2.200f') + self.checkParam(widget, 'format', '%09.200f') + self.checkInvalidParam(widget, 'format', '%d') + + def test_configure_from(self): + widget = self.create() + self.checkParam(widget, 'to', 100.0) + self.checkFloatParam(widget, 'from', -10, 10.2, 11.7) + self.checkInvalidParam(widget, 'from', 200, + errmsg='-to value must be greater than -from value') + + def test_configure_increment(self): + widget = self.create() + self.checkFloatParam(widget, 'increment', -1, 1, 10.2, 12.8, 0) + + def test_configure_to(self): + widget = self.create() + self.checkParam(widget, 'from', -100.0) + self.checkFloatParam(widget, 'to', -10, 10.2, 11.7) + self.checkInvalidParam(widget, 'to', -200, + errmsg='-to value must be greater than -from value') + + def test_configure_values(self): + # XXX + widget = self.create() + self.assertEqual(widget['values'], '') + self.checkParam(widget, 'values', 'mon tue wed thur') + self.checkParam(widget, 'values', ('mon', 'tue', 'wed', 'thur'), + expected='mon tue wed thur') + self.checkParam(widget, 'values', (42, 3.14, '', 'any string'), + expected='42 3.14 {} {any string}') + self.checkParam(widget, 'values', '') + + def test_configure_wrap(self): + widget = self.create() + self.checkBooleanParam(widget, 'wrap') + + def test_bbox(self): + widget = self.create() + self.assertIsBoundingBox(widget.bbox(0)) + self.assertRaises(tkinter.TclError, widget.bbox, 'noindex') + self.assertRaises(tkinter.TclError, widget.bbox, None) + self.assertRaises(TypeError, widget.bbox) + self.assertRaises(TypeError, widget.bbox, 0, 1) + + def test_selection_methods(self): + widget = self.create() + widget.insert(0, '12345') + self.assertFalse(widget.selection_present()) + widget.selection_range(0, 'end') + self.assertEqual(widget.selection_get(), '12345') + self.assertTrue(widget.selection_present()) + widget.selection_from(1) + widget.selection_to(2) + self.assertEqual(widget.selection_get(), '2') + widget.selection_range(3, 4) + self.assertEqual(widget.selection_get(), '4') + widget.selection_clear() + self.assertFalse(widget.selection_present()) + widget.selection_range(0, 'end') + widget.selection_adjust(4) + self.assertEqual(widget.selection_get(), '1234') + widget.selection_adjust(1) + self.assertEqual(widget.selection_get(), '234') + widget.selection_adjust(5) + self.assertEqual(widget.selection_get(), '2345') + widget.selection_adjust(0) + self.assertEqual(widget.selection_get(), '12345') + + def test_selection_element(self): + widget = self.create() + self.assertEqual(widget.selection_element(), "none") + widget.selection_element("buttonup") + self.assertEqual(widget.selection_element(), "buttonup") + widget.selection_element("buttondown") + self.assertEqual(widget.selection_element(), "buttondown") + + +@add_standard_options(StandardOptionsTests) +class TextTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'autoseparators', 'background', 'blockcursor', 'borderwidth', + 'cursor', 'endline', 'exportselection', + 'font', 'foreground', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'inactiveselectbackground', 'insertbackground', 'insertborderwidth', + 'insertofftime', 'insertontime', 'insertunfocussed', 'insertwidth', + 'maxundo', 'padx', 'pady', 'relief', + 'selectbackground', 'selectborderwidth', 'selectforeground', + 'setgrid', 'spacing1', 'spacing2', 'spacing3', 'startline', 'state', + 'tabs', 'tabstyle', 'takefocus', 'undo', 'width', 'wrap', + 'xscrollcommand', 'yscrollcommand', + ) + + def create(self, **kwargs): + return tkinter.Text(self.root, **kwargs) + + def test_configure_autoseparators(self): + widget = self.create() + self.checkBooleanParam(widget, 'autoseparators') + + def test_configure_blockcursor(self): + widget = self.create() + self.checkBooleanParam(widget, 'blockcursor') + + def test_configure_endline(self): + widget = self.create() + text = '\n'.join('Line %d' for i in range(100)) + widget.insert('end', text) + self.checkParam(widget, 'endline', 200, expected='') + self.checkParam(widget, 'endline', -10, expected='') + self.checkInvalidParam(widget, 'endline', 'spam', + errmsg='expected integer but got "spam"') + self.checkParam(widget, 'endline', 50) + self.checkParam(widget, 'startline', 15) + self.checkInvalidParam(widget, 'endline', 10, + errmsg='-startline must be less than or equal to -endline') + + def test_configure_height(self): + widget = self.create() + self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c') + self.checkParam(widget, 'height', -100, expected=1) + self.checkParam(widget, 'height', 0, expected=1) + + def test_configure_maxundo(self): + widget = self.create() + self.checkIntegerParam(widget, 'maxundo', 0, 5, -1) + + def test_configure_inactiveselectbackground(self): + widget = self.create() + self.checkColorParam(widget, 'inactiveselectbackground') + + @requires_tcl(8, 6) + def test_configure_insertunfocussed(self): + widget = self.create() + self.checkEnumParam(widget, 'insertunfocussed', + 'hollow', 'none', 'solid') + + def test_configure_selectborderwidth(self): + widget = self.create() + self.checkPixelsParam(widget, 'selectborderwidth', + 1.3, 2.6, -2, '10p', conv=False) + + def test_configure_spacing1(self): + widget = self.create() + self.checkPixelsParam(widget, 'spacing1', 20, 21.4, 22.6, '0.5c') + self.checkParam(widget, 'spacing1', -5, expected=0) + + def test_configure_spacing2(self): + widget = self.create() + self.checkPixelsParam(widget, 'spacing2', 5, 6.4, 7.6, '0.1c') + self.checkParam(widget, 'spacing2', -1, expected=0) + + def test_configure_spacing3(self): + widget = self.create() + self.checkPixelsParam(widget, 'spacing3', 20, 21.4, 22.6, '0.5c') + self.checkParam(widget, 'spacing3', -10, expected=0) + + def test_configure_startline(self): + widget = self.create() + text = '\n'.join('Line %d' for i in range(100)) + widget.insert('end', text) + self.checkParam(widget, 'startline', 200, expected='') + self.checkParam(widget, 'startline', -10, expected='') + self.checkInvalidParam(widget, 'startline', 'spam', + errmsg='expected integer but got "spam"') + self.checkParam(widget, 'startline', 10) + self.checkParam(widget, 'endline', 50) + self.checkInvalidParam(widget, 'startline', 70, + errmsg='-startline must be less than or equal to -endline') + + def test_configure_state(self): + widget = self.create() + self.checkEnumParam(widget, 'state', 'disabled', 'normal') + + def test_configure_tabs(self): + widget = self.create() + self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i')) + self.checkParam(widget, 'tabs', '10.2 20.7 1i 2i', + expected=('10.2', '20.7', '1i', '2i')) + self.checkParam(widget, 'tabs', '2c left 4c 6c center', + expected=('2c', 'left', '4c', '6c', 'center')) + self.checkInvalidParam(widget, 'tabs', 'spam', + errmsg='bad screen distance "spam"') + + def test_configure_tabstyle(self): + widget = self.create() + self.checkEnumParam(widget, 'tabstyle', 'tabular', 'wordprocessor') + + def test_configure_undo(self): + widget = self.create() + self.checkBooleanParam(widget, 'undo') + + def test_configure_width(self): + widget = self.create() + self.checkIntegerParam(widget, 'width', 402) + self.checkParam(widget, 'width', -402, expected=1) + self.checkParam(widget, 'width', 0, expected=1) + + def test_configure_wrap(self): + widget = self.create() + self.checkEnumParam(widget, 'wrap', 'char', 'none', 'word') + + def test_bbox(self): + widget = self.create() + self.assertIsBoundingBox(widget.bbox('1.1')) + self.assertIsNone(widget.bbox('end')) + self.assertRaises(tkinter.TclError, widget.bbox, 'noindex') + self.assertRaises(tkinter.TclError, widget.bbox, None) + self.assertRaises(TypeError, widget.bbox) + self.assertRaises(TypeError, widget.bbox, '1.1', 'end') + + +@add_standard_options(PixelSizeTests, StandardOptionsTests) +class CanvasTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'background', 'borderwidth', + 'closeenough', 'confine', 'cursor', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'insertbackground', 'insertborderwidth', + 'insertofftime', 'insertontime', 'insertwidth', + 'offset', 'relief', 'scrollregion', + 'selectbackground', 'selectborderwidth', 'selectforeground', + 'state', 'takefocus', + 'xscrollcommand', 'xscrollincrement', + 'yscrollcommand', 'yscrollincrement', 'width', + ) + + _conv_pixels = round + _stringify = True + + def create(self, **kwargs): + return tkinter.Canvas(self.root, **kwargs) + + def test_configure_closeenough(self): + widget = self.create() + self.checkFloatParam(widget, 'closeenough', 24, 2.4, 3.6, -3, + conv=float) + + def test_configure_confine(self): + widget = self.create() + self.checkBooleanParam(widget, 'confine') + + def test_configure_offset(self): + widget = self.create() + self.assertEqual(widget['offset'], '0,0') + self.checkParams(widget, 'offset', + 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center') + self.checkParam(widget, 'offset', '10,20') + self.checkParam(widget, 'offset', '#5,6') + self.checkInvalidParam(widget, 'offset', 'spam') + + def test_configure_scrollregion(self): + widget = self.create() + self.checkParam(widget, 'scrollregion', '0 0 200 150') + self.checkParam(widget, 'scrollregion', (0, 0, 200, 150), + expected='0 0 200 150') + self.checkParam(widget, 'scrollregion', '') + self.checkInvalidParam(widget, 'scrollregion', 'spam', + errmsg='bad scrollRegion "spam"') + self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 'spam')) + self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200)) + self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 150, 0)) + + def test_configure_state(self): + widget = self.create() + self.checkEnumParam(widget, 'state', 'disabled', 'normal', + errmsg='bad state value "{}": must be normal or disabled') + + def test_configure_xscrollincrement(self): + widget = self.create() + self.checkPixelsParam(widget, 'xscrollincrement', + 40, 0, 41.2, 43.6, -40, '0.5i') + + def test_configure_yscrollincrement(self): + widget = self.create() + self.checkPixelsParam(widget, 'yscrollincrement', + 10, 0, 11.2, 13.6, -10, '0.1i') + + @requires_tcl(8, 6) + def test_moveto(self): + widget = self.create() + i1 = widget.create_rectangle(1, 1, 20, 20, tags='group') + i2 = widget.create_rectangle(30, 30, 50, 70, tags='group') + x1, y1, _, _ = widget.bbox(i1) + x2, y2, _, _ = widget.bbox(i2) + widget.moveto('group', 200, 100) + x1_2, y1_2, _, _ = widget.bbox(i1) + x2_2, y2_2, _, _ = widget.bbox(i2) + self.assertEqual(x1_2, 200) + self.assertEqual(y1_2, 100) + self.assertEqual(x2 - x1, x2_2 - x1_2) + self.assertEqual(y2 - y1, y2_2 - y1_2) + widget.tag_lower(i2, i1) + widget.moveto('group', y=50) + x1_3, y1_3, _, _ = widget.bbox(i1) + x2_3, y2_3, _, _ = widget.bbox(i2) + self.assertEqual(y2_3, 50) + self.assertEqual(x2_3, x2_2) + self.assertEqual(x2_2 - x1_2, x2_3 - x1_3) + self.assertEqual(y2_2 - y1_2, y2_3 - y1_3) + + +@add_standard_options(IntegerSizeTests, StandardOptionsTests) +class ListboxTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'activestyle', 'background', 'borderwidth', 'cursor', + 'disabledforeground', 'exportselection', + 'font', 'foreground', 'height', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'justify', 'listvariable', 'relief', + 'selectbackground', 'selectborderwidth', 'selectforeground', + 'selectmode', 'setgrid', 'state', + 'takefocus', 'width', 'xscrollcommand', 'yscrollcommand', + ) + + def create(self, **kwargs): + return tkinter.Listbox(self.root, **kwargs) + + def test_configure_activestyle(self): + widget = self.create() + self.checkEnumParam(widget, 'activestyle', + 'dotbox', 'none', 'underline') + + test_configure_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify) + + def test_configure_listvariable(self): + widget = self.create() + var = tkinter.DoubleVar(self.root) + self.checkVariableParam(widget, 'listvariable', var) + + def test_configure_selectmode(self): + widget = self.create() + self.checkParam(widget, 'selectmode', 'single') + self.checkParam(widget, 'selectmode', 'browse') + self.checkParam(widget, 'selectmode', 'multiple') + self.checkParam(widget, 'selectmode', 'extended') + + def test_configure_state(self): + widget = self.create() + self.checkEnumParam(widget, 'state', 'disabled', 'normal') + + def test_itemconfigure(self): + widget = self.create() + with self.assertRaisesRegex(TclError, 'item number "0" out of range'): + widget.itemconfigure(0) + colors = 'red orange yellow green blue white violet'.split() + widget.insert('end', *colors) + for i, color in enumerate(colors): + widget.itemconfigure(i, background=color) + with self.assertRaises(TypeError): + widget.itemconfigure() + with self.assertRaisesRegex(TclError, 'bad listbox index "red"'): + widget.itemconfigure('red') + self.assertEqual(widget.itemconfigure(0, 'background'), + ('background', 'background', 'Background', '', 'red')) + self.assertEqual(widget.itemconfigure('end', 'background'), + ('background', 'background', 'Background', '', 'violet')) + self.assertEqual(widget.itemconfigure('@0,0', 'background'), + ('background', 'background', 'Background', '', 'red')) + + d = widget.itemconfigure(0) + self.assertIsInstance(d, dict) + for k, v in d.items(): + self.assertIn(len(v), (2, 5)) + if len(v) == 5: + self.assertEqual(v, widget.itemconfigure(0, k)) + self.assertEqual(v[4], widget.itemcget(0, k)) + + def check_itemconfigure(self, name, value): + widget = self.create() + widget.insert('end', 'a', 'b', 'c', 'd') + widget.itemconfigure(0, **{name: value}) + self.assertEqual(widget.itemconfigure(0, name)[4], value) + self.assertEqual(widget.itemcget(0, name), value) + with self.assertRaisesRegex(TclError, 'unknown color name "spam"'): + widget.itemconfigure(0, **{name: 'spam'}) + + def test_itemconfigure_background(self): + self.check_itemconfigure('background', '#ff0000') + + def test_itemconfigure_bg(self): + self.check_itemconfigure('bg', '#ff0000') + + def test_itemconfigure_fg(self): + self.check_itemconfigure('fg', '#110022') + + def test_itemconfigure_foreground(self): + self.check_itemconfigure('foreground', '#110022') + + def test_itemconfigure_selectbackground(self): + self.check_itemconfigure('selectbackground', '#110022') + + def test_itemconfigure_selectforeground(self): + self.check_itemconfigure('selectforeground', '#654321') + + def test_box(self): + lb = self.create() + lb.insert(0, *('el%d' % i for i in range(8))) + lb.pack() + self.assertIsBoundingBox(lb.bbox(0)) + self.assertIsNone(lb.bbox(-1)) + self.assertIsNone(lb.bbox(10)) + self.assertRaises(TclError, lb.bbox, 'noindex') + self.assertRaises(TclError, lb.bbox, None) + self.assertRaises(TypeError, lb.bbox) + self.assertRaises(TypeError, lb.bbox, 0, 1) + + def test_curselection(self): + lb = self.create() + lb.insert(0, *('el%d' % i for i in range(8))) + lb.selection_clear(0, tkinter.END) + lb.selection_set(2, 4) + lb.selection_set(6) + self.assertEqual(lb.curselection(), (2, 3, 4, 6)) + self.assertRaises(TypeError, lb.curselection, 0) + + def test_get(self): + lb = self.create() + lb.insert(0, *('el%d' % i for i in range(8))) + self.assertEqual(lb.get(0), 'el0') + self.assertEqual(lb.get(3), 'el3') + self.assertEqual(lb.get('end'), 'el7') + self.assertEqual(lb.get(8), '') + self.assertEqual(lb.get(-1), '') + self.assertEqual(lb.get(3, 5), ('el3', 'el4', 'el5')) + self.assertEqual(lb.get(5, 'end'), ('el5', 'el6', 'el7')) + self.assertEqual(lb.get(5, 0), ()) + self.assertEqual(lb.get(0, 0), ('el0',)) + self.assertRaises(TclError, lb.get, 'noindex') + self.assertRaises(TclError, lb.get, None) + self.assertRaises(TypeError, lb.get) + self.assertRaises(TclError, lb.get, 'end', 'noindex') + self.assertRaises(TypeError, lb.get, 1, 2, 3) + self.assertRaises(TclError, lb.get, 2.4) + + +@add_standard_options(PixelSizeTests, StandardOptionsTests) +class ScaleTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'activebackground', 'background', 'bigincrement', 'borderwidth', + 'command', 'cursor', 'digits', 'font', 'foreground', 'from', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'label', 'length', 'orient', 'relief', + 'repeatdelay', 'repeatinterval', + 'resolution', 'showvalue', 'sliderlength', 'sliderrelief', 'state', + 'takefocus', 'tickinterval', 'to', 'troughcolor', 'variable', 'width', + ) + default_orient = 'vertical' + + def create(self, **kwargs): + return tkinter.Scale(self.root, **kwargs) + + def test_configure_bigincrement(self): + widget = self.create() + self.checkFloatParam(widget, 'bigincrement', 12.4, 23.6, -5) + + def test_configure_digits(self): + widget = self.create() + self.checkIntegerParam(widget, 'digits', 5, 0) + + def test_configure_from(self): + widget = self.create() + conv = float if get_tk_patchlevel() >= (8, 6, 10) else float_round + self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv) + + def test_configure_label(self): + widget = self.create() + self.checkParam(widget, 'label', 'any string') + self.checkParam(widget, 'label', '') + + def test_configure_length(self): + widget = self.create() + self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i') + + def test_configure_resolution(self): + widget = self.create() + self.checkFloatParam(widget, 'resolution', 4.2, 0, 6.7, -2) + + def test_configure_showvalue(self): + widget = self.create() + self.checkBooleanParam(widget, 'showvalue') + + def test_configure_sliderlength(self): + widget = self.create() + self.checkPixelsParam(widget, 'sliderlength', + 10, 11.2, 15.6, -3, '3m') + + def test_configure_sliderrelief(self): + widget = self.create() + self.checkReliefParam(widget, 'sliderrelief') + + def test_configure_tickinterval(self): + widget = self.create() + self.checkFloatParam(widget, 'tickinterval', 1, 4.3, 7.6, 0, + conv=float_round) + self.checkParam(widget, 'tickinterval', -2, expected=2, + conv=float_round) + + def test_configure_to(self): + widget = self.create() + self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, + conv=float_round) + + +@add_standard_options(PixelSizeTests, StandardOptionsTests) +class ScrollbarTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'activebackground', 'activerelief', + 'background', 'borderwidth', + 'command', 'cursor', 'elementborderwidth', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'jump', 'orient', 'relief', + 'repeatdelay', 'repeatinterval', + 'takefocus', 'troughcolor', 'width', + ) + _conv_pixels = round + _stringify = True + default_orient = 'vertical' + + def create(self, **kwargs): + return tkinter.Scrollbar(self.root, **kwargs) + + def test_configure_activerelief(self): + widget = self.create() + self.checkReliefParam(widget, 'activerelief') + + def test_configure_elementborderwidth(self): + widget = self.create() + self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m') + + def test_configure_orient(self): + widget = self.create() + self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal', + errmsg='bad orientation "{}": must be vertical or horizontal') + + def test_activate(self): + sb = self.create() + for e in ('arrow1', 'slider', 'arrow2'): + sb.activate(e) + self.assertEqual(sb.activate(), e) + sb.activate('') + self.assertIsNone(sb.activate()) + self.assertRaises(TypeError, sb.activate, 'arrow1', 'arrow2') + + def test_set(self): + sb = self.create() + sb.set(0.2, 0.4) + self.assertEqual(sb.get(), (0.2, 0.4)) + self.assertRaises(TclError, sb.set, 'abc', 'def') + self.assertRaises(TclError, sb.set, 0.6, 'def') + self.assertRaises(TclError, sb.set, 0.6, None) + self.assertRaises(TypeError, sb.set, 0.6) + self.assertRaises(TypeError, sb.set, 0.6, 0.7, 0.8) + + +@add_standard_options(StandardOptionsTests) +class PanedWindowTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'background', 'borderwidth', 'cursor', + 'handlepad', 'handlesize', 'height', + 'opaqueresize', 'orient', + 'proxybackground', 'proxyborderwidth', 'proxyrelief', + 'relief', + 'sashcursor', 'sashpad', 'sashrelief', 'sashwidth', + 'showhandle', 'width', + ) + default_orient = 'horizontal' + + def create(self, **kwargs): + return tkinter.PanedWindow(self.root, **kwargs) + + def test_configure_handlepad(self): + widget = self.create() + self.checkPixelsParam(widget, 'handlepad', 5, 6.4, 7.6, -3, '1m') + + def test_configure_handlesize(self): + widget = self.create() + self.checkPixelsParam(widget, 'handlesize', 8, 9.4, 10.6, -3, '2m', + conv=False) + + def test_configure_height(self): + widget = self.create() + self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i', + conv=False) + + def test_configure_opaqueresize(self): + widget = self.create() + self.checkBooleanParam(widget, 'opaqueresize') + + @requires_tcl(8, 6, 5) + def test_configure_proxybackground(self): + widget = self.create() + self.checkColorParam(widget, 'proxybackground') + + @requires_tcl(8, 6, 5) + def test_configure_proxyborderwidth(self): + widget = self.create() + self.checkPixelsParam(widget, 'proxyborderwidth', + 0, 1.3, 2.9, 6, -2, '10p', + conv=False) + + @requires_tcl(8, 6, 5) + def test_configure_proxyrelief(self): + widget = self.create() + self.checkReliefParam(widget, 'proxyrelief') + + def test_configure_sashcursor(self): + widget = self.create() + self.checkCursorParam(widget, 'sashcursor') + + def test_configure_sashpad(self): + widget = self.create() + self.checkPixelsParam(widget, 'sashpad', 8, 1.3, 2.6, -2, '2m') + + def test_configure_sashrelief(self): + widget = self.create() + self.checkReliefParam(widget, 'sashrelief') + + def test_configure_sashwidth(self): + widget = self.create() + self.checkPixelsParam(widget, 'sashwidth', 10, 11.1, 15.6, -3, '1m', + conv=False) + + def test_configure_showhandle(self): + widget = self.create() + self.checkBooleanParam(widget, 'showhandle') + + def test_configure_width(self): + widget = self.create() + self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i', + conv=False) + + def create2(self): + p = self.create() + b = tkinter.Button(p) + c = tkinter.Button(p) + p.add(b) + p.add(c) + return p, b, c + + def test_paneconfigure(self): + p, b, c = self.create2() + self.assertRaises(TypeError, p.paneconfigure) + d = p.paneconfigure(b) + self.assertIsInstance(d, dict) + for k, v in d.items(): + self.assertEqual(len(v), 5) + self.assertEqual(v, p.paneconfigure(b, k)) + self.assertEqual(v[4], p.panecget(b, k)) + + def check_paneconfigure(self, p, b, name, value, expected): + if not self.wantobjects: + expected = str(expected) + p.paneconfigure(b, **{name: value}) + self.assertEqual(p.paneconfigure(b, name)[4], expected) + self.assertEqual(p.panecget(b, name), expected) + + def check_paneconfigure_bad(self, p, b, name, msg): + with self.assertRaisesRegex(TclError, msg): + p.paneconfigure(b, **{name: 'badValue'}) + + def test_paneconfigure_after(self): + p, b, c = self.create2() + self.check_paneconfigure(p, b, 'after', c, str(c)) + self.check_paneconfigure_bad(p, b, 'after', + 'bad window path name "badValue"') + + def test_paneconfigure_before(self): + p, b, c = self.create2() + self.check_paneconfigure(p, b, 'before', c, str(c)) + self.check_paneconfigure_bad(p, b, 'before', + 'bad window path name "badValue"') + + def test_paneconfigure_height(self): + p, b, c = self.create2() + self.check_paneconfigure(p, b, 'height', 10, 10) + self.check_paneconfigure_bad(p, b, 'height', + 'bad screen distance "badValue"') + + def test_paneconfigure_hide(self): + p, b, c = self.create2() + self.check_paneconfigure(p, b, 'hide', False, 0) + self.check_paneconfigure_bad(p, b, 'hide', + 'expected boolean value but got "badValue"') + + def test_paneconfigure_minsize(self): + p, b, c = self.create2() + self.check_paneconfigure(p, b, 'minsize', 10, 10) + self.check_paneconfigure_bad(p, b, 'minsize', + 'bad screen distance "badValue"') + + def test_paneconfigure_padx(self): + p, b, c = self.create2() + self.check_paneconfigure(p, b, 'padx', 1.3, 1) + self.check_paneconfigure_bad(p, b, 'padx', + 'bad screen distance "badValue"') + + def test_paneconfigure_pady(self): + p, b, c = self.create2() + self.check_paneconfigure(p, b, 'pady', 1.3, 1) + self.check_paneconfigure_bad(p, b, 'pady', + 'bad screen distance "badValue"') + + def test_paneconfigure_sticky(self): + p, b, c = self.create2() + self.check_paneconfigure(p, b, 'sticky', 'nsew', 'nesw') + self.check_paneconfigure_bad(p, b, 'sticky', + 'bad stickyness value "badValue": must ' + 'be a string containing zero or more of ' + 'n, e, s, and w') + + def test_paneconfigure_stretch(self): + p, b, c = self.create2() + self.check_paneconfigure(p, b, 'stretch', 'alw', 'always') + self.check_paneconfigure_bad(p, b, 'stretch', + 'bad stretch "badValue": must be ' + 'always, first, last, middle, or never') + + def test_paneconfigure_width(self): + p, b, c = self.create2() + self.check_paneconfigure(p, b, 'width', 10, 10) + self.check_paneconfigure_bad(p, b, 'width', + 'bad screen distance "badValue"') + + +@add_standard_options(StandardOptionsTests) +class MenuTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'activebackground', 'activeborderwidth', 'activeforeground', + 'background', 'borderwidth', 'cursor', + 'disabledforeground', 'font', 'foreground', + 'postcommand', 'relief', 'selectcolor', 'takefocus', + 'tearoff', 'tearoffcommand', 'title', 'type', + ) + _conv_pixels = False + + def create(self, **kwargs): + return tkinter.Menu(self.root, **kwargs) + + def test_configure_postcommand(self): + widget = self.create() + self.checkCommandParam(widget, 'postcommand') + + def test_configure_tearoff(self): + widget = self.create() + self.checkBooleanParam(widget, 'tearoff') + + def test_configure_tearoffcommand(self): + widget = self.create() + self.checkCommandParam(widget, 'tearoffcommand') + + def test_configure_title(self): + widget = self.create() + self.checkParam(widget, 'title', 'any string') + + def test_configure_type(self): + widget = self.create() + self.checkEnumParam( + widget, 'type', + 'normal', 'tearoff', 'menubar', + errmsg='bad type "{}": must be normal, tearoff, or menubar', + ) + + def test_entryconfigure(self): + m1 = self.create() + m1.add_command(label='test') + self.assertRaises(TypeError, m1.entryconfigure) + with self.assertRaisesRegex(TclError, 'bad menu entry index "foo"'): + m1.entryconfigure('foo') + d = m1.entryconfigure(1) + self.assertIsInstance(d, dict) + for k, v in d.items(): + self.assertIsInstance(k, str) + self.assertIsInstance(v, tuple) + self.assertEqual(len(v), 5) + self.assertEqual(v[0], k) + self.assertEqual(m1.entrycget(1, k), v[4]) + m1.destroy() + + def test_entryconfigure_label(self): + m1 = self.create() + m1.add_command(label='test') + self.assertEqual(m1.entrycget(1, 'label'), 'test') + m1.entryconfigure(1, label='changed') + self.assertEqual(m1.entrycget(1, 'label'), 'changed') + + def test_entryconfigure_variable(self): + m1 = self.create() + v1 = tkinter.BooleanVar(self.root) + v2 = tkinter.BooleanVar(self.root) + m1.add_checkbutton(variable=v1, onvalue=True, offvalue=False, + label='Nonsense') + self.assertEqual(str(m1.entrycget(1, 'variable')), str(v1)) + m1.entryconfigure(1, variable=v2) + self.assertEqual(str(m1.entrycget(1, 'variable')), str(v2)) + + +@add_standard_options(PixelSizeTests, StandardOptionsTests) +class MessageTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'anchor', 'aspect', 'background', 'borderwidth', + 'cursor', 'font', 'foreground', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'justify', 'padx', 'pady', 'relief', + 'takefocus', 'text', 'textvariable', 'width', + ) + _conv_pad_pixels = False + + def create(self, **kwargs): + return tkinter.Message(self.root, **kwargs) + + def test_configure_aspect(self): + widget = self.create() + 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, DefaultRootTest, +) + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py new file mode 100644 index 0000000..85b0511 --- /dev/null +++ b/Lib/test/test_tkinter/widget_tests.py @@ -0,0 +1,519 @@ +# Common tests for test_tkinter/test_widgets.py and test_ttk/test_widgets.py + +import tkinter +from test.test_tkinter.support import (AbstractTkTest, tcl_version, + pixels_conv, tcl_obj_eq) +import test.support + + +_sentinel = object() + +class AbstractWidgetTest(AbstractTkTest): + _conv_pixels = round + _conv_pad_pixels = None + _stringify = False + + @property + def scaling(self): + try: + return self._scaling + except AttributeError: + self._scaling = float(self.root.call('tk', 'scaling')) + return self._scaling + + def _str(self, value): + if not self._stringify and self.wantobjects and tcl_version >= (8, 6): + return value + if isinstance(value, tuple): + return ' '.join(map(self._str, value)) + return str(value) + + def assertEqual2(self, actual, expected, msg=None, eq=object.__eq__): + if eq(actual, expected): + return + self.assertEqual(actual, expected, msg) + + def checkParam(self, widget, name, value, *, expected=_sentinel, + conv=False, eq=None): + widget[name] = value + if expected is _sentinel: + expected = value + if conv: + expected = conv(expected) + if self._stringify or not self.wantobjects: + if isinstance(expected, tuple): + expected = tkinter._join(expected) + else: + expected = str(expected) + if eq is None: + eq = tcl_obj_eq + self.assertEqual2(widget[name], expected, eq=eq) + self.assertEqual2(widget.cget(name), expected, eq=eq) + t = widget.configure(name) + self.assertEqual(len(t), 5) + self.assertEqual2(t[4], expected, eq=eq) + + def checkInvalidParam(self, widget, name, value, errmsg=None): + orig = widget[name] + if errmsg is not None: + errmsg = errmsg.format(value) + with self.assertRaises(tkinter.TclError) as cm: + widget[name] = value + if errmsg is not None: + self.assertEqual(str(cm.exception), errmsg) + self.assertEqual(widget[name], orig) + with self.assertRaises(tkinter.TclError) as cm: + widget.configure({name: value}) + if errmsg is not None: + self.assertEqual(str(cm.exception), errmsg) + self.assertEqual(widget[name], orig) + + def checkParams(self, widget, name, *values, **kwargs): + for value in values: + self.checkParam(widget, name, value, **kwargs) + + def checkIntegerParam(self, widget, name, *values, **kwargs): + self.checkParams(widget, name, *values, **kwargs) + self.checkInvalidParam(widget, name, '', + errmsg='expected integer but got ""') + self.checkInvalidParam(widget, name, '10p', + errmsg='expected integer but got "10p"') + self.checkInvalidParam(widget, name, 3.2, + errmsg='expected integer but got "3.2"') + + def checkFloatParam(self, widget, name, *values, conv=float, **kwargs): + for value in values: + self.checkParam(widget, name, value, conv=conv, **kwargs) + self.checkInvalidParam(widget, name, '', + errmsg='expected floating-point number but got ""') + self.checkInvalidParam(widget, name, 'spam', + errmsg='expected floating-point number but got "spam"') + + def checkBooleanParam(self, widget, name): + for value in (False, 0, 'false', 'no', 'off'): + self.checkParam(widget, name, value, expected=0) + for value in (True, 1, 'true', 'yes', 'on'): + self.checkParam(widget, name, value, expected=1) + self.checkInvalidParam(widget, name, '', + errmsg='expected boolean value but got ""') + self.checkInvalidParam(widget, name, 'spam', + errmsg='expected boolean value but got "spam"') + + def checkColorParam(self, widget, name, *, allow_empty=None, **kwargs): + self.checkParams(widget, name, + '#ff0000', '#00ff00', '#0000ff', '#123456', + 'red', 'green', 'blue', 'white', 'black', 'grey', + **kwargs) + self.checkInvalidParam(widget, name, 'spam', + errmsg='unknown color name "spam"') + + def checkCursorParam(self, widget, name, **kwargs): + self.checkParams(widget, name, 'arrow', 'watch', 'cross', '',**kwargs) + self.checkParam(widget, name, 'none') + self.checkInvalidParam(widget, name, 'spam', + errmsg='bad cursor spec "spam"') + + def checkCommandParam(self, widget, name): + def command(*args): + pass + widget[name] = command + self.assertTrue(widget[name]) + self.checkParams(widget, name, '') + + def checkEnumParam(self, widget, name, *values, errmsg=None, **kwargs): + self.checkParams(widget, name, *values, **kwargs) + if errmsg is None: + errmsg2 = ' %s "{}": must be %s%s or %s' % ( + name, + ', '.join(values[:-1]), + ',' if len(values) > 2 else '', + values[-1]) + self.checkInvalidParam(widget, name, '', + errmsg='ambiguous' + errmsg2) + errmsg = 'bad' + errmsg2 + self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) + + def checkPixelsParam(self, widget, name, *values, + conv=None, **kwargs): + if conv is None: + conv = self._conv_pixels + for value in values: + expected = _sentinel + conv1 = conv + if isinstance(value, str): + if conv1 and conv1 is not str: + expected = pixels_conv(value) * self.scaling + conv1 = round + self.checkParam(widget, name, value, expected=expected, + conv=conv1, **kwargs) + self.checkInvalidParam(widget, name, '6x', + errmsg='bad screen distance "6x"') + self.checkInvalidParam(widget, name, 'spam', + errmsg='bad screen distance "spam"') + + def checkReliefParam(self, widget, name): + self.checkParams(widget, name, + 'flat', 'groove', 'raised', 'ridge', 'solid', 'sunken') + errmsg='bad relief "spam": must be '\ + 'flat, groove, raised, ridge, solid, or sunken' + if tcl_version < (8, 6): + errmsg = None + self.checkInvalidParam(widget, name, 'spam', + errmsg=errmsg) + + def checkImageParam(self, widget, name): + image = tkinter.PhotoImage(master=self.root, name='image1') + self.checkParam(widget, name, image, conv=str) + self.checkInvalidParam(widget, name, 'spam', + errmsg='image "spam" doesn\'t exist') + widget[name] = '' + + def checkVariableParam(self, widget, name, var): + self.checkParam(widget, name, var, conv=str) + + def assertIsBoundingBox(self, bbox): + self.assertIsNotNone(bbox) + self.assertIsInstance(bbox, tuple) + if len(bbox) != 4: + self.fail('Invalid bounding box: %r' % (bbox,)) + for item in bbox: + if not isinstance(item, int): + self.fail('Invalid bounding box: %r' % (bbox,)) + break + + + def test_keys(self): + widget = self.create() + keys = widget.keys() + self.assertEqual(sorted(keys), sorted(widget.configure())) + for k in keys: + widget[k] + # Test if OPTIONS contains all keys + if test.support.verbose: + aliases = { + 'bd': 'borderwidth', + 'bg': 'background', + 'fg': 'foreground', + 'invcmd': 'invalidcommand', + 'vcmd': 'validatecommand', + } + keys = set(keys) + expected = set(self.OPTIONS) + for k in sorted(keys - expected): + if not (k in aliases and + aliases[k] in keys and + aliases[k] in expected): + print('%s.OPTIONS doesn\'t contain "%s"' % + (self.__class__.__name__, k)) + + +class StandardOptionsTests: + STANDARD_OPTIONS = ( + 'activebackground', 'activeborderwidth', 'activeforeground', 'anchor', + 'background', 'bitmap', 'borderwidth', 'compound', 'cursor', + 'disabledforeground', 'exportselection', 'font', 'foreground', + 'highlightbackground', 'highlightcolor', 'highlightthickness', + 'image', 'insertbackground', 'insertborderwidth', + 'insertofftime', 'insertontime', 'insertwidth', + 'jump', 'justify', 'orient', 'padx', 'pady', 'relief', + 'repeatdelay', 'repeatinterval', + 'selectbackground', 'selectborderwidth', 'selectforeground', + 'setgrid', 'takefocus', 'text', 'textvariable', 'troughcolor', + 'underline', 'wraplength', 'xscrollcommand', 'yscrollcommand', + ) + + def test_configure_activebackground(self): + widget = self.create() + self.checkColorParam(widget, 'activebackground') + + def test_configure_activeborderwidth(self): + widget = self.create() + self.checkPixelsParam(widget, 'activeborderwidth', + 0, 1.3, 2.9, 6, -2, '10p') + + def test_configure_activeforeground(self): + widget = self.create() + self.checkColorParam(widget, 'activeforeground') + + def test_configure_anchor(self): + widget = self.create() + self.checkEnumParam(widget, 'anchor', + 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center') + + def test_configure_background(self): + widget = self.create() + self.checkColorParam(widget, 'background') + if 'bg' in self.OPTIONS: + self.checkColorParam(widget, 'bg') + + def test_configure_bitmap(self): + widget = self.create() + self.checkParam(widget, 'bitmap', 'questhead') + self.checkParam(widget, 'bitmap', 'gray50') + filename = test.support.findfile('python.xbm', subdir='imghdrdata') + self.checkParam(widget, 'bitmap', '@' + filename) + # Cocoa Tk widgets don't detect invalid -bitmap values + # See https://core.tcl.tk/tk/info/31cd33dbf0 + if not ('aqua' in self.root.tk.call('tk', 'windowingsystem') and + 'AppKit' in self.root.winfo_server()): + self.checkInvalidParam(widget, 'bitmap', 'spam', + errmsg='bitmap "spam" not defined') + + def test_configure_borderwidth(self): + widget = self.create() + self.checkPixelsParam(widget, 'borderwidth', + 0, 1.3, 2.6, 6, -2, '10p') + if 'bd' in self.OPTIONS: + self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, -2, '10p') + + def test_configure_compound(self): + widget = self.create() + self.checkEnumParam(widget, 'compound', + 'bottom', 'center', 'left', 'none', 'right', 'top') + + def test_configure_cursor(self): + widget = self.create() + self.checkCursorParam(widget, 'cursor') + + def test_configure_disabledforeground(self): + widget = self.create() + self.checkColorParam(widget, 'disabledforeground') + + def test_configure_exportselection(self): + widget = self.create() + self.checkBooleanParam(widget, 'exportselection') + + def test_configure_font(self): + widget = self.create() + self.checkParam(widget, 'font', + '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') + self.checkInvalidParam(widget, 'font', '', + errmsg='font "" doesn\'t exist') + + def test_configure_foreground(self): + widget = self.create() + self.checkColorParam(widget, 'foreground') + if 'fg' in self.OPTIONS: + self.checkColorParam(widget, 'fg') + + def test_configure_highlightbackground(self): + widget = self.create() + self.checkColorParam(widget, 'highlightbackground') + + def test_configure_highlightcolor(self): + widget = self.create() + self.checkColorParam(widget, 'highlightcolor') + + def test_configure_highlightthickness(self): + widget = self.create() + self.checkPixelsParam(widget, 'highlightthickness', + 0, 1.3, 2.6, 6, '10p') + self.checkParam(widget, 'highlightthickness', -2, expected=0, + conv=self._conv_pixels) + + def test_configure_image(self): + widget = self.create() + self.checkImageParam(widget, 'image') + + def test_configure_insertbackground(self): + widget = self.create() + self.checkColorParam(widget, 'insertbackground') + + def test_configure_insertborderwidth(self): + widget = self.create() + self.checkPixelsParam(widget, 'insertborderwidth', + 0, 1.3, 2.6, 6, -2, '10p') + + def test_configure_insertofftime(self): + widget = self.create() + self.checkIntegerParam(widget, 'insertofftime', 100) + + def test_configure_insertontime(self): + widget = self.create() + self.checkIntegerParam(widget, 'insertontime', 100) + + def test_configure_insertwidth(self): + widget = self.create() + self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p') + + def test_configure_jump(self): + widget = self.create() + self.checkBooleanParam(widget, 'jump') + + def test_configure_justify(self): + widget = self.create() + self.checkEnumParam(widget, 'justify', 'left', 'right', 'center', + errmsg='bad justification "{}": must be ' + 'left, right, or center') + self.checkInvalidParam(widget, 'justify', '', + errmsg='ambiguous justification "": must be ' + 'left, right, or center') + + def test_configure_orient(self): + widget = self.create() + self.assertEqual(str(widget['orient']), self.default_orient) + self.checkEnumParam(widget, 'orient', 'horizontal', 'vertical') + + def test_configure_padx(self): + widget = self.create() + self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, -2, '12m', + conv=self._conv_pad_pixels) + + def test_configure_pady(self): + widget = self.create() + self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, -2, '12m', + conv=self._conv_pad_pixels) + + def test_configure_relief(self): + widget = self.create() + self.checkReliefParam(widget, 'relief') + + def test_configure_repeatdelay(self): + widget = self.create() + self.checkIntegerParam(widget, 'repeatdelay', -500, 500) + + def test_configure_repeatinterval(self): + widget = self.create() + self.checkIntegerParam(widget, 'repeatinterval', -500, 500) + + def test_configure_selectbackground(self): + widget = self.create() + self.checkColorParam(widget, 'selectbackground') + + def test_configure_selectborderwidth(self): + widget = self.create() + self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p') + + def test_configure_selectforeground(self): + widget = self.create() + self.checkColorParam(widget, 'selectforeground') + + def test_configure_setgrid(self): + widget = self.create() + self.checkBooleanParam(widget, 'setgrid') + + def test_configure_state(self): + widget = self.create() + self.checkEnumParam(widget, 'state', 'active', 'disabled', 'normal') + + def test_configure_takefocus(self): + widget = self.create() + self.checkParams(widget, 'takefocus', '0', '1', '') + + def test_configure_text(self): + widget = self.create() + self.checkParams(widget, 'text', '', 'any string') + + def test_configure_textvariable(self): + widget = self.create() + var = tkinter.StringVar(self.root) + self.checkVariableParam(widget, 'textvariable', var) + + def test_configure_troughcolor(self): + widget = self.create() + self.checkColorParam(widget, 'troughcolor') + + def test_configure_underline(self): + widget = self.create() + self.checkIntegerParam(widget, 'underline', 0, 1, 10) + + def test_configure_wraplength(self): + widget = self.create() + self.checkPixelsParam(widget, 'wraplength', 100) + + def test_configure_xscrollcommand(self): + widget = self.create() + self.checkCommandParam(widget, 'xscrollcommand') + + def test_configure_yscrollcommand(self): + widget = self.create() + self.checkCommandParam(widget, 'yscrollcommand') + + # non-standard but common options + + def test_configure_command(self): + widget = self.create() + self.checkCommandParam(widget, 'command') + + def test_configure_indicatoron(self): + widget = self.create() + self.checkBooleanParam(widget, 'indicatoron') + + def test_configure_offrelief(self): + widget = self.create() + self.checkReliefParam(widget, 'offrelief') + + def test_configure_overrelief(self): + widget = self.create() + self.checkReliefParam(widget, 'overrelief') + + def test_configure_selectcolor(self): + widget = self.create() + self.checkColorParam(widget, 'selectcolor') + + def test_configure_selectimage(self): + widget = self.create() + self.checkImageParam(widget, 'selectimage') + + def test_configure_tristateimage(self): + widget = self.create() + self.checkImageParam(widget, 'tristateimage') + + def test_configure_tristatevalue(self): + widget = self.create() + self.checkParam(widget, 'tristatevalue', 'unknowable') + + def test_configure_variable(self): + widget = self.create() + var = tkinter.DoubleVar(self.root) + self.checkVariableParam(widget, 'variable', var) + + +class IntegerSizeTests: + def test_configure_height(self): + widget = self.create() + self.checkIntegerParam(widget, 'height', 100, -100, 0) + + def test_configure_width(self): + widget = self.create() + self.checkIntegerParam(widget, 'width', 402, -402, 0) + + +class PixelSizeTests: + def test_configure_height(self): + widget = self.create() + self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '3c') + + def test_configure_width(self): + widget = self.create() + self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i') + + +def add_standard_options(*source_classes): + # This decorator adds test_configure_xxx methods from source classes for + # every xxx option in the OPTIONS class attribute if they are not defined + # explicitly. + def decorator(cls): + for option in cls.OPTIONS: + methodname = 'test_configure_' + option + if not hasattr(cls, methodname): + for source_class in source_classes: + if hasattr(source_class, methodname): + setattr(cls, methodname, + getattr(source_class, methodname)) + break + else: + def test(self, option=option): + widget = self.create() + widget[option] + raise AssertionError('Option "%s" is not tested in %s' % + (option, cls.__name__)) + test.__name__ = methodname + setattr(cls, methodname, test) + return cls + return decorator + +def setUpModule(): + if test.support.verbose: + tcl = tkinter.Tcl() + print('patchlevel =', tcl.call('info', 'patchlevel'), flush=True) diff --git a/Lib/test/test_ttk/__init__.py b/Lib/test/test_ttk/__init__.py new file mode 100644 index 0000000..7ee7ffb --- /dev/null +++ b/Lib/test/test_ttk/__init__.py @@ -0,0 +1,39 @@ +import os.path +import unittest +from test import support +from test.support import import_helper + + +if support.check_sanitizer(address=True, memory=True): + raise unittest.SkipTest("Tests involving libX11 can SEGFAULT on ASAN/MSAN builds") + +# Skip this test if _tkinter wasn't built. +import_helper.import_module('_tkinter') + +# Skip test if tk cannot be initialized. +support.requires('gui') + + +import tkinter +from _tkinter import TclError +from tkinter import ttk + + +def setUpModule(): + root = None + try: + root = tkinter.Tk() + button = ttk.Button(root) + button.destroy() + del button + except TclError as msg: + # assuming ttk is not available + raise unittest.SkipTest("ttk not available: %s" % msg) + finally: + if root is not None: + root.destroy() + del root + + +def load_tests(*args): + return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_ttk/__main__.py b/Lib/test/test_ttk/__main__.py new file mode 100644 index 0000000..40a23a2 --- /dev/null +++ b/Lib/test/test_ttk/__main__.py @@ -0,0 +1,4 @@ +from . import load_tests +import unittest + +unittest.main() diff --git a/Lib/test/test_ttk/test_extensions.py b/Lib/test/test_ttk/test_extensions.py new file mode 100644 index 0000000..6135c49 --- /dev/null +++ b/Lib/test/test_ttk/test_extensions.py @@ -0,0 +1,328 @@ +import sys +import unittest +import tkinter +from tkinter import ttk +from test.support import requires, gc_collect +from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest + +requires('gui') + +class LabeledScaleTest(AbstractTkTest, unittest.TestCase): + + def tearDown(self): + self.root.update_idletasks() + super().tearDown() + + def test_widget_destroy(self): + # automatically created variable + x = ttk.LabeledScale(self.root) + var = x._variable._name + x.destroy() + gc_collect() # For PyPy or other GCs. + self.assertRaises(tkinter.TclError, x.tk.globalgetvar, var) + + # manually created variable + myvar = tkinter.DoubleVar(self.root) + name = myvar._name + x = ttk.LabeledScale(self.root, variable=myvar) + x.destroy() + if self.wantobjects: + self.assertEqual(x.tk.globalgetvar(name), myvar.get()) + else: + self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get()) + del myvar + gc_collect() # For PyPy or other GCs. + self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name) + + # checking that the tracing callback is properly removed + myvar = tkinter.IntVar(self.root) + # LabeledScale will start tracing myvar + x = ttk.LabeledScale(self.root, variable=myvar) + x.destroy() + # Unless the tracing callback was removed, creating a new + # LabeledScale with the same var will cause an error now. This + # happens because the variable will be set to (possibly) a new + # value which causes the tracing callback to be called and then + # it tries calling instance attributes not yet defined. + ttk.LabeledScale(self.root, variable=myvar) + if hasattr(sys, 'last_type'): + self.assertNotEqual(sys.last_type, tkinter.TclError) + + def test_initialization(self): + # master passing + master = tkinter.Frame(self.root) + x = ttk.LabeledScale(master) + self.assertEqual(x.master, master) + x.destroy() + + # variable initialization/passing + passed_expected = (('0', 0), (0, 0), (10, 10), + (-1, -1), (sys.maxsize + 1, sys.maxsize + 1), + (2.5, 2), ('2.5', 2)) + for pair in passed_expected: + x = ttk.LabeledScale(self.root, from_=pair[0]) + self.assertEqual(x.value, pair[1]) + x.destroy() + x = ttk.LabeledScale(self.root, from_=None) + self.assertRaises((ValueError, tkinter.TclError), x._variable.get) + x.destroy() + # variable should have its default value set to the from_ value + myvar = tkinter.DoubleVar(self.root, value=20) + x = ttk.LabeledScale(self.root, variable=myvar) + self.assertEqual(x.value, 0) + x.destroy() + # check that it is really using a DoubleVar + x = ttk.LabeledScale(self.root, variable=myvar, from_=0.5) + self.assertEqual(x.value, 0.5) + self.assertEqual(x._variable._name, myvar._name) + x.destroy() + + # widget positionment + def check_positions(scale, scale_pos, label, label_pos): + self.assertEqual(scale.pack_info()['side'], scale_pos) + self.assertEqual(label.place_info()['anchor'], label_pos) + x = ttk.LabeledScale(self.root, compound='top') + check_positions(x.scale, 'bottom', x.label, 'n') + x.destroy() + x = ttk.LabeledScale(self.root, compound='bottom') + check_positions(x.scale, 'top', x.label, 's') + x.destroy() + # invert default positions + x = ttk.LabeledScale(self.root, compound='unknown') + check_positions(x.scale, 'top', x.label, 's') + x.destroy() + x = ttk.LabeledScale(self.root) # take default positions + check_positions(x.scale, 'bottom', x.label, 'n') + x.destroy() + + # extra, and invalid, kwargs + self.assertRaises(tkinter.TclError, ttk.LabeledScale, master, a='b') + + + def test_horizontal_range(self): + lscale = ttk.LabeledScale(self.root, from_=0, to=10) + lscale.pack() + lscale.update() + + linfo_1 = lscale.label.place_info() + prev_xcoord = lscale.scale.coords()[0] + self.assertEqual(prev_xcoord, int(linfo_1['x'])) + # change range to: from -5 to 5. This should change the x coord of + # the scale widget, since 0 is at the middle of the new + # range. + lscale.scale.configure(from_=-5, to=5) + # The following update is needed since the test doesn't use mainloop, + # at the same time this shouldn't affect test outcome + lscale.update() + curr_xcoord = lscale.scale.coords()[0] + self.assertNotEqual(prev_xcoord, curr_xcoord) + # the label widget should have been repositioned too + linfo_2 = lscale.label.place_info() + self.assertEqual(lscale.label['text'], 0 if self.wantobjects else '0') + self.assertEqual(curr_xcoord, int(linfo_2['x'])) + # change the range back + lscale.scale.configure(from_=0, to=10) + self.assertNotEqual(prev_xcoord, curr_xcoord) + self.assertEqual(prev_xcoord, int(linfo_1['x'])) + + lscale.destroy() + + + def test_variable_change(self): + x = ttk.LabeledScale(self.root) + x.pack() + x.update() + + curr_xcoord = x.scale.coords()[0] + newval = x.value + 1 + x.value = newval + # The following update is needed since the test doesn't use mainloop, + # at the same time this shouldn't affect test outcome + x.update() + self.assertEqual(x.value, newval) + self.assertEqual(x.label['text'], + newval if self.wantobjects else str(newval)) + self.assertEqual(float(x.scale.get()), newval) + self.assertGreater(x.scale.coords()[0], curr_xcoord) + self.assertEqual(x.scale.coords()[0], + int(x.label.place_info()['x'])) + + # value outside range + if self.wantobjects: + conv = lambda x: x + else: + conv = int + x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen + x.update() + self.assertEqual(x.value, newval) + self.assertEqual(conv(x.label['text']), newval) + self.assertEqual(float(x.scale.get()), newval) + self.assertEqual(x.scale.coords()[0], + int(x.label.place_info()['x'])) + + # non-integer value + x.value = newval = newval + 1.5 + x.update() + self.assertEqual(x.value, int(newval)) + self.assertEqual(conv(x.label['text']), int(newval)) + self.assertEqual(float(x.scale.get()), newval) + + x.destroy() + + + def test_resize(self): + x = ttk.LabeledScale(self.root) + x.pack(expand=True, fill='both') + gc_collect() # For PyPy or other GCs. + x.update() + + width, height = x.master.winfo_width(), x.master.winfo_height() + width_new, height_new = width * 2, height * 2 + + x.value = 3 + x.update() + x.master.wm_geometry("%dx%d" % (width_new, height_new)) + self.assertEqual(int(x.label.place_info()['x']), + x.scale.coords()[0]) + + # Reset geometry + x.master.wm_geometry("%dx%d" % (width, height)) + x.destroy() + + +class OptionMenuTest(AbstractTkTest, unittest.TestCase): + + def setUp(self): + super().setUp() + self.textvar = tkinter.StringVar(self.root) + + def tearDown(self): + del self.textvar + super().tearDown() + + + def test_widget_destroy(self): + var = tkinter.StringVar(self.root) + optmenu = ttk.OptionMenu(self.root, var) + name = var._name + optmenu.update_idletasks() + optmenu.destroy() + self.assertEqual(optmenu.tk.globalgetvar(name), var.get()) + del var + gc_collect() # For PyPy or other GCs. + self.assertRaises(tkinter.TclError, optmenu.tk.globalgetvar, name) + + + def test_initialization(self): + self.assertRaises(tkinter.TclError, + ttk.OptionMenu, self.root, self.textvar, invalid='thing') + + optmenu = ttk.OptionMenu(self.root, self.textvar, 'b', 'a', 'b') + self.assertEqual(optmenu._variable.get(), 'b') + + self.assertTrue(optmenu['menu']) + self.assertTrue(optmenu['textvariable']) + + optmenu.destroy() + + + def test_menu(self): + items = ('a', 'b', 'c') + default = 'a' + optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) + found_default = False + for i in range(len(items)): + value = optmenu['menu'].entrycget(i, 'value') + self.assertEqual(value, items[i]) + if value == default: + found_default = True + self.assertTrue(found_default) + optmenu.destroy() + + # default shouldn't be in menu if it is not part of values + default = 'd' + optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) + curr = None + i = 0 + while True: + last, curr = curr, optmenu['menu'].entryconfigure(i, 'value') + if last == curr: + # no more menu entries + break + self.assertNotEqual(curr, default) + i += 1 + self.assertEqual(i, len(items)) + + # check that variable is updated correctly + optmenu.pack() + gc_collect() # For PyPy or other GCs. + optmenu['menu'].invoke(0) + self.assertEqual(optmenu._variable.get(), items[0]) + + # changing to an invalid index shouldn't change the variable + self.assertRaises(tkinter.TclError, optmenu['menu'].invoke, -1) + self.assertEqual(optmenu._variable.get(), items[0]) + + optmenu.destroy() + + # specifying a callback + success = [] + def cb_test(item): + self.assertEqual(item, items[1]) + success.append(True) + optmenu = ttk.OptionMenu(self.root, self.textvar, 'a', command=cb_test, + *items) + optmenu['menu'].invoke(1) + if not success: + self.fail("Menu callback not invoked") + + optmenu.destroy() + + def test_unique_radiobuttons(self): + # check that radiobuttons are unique across instances (bpo25684) + items = ('a', 'b', 'c') + default = 'a' + optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) + textvar2 = tkinter.StringVar(self.root) + optmenu2 = ttk.OptionMenu(self.root, textvar2, default, *items) + optmenu.pack() + optmenu2.pack() + optmenu['menu'].invoke(1) + optmenu2['menu'].invoke(2) + optmenu_stringvar_name = optmenu['menu'].entrycget(0, 'variable') + optmenu2_stringvar_name = optmenu2['menu'].entrycget(0, 'variable') + self.assertNotEqual(optmenu_stringvar_name, + optmenu2_stringvar_name) + self.assertEqual(self.root.tk.globalgetvar(optmenu_stringvar_name), + items[1]) + self.assertEqual(self.root.tk.globalgetvar(optmenu2_stringvar_name), + items[2]) + + optmenu.destroy() + optmenu2.destroy() + + def test_trace_variable(self): + # prior to bpo45160, tracing a variable would cause the callback to be made twice + success = [] + items = ('a', 'b', 'c') + textvar = tkinter.StringVar(self.root) + def cb_test(*args): + success.append(textvar.get()) + optmenu = ttk.OptionMenu(self.root, textvar, "a", *items) + optmenu.pack() + cb_name = textvar.trace_add("write", cb_test) + optmenu['menu'].invoke(1) + self.assertEqual(success, ['b']) + self.assertEqual(textvar.get(), 'b') + textvar.trace_remove("write", cb_name) + optmenu.destroy() + + +class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): + + def test_labeledscale(self): + self._test_widget(ttk.LabeledScale) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_ttk/test_style.py b/Lib/test/test_ttk/test_style.py new file mode 100644 index 0000000..0ec95cf --- /dev/null +++ b/Lib/test/test_ttk/test_style.py @@ -0,0 +1,181 @@ +import unittest +import sys +import tkinter +from tkinter import ttk +from test import support +from test.support import requires +from test.test_tkinter.support import AbstractTkTest, get_tk_patchlevel + +requires('gui') + +CLASS_NAMES = [ + '.', 'ComboboxPopdownFrame', 'Heading', + 'Horizontal.TProgressbar', 'Horizontal.TScale', 'Item', 'Sash', + 'TButton', 'TCheckbutton', 'TCombobox', 'TEntry', + 'TLabelframe', 'TLabelframe.Label', 'TMenubutton', + 'TNotebook', 'TNotebook.Tab', 'Toolbutton', 'TProgressbar', + 'TRadiobutton', 'Treeview', 'TScale', 'TScrollbar', 'TSpinbox', + 'Vertical.TProgressbar', 'Vertical.TScale' +] + +class StyleTest(AbstractTkTest, unittest.TestCase): + + def setUp(self): + super().setUp() + self.style = ttk.Style(self.root) + + + def test_configure(self): + style = self.style + style.configure('TButton', background='yellow') + self.assertEqual(style.configure('TButton', 'background'), + 'yellow') + self.assertIsInstance(style.configure('TButton'), dict) + + + def test_map(self): + style = self.style + + # Single state + for states in ['active'], [('active',)]: + with self.subTest(states=states): + style.map('TButton', background=[(*states, 'white')]) + expected = [('active', 'white')] + self.assertEqual(style.map('TButton', 'background'), expected) + m = style.map('TButton') + self.assertIsInstance(m, dict) + self.assertEqual(m['background'], expected) + + # Multiple states + for states in ['pressed', '!disabled'], ['pressed !disabled'], [('pressed', '!disabled')]: + with self.subTest(states=states): + style.map('TButton', background=[(*states, 'black')]) + expected = [('pressed', '!disabled', 'black')] + self.assertEqual(style.map('TButton', 'background'), expected) + m = style.map('TButton') + self.assertIsInstance(m, dict) + self.assertEqual(m['background'], expected) + + # Default state + for states in [], [''], [()]: + with self.subTest(states=states): + style.map('TButton', background=[(*states, 'grey')]) + expected = [('grey',)] + self.assertEqual(style.map('TButton', 'background'), expected) + m = style.map('TButton') + self.assertIsInstance(m, dict) + self.assertEqual(m['background'], expected) + + + def test_lookup(self): + style = self.style + style.configure('TButton', background='yellow') + style.map('TButton', background=[('active', 'background', 'blue')]) + + self.assertEqual(style.lookup('TButton', 'background'), 'yellow') + self.assertEqual(style.lookup('TButton', 'background', + ['active', 'background']), 'blue') + self.assertEqual(style.lookup('TButton', 'optionnotdefined', + default='iknewit'), 'iknewit') + + + def test_layout(self): + style = self.style + self.assertRaises(tkinter.TclError, style.layout, 'NotALayout') + tv_style = style.layout('Treeview') + + # "erase" Treeview layout + style.layout('Treeview', '') + self.assertEqual(style.layout('Treeview'), + [('null', {'sticky': 'nswe'})] + ) + + # restore layout + style.layout('Treeview', tv_style) + self.assertEqual(style.layout('Treeview'), tv_style) + + # should return a list + self.assertIsInstance(style.layout('TButton'), list) + + # correct layout, but "option" doesn't exist as option + self.assertRaises(tkinter.TclError, style.layout, 'Treeview', + [('name', {'option': 'inexistent'})]) + + + def test_theme_use(self): + self.assertRaises(tkinter.TclError, self.style.theme_use, + 'nonexistingname') + + curr_theme = self.style.theme_use() + new_theme = None + for theme in self.style.theme_names(): + if theme != curr_theme: + new_theme = theme + self.style.theme_use(theme) + break + else: + # just one theme available, can't go on with tests + return + + self.assertFalse(curr_theme == new_theme) + self.assertFalse(new_theme != self.style.theme_use()) + + self.style.theme_use(curr_theme) + + + def test_configure_custom_copy(self): + style = self.style + + curr_theme = self.style.theme_use() + self.addCleanup(self.style.theme_use, curr_theme) + for theme in self.style.theme_names(): + self.style.theme_use(theme) + for name in CLASS_NAMES: + default = style.configure(name) + if not default: + continue + with self.subTest(theme=theme, name=name): + if support.verbose >= 2: + print('configure', theme, name, default) + if (theme in ('vista', 'xpnative') + and sys.getwindowsversion()[:2] == (6, 1)): + # Fails on the Windows 7 buildbot + continue + newname = f'C.{name}' + self.assertEqual(style.configure(newname), None) + style.configure(newname, **default) + self.assertEqual(style.configure(newname), default) + for key, value in default.items(): + self.assertEqual(style.configure(newname, key), value) + + + def test_map_custom_copy(self): + style = self.style + + curr_theme = self.style.theme_use() + self.addCleanup(self.style.theme_use, curr_theme) + for theme in self.style.theme_names(): + self.style.theme_use(theme) + for name in CLASS_NAMES: + default = style.map(name) + if not default: + continue + with self.subTest(theme=theme, name=name): + if support.verbose >= 2: + print('map', theme, name, default) + if (theme in ('vista', 'xpnative') + and sys.getwindowsversion()[:2] == (6, 1)): + # Fails on the Windows 7 buildbot + continue + newname = f'C.{name}' + self.assertEqual(style.map(newname), {}) + style.map(newname, **default) + if theme == 'alt' and name == '.' and get_tk_patchlevel() < (8, 6, 1): + default['embossed'] = [('disabled', '1')] + self.assertEqual(style.map(newname), default) + for key, value in default.items(): + self.assertEqual(style.map(newname, key), value) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py new file mode 100644 index 0000000..eb0cc93 --- /dev/null +++ b/Lib/test/test_ttk/test_widgets.py @@ -0,0 +1,1858 @@ +import unittest +import tkinter +from tkinter import ttk, TclError +from test.support import requires, gc_collect +import sys + +from test.test_ttk_textonly import MockTclObj +from test.test_tkinter.support import (AbstractTkTest, tcl_version, get_tk_patchlevel, + simulate_mouse_click, AbstractDefaultRootTest) +from test.test_tkinter.widget_tests import (add_standard_options, + AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, + setUpModule) + +requires('gui') + + +class StandardTtkOptionsTests(StandardOptionsTests): + + def test_configure_class(self): + widget = self.create() + self.assertEqual(widget['class'], '') + errmsg='attempt to change read-only option' + if get_tk_patchlevel() < (8, 6, 0, 'beta', 3): + errmsg='Attempt to change read-only option' + self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg) + widget2 = self.create(class_='Foo') + self.assertEqual(widget2['class'], 'Foo') + + def test_configure_padding(self): + widget = self.create() + self.checkParam(widget, 'padding', 0, expected=('0',)) + self.checkParam(widget, 'padding', 5, expected=('5',)) + self.checkParam(widget, 'padding', (5, 6), expected=('5', '6')) + self.checkParam(widget, 'padding', (5, 6, 7), + expected=('5', '6', '7')) + self.checkParam(widget, 'padding', (5, 6, 7, 8), + expected=('5', '6', '7', '8')) + self.checkParam(widget, 'padding', ('5p', '6p', '7p', '8p')) + self.checkParam(widget, 'padding', (), expected='') + + def test_configure_style(self): + widget = self.create() + self.assertEqual(widget['style'], '') + errmsg = 'Layout Foo not found' + if hasattr(self, 'default_orient'): + errmsg = ('Layout %s.Foo not found' % + getattr(self, 'default_orient').title()) + self.checkInvalidParam(widget, 'style', 'Foo', + errmsg=errmsg) + widget2 = self.create(class_='Foo') + self.assertEqual(widget2['class'], 'Foo') + # XXX + pass + + +class WidgetTest(AbstractTkTest, unittest.TestCase): + """Tests methods available in every ttk widget.""" + + def setUp(self): + super().setUp() + self.widget = ttk.Button(self.root, width=0, text="Text") + self.widget.pack() + + def test_identify(self): + self.widget.update() + self.assertEqual(self.widget.identify( + int(self.widget.winfo_width() / 2), + int(self.widget.winfo_height() / 2) + ), "label") + self.assertEqual(self.widget.identify(-1, -1), "") + + self.assertRaises(tkinter.TclError, self.widget.identify, None, 5) + self.assertRaises(tkinter.TclError, self.widget.identify, 5, None) + self.assertRaises(tkinter.TclError, self.widget.identify, 5, '') + + def test_widget_state(self): + # XXX not sure about the portability of all these tests + self.assertEqual(self.widget.state(), ()) + self.assertEqual(self.widget.instate(['!disabled']), True) + + # changing from !disabled to disabled + self.assertEqual(self.widget.state(['disabled']), ('!disabled', )) + # no state change + self.assertEqual(self.widget.state(['disabled']), ()) + # change back to !disable but also active + self.assertEqual(self.widget.state(['!disabled', 'active']), + ('!active', 'disabled')) + # no state changes, again + self.assertEqual(self.widget.state(['!disabled', 'active']), ()) + self.assertEqual(self.widget.state(['active', '!disabled']), ()) + + def test_cb(arg1, **kw): + return arg1, kw + self.assertEqual(self.widget.instate(['!disabled'], + test_cb, "hi", **{"msg": "there"}), + ('hi', {'msg': 'there'})) + + # attempt to set invalid statespec + currstate = self.widget.state() + self.assertRaises(tkinter.TclError, self.widget.instate, + ['badstate']) + self.assertRaises(tkinter.TclError, self.widget.instate, + ['disabled', 'badstate']) + # verify that widget didn't change its state + self.assertEqual(currstate, self.widget.state()) + + # ensuring that passing None as state doesn't modify current state + self.widget.state(['active', '!disabled']) + self.assertEqual(self.widget.state(), ('active', )) + + +class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests): + _conv_pixels = False + + +@add_standard_options(StandardTtkOptionsTests) +class FrameTest(AbstractToplevelTest, unittest.TestCase): + OPTIONS = ( + 'borderwidth', 'class', 'cursor', 'height', + 'padding', 'relief', 'style', 'takefocus', + 'width', + ) + + def create(self, **kwargs): + return ttk.Frame(self.root, **kwargs) + + +@add_standard_options(StandardTtkOptionsTests) +class LabelFrameTest(AbstractToplevelTest, unittest.TestCase): + OPTIONS = ( + 'borderwidth', 'class', 'cursor', 'height', + 'labelanchor', 'labelwidget', + 'padding', 'relief', 'style', 'takefocus', + 'text', 'underline', 'width', + ) + + def create(self, **kwargs): + return ttk.LabelFrame(self.root, **kwargs) + + def test_configure_labelanchor(self): + widget = self.create() + self.checkEnumParam(widget, 'labelanchor', + 'e', 'en', 'es', 'n', 'ne', 'nw', 's', 'se', 'sw', 'w', 'wn', 'ws', + errmsg='Bad label anchor specification {}') + self.checkInvalidParam(widget, 'labelanchor', 'center') + + def test_configure_labelwidget(self): + widget = self.create() + label = ttk.Label(self.root, text='Mupp', name='foo') + self.checkParam(widget, 'labelwidget', label, expected='.foo') + label.destroy() + + +class AbstractLabelTest(AbstractWidgetTest): + + def checkImageParam(self, widget, name): + image = tkinter.PhotoImage(master=self.root, name='image1') + image2 = tkinter.PhotoImage(master=self.root, name='image2') + self.checkParam(widget, name, image, expected=('image1',)) + self.checkParam(widget, name, 'image1', expected=('image1',)) + self.checkParam(widget, name, (image,), expected=('image1',)) + self.checkParam(widget, name, (image, 'active', image2), + expected=('image1', 'active', 'image2')) + self.checkParam(widget, name, 'image1 active image2', + expected=('image1', 'active', 'image2')) + self.checkInvalidParam(widget, name, 'spam', + errmsg='image "spam" doesn\'t exist') + + def test_configure_compound(self): + options = 'none text image center top bottom left right'.split() + errmsg = ( + 'bad compound "{}": must be' + f' {", ".join(options[:-1])}, or {options[-1]}' + ) + widget = self.create() + self.checkEnumParam(widget, 'compound', *options, errmsg=errmsg) + + def test_configure_state(self): + widget = self.create() + self.checkParams(widget, 'state', 'active', 'disabled', 'normal') + + def test_configure_width(self): + widget = self.create() + self.checkParams(widget, 'width', 402, -402, 0) + + +@add_standard_options(StandardTtkOptionsTests) +class LabelTest(AbstractLabelTest, unittest.TestCase): + OPTIONS = ( + 'anchor', 'background', 'borderwidth', + 'class', 'compound', 'cursor', 'font', 'foreground', + 'image', 'justify', 'padding', 'relief', 'state', 'style', + 'takefocus', 'text', 'textvariable', + 'underline', 'width', 'wraplength', + ) + _conv_pixels = False + + def create(self, **kwargs): + return ttk.Label(self.root, **kwargs) + + def test_configure_font(self): + widget = self.create() + self.checkParam(widget, 'font', + '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') + + +@add_standard_options(StandardTtkOptionsTests) +class ButtonTest(AbstractLabelTest, unittest.TestCase): + OPTIONS = ( + 'class', 'command', 'compound', 'cursor', 'default', + 'image', 'padding', 'state', 'style', + 'takefocus', 'text', 'textvariable', + 'underline', 'width', + ) + + def create(self, **kwargs): + return ttk.Button(self.root, **kwargs) + + def test_configure_default(self): + widget = self.create() + self.checkEnumParam(widget, 'default', 'normal', 'active', 'disabled') + + def test_invoke(self): + success = [] + btn = ttk.Button(self.root, command=lambda: success.append(1)) + btn.invoke() + self.assertTrue(success) + + +@add_standard_options(StandardTtkOptionsTests) +class CheckbuttonTest(AbstractLabelTest, unittest.TestCase): + OPTIONS = ( + 'class', 'command', 'compound', 'cursor', + 'image', + 'offvalue', 'onvalue', + 'padding', 'state', 'style', + 'takefocus', 'text', 'textvariable', + 'underline', 'variable', 'width', + ) + + def create(self, **kwargs): + return ttk.Checkbutton(self.root, **kwargs) + + def test_configure_offvalue(self): + widget = self.create() + self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string') + + def test_configure_onvalue(self): + widget = self.create() + self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string') + + def test_invoke(self): + success = [] + def cb_test(): + success.append(1) + return "cb test called" + + cbtn = ttk.Checkbutton(self.root, command=cb_test) + # the variable automatically created by ttk.Checkbutton is actually + # undefined till we invoke the Checkbutton + self.assertEqual(cbtn.state(), ('alternate', )) + self.assertRaises(tkinter.TclError, cbtn.tk.globalgetvar, + cbtn['variable']) + + res = cbtn.invoke() + self.assertEqual(res, "cb test called") + self.assertEqual(cbtn['onvalue'], + cbtn.tk.globalgetvar(cbtn['variable'])) + self.assertTrue(success) + + cbtn['command'] = '' + res = cbtn.invoke() + self.assertFalse(str(res)) + self.assertLessEqual(len(success), 1) + self.assertEqual(cbtn['offvalue'], + cbtn.tk.globalgetvar(cbtn['variable'])) + + +@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) +class EntryTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'background', 'class', 'cursor', + 'exportselection', 'font', 'foreground', + 'invalidcommand', 'justify', + 'show', 'state', 'style', 'takefocus', 'textvariable', + 'validate', 'validatecommand', 'width', 'xscrollcommand', + ) + IDENTIFY_AS = 'Entry.field' if sys.platform == 'darwin' else 'textarea' + + def setUp(self): + super().setUp() + self.entry = self.create() + + def create(self, **kwargs): + return ttk.Entry(self.root, **kwargs) + + def test_configure_invalidcommand(self): + widget = self.create() + self.checkCommandParam(widget, 'invalidcommand') + + def test_configure_show(self): + widget = self.create() + self.checkParam(widget, 'show', '*') + self.checkParam(widget, 'show', '') + self.checkParam(widget, 'show', ' ') + + def test_configure_state(self): + widget = self.create() + self.checkParams(widget, 'state', + 'disabled', 'normal', 'readonly') + + def test_configure_validate(self): + widget = self.create() + self.checkEnumParam(widget, 'validate', + 'all', 'key', 'focus', 'focusin', 'focusout', 'none') + + def test_configure_validatecommand(self): + widget = self.create() + self.checkCommandParam(widget, 'validatecommand') + + def test_bbox(self): + self.assertIsBoundingBox(self.entry.bbox(0)) + self.assertRaises(tkinter.TclError, self.entry.bbox, 'noindex') + self.assertRaises(tkinter.TclError, self.entry.bbox, None) + + def test_identify(self): + self.entry.pack() + self.entry.update() + + # bpo-27313: macOS Cocoa widget differs from X, allow either + self.assertEqual(self.entry.identify(5, 5), self.IDENTIFY_AS) + self.assertEqual(self.entry.identify(-1, -1), "") + + self.assertRaises(tkinter.TclError, self.entry.identify, None, 5) + self.assertRaises(tkinter.TclError, self.entry.identify, 5, None) + self.assertRaises(tkinter.TclError, self.entry.identify, 5, '') + + def test_validation_options(self): + success = [] + test_invalid = lambda: success.append(True) + + self.entry['validate'] = 'none' + self.entry['validatecommand'] = lambda: False + + self.entry['invalidcommand'] = test_invalid + self.entry.validate() + self.assertTrue(success) + + self.entry['invalidcommand'] = '' + self.entry.validate() + self.assertEqual(len(success), 1) + + self.entry['invalidcommand'] = test_invalid + self.entry['validatecommand'] = lambda: True + self.entry.validate() + self.assertEqual(len(success), 1) + + self.entry['validatecommand'] = '' + self.entry.validate() + self.assertEqual(len(success), 1) + + self.entry['validatecommand'] = True + self.assertRaises(tkinter.TclError, self.entry.validate) + + def test_validation(self): + validation = [] + def validate(to_insert): + if not 'a' <= to_insert.lower() <= 'z': + validation.append(False) + return False + validation.append(True) + return True + + self.entry['validate'] = 'key' + self.entry['validatecommand'] = self.entry.register(validate), '%S' + + self.entry.insert('end', 1) + self.entry.insert('end', 'a') + self.assertEqual(validation, [False, True]) + self.assertEqual(self.entry.get(), 'a') + + def test_revalidation(self): + def validate(content): + for letter in content: + if not 'a' <= letter.lower() <= 'z': + return False + return True + + self.entry['validatecommand'] = self.entry.register(validate), '%P' + + self.entry.insert('end', 'avocado') + self.assertEqual(self.entry.validate(), True) + self.assertEqual(self.entry.state(), ()) + + self.entry.delete(0, 'end') + self.assertEqual(self.entry.get(), '') + + self.entry.insert('end', 'a1b') + self.assertEqual(self.entry.validate(), False) + self.assertEqual(self.entry.state(), ('invalid', )) + + self.entry.delete(1) + self.assertEqual(self.entry.validate(), True) + self.assertEqual(self.entry.state(), ()) + + +@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) +class ComboboxTest(EntryTest, unittest.TestCase): + OPTIONS = ( + 'background', 'class', 'cursor', 'exportselection', + 'font', 'foreground', 'height', 'invalidcommand', + 'justify', 'postcommand', 'show', 'state', 'style', + 'takefocus', 'textvariable', + 'validate', 'validatecommand', 'values', + 'width', 'xscrollcommand', + ) + IDENTIFY_AS = 'Combobox.button' if sys.platform == 'darwin' else 'textarea' + + def setUp(self): + super().setUp() + self.combo = self.create() + + def create(self, **kwargs): + return ttk.Combobox(self.root, **kwargs) + + def test_configure_height(self): + widget = self.create() + self.checkParams(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i') + + def _show_drop_down_listbox(self): + width = self.combo.winfo_width() + x, y = width - 5, 5 + if sys.platform != 'darwin': # there's no down arrow on macOS + self.assertRegex(self.combo.identify(x, y), r'.*downarrow\Z') + self.combo.event_generate('', x=x, y=y) + self.combo.event_generate('', x=x, y=y) + self.combo.update_idletasks() + + def test_virtual_event(self): + success = [] + + self.combo['values'] = [1] + self.combo.bind('<>', + lambda evt: success.append(True)) + self.combo.pack() + self.combo.update() + + height = self.combo.winfo_height() + self._show_drop_down_listbox() + self.combo.update() + self.combo.event_generate('') + self.combo.update() + + self.assertTrue(success) + + def test_configure_postcommand(self): + success = [] + + self.combo['postcommand'] = lambda: success.append(True) + self.combo.pack() + self.combo.update() + + self._show_drop_down_listbox() + self.assertTrue(success) + + # testing postcommand removal + self.combo['postcommand'] = '' + self._show_drop_down_listbox() + self.assertEqual(len(success), 1) + + def test_configure_values(self): + def check_get_current(getval, currval): + self.assertEqual(self.combo.get(), getval) + self.assertEqual(self.combo.current(), currval) + + self.assertEqual(self.combo['values'], '') + check_get_current('', -1) + + self.checkParam(self.combo, 'values', 'mon tue wed thur', + expected=('mon', 'tue', 'wed', 'thur')) + self.checkParam(self.combo, 'values', ('mon', 'tue', 'wed', 'thur')) + self.checkParam(self.combo, 'values', (42, 3.14, '', 'any string')) + self.checkParam(self.combo, 'values', '') + + self.combo['values'] = ['a', 1, 'c'] + + self.combo.set('c') + check_get_current('c', 2) + + self.combo.current(0) + check_get_current('a', 0) + + self.combo.set('d') + check_get_current('d', -1) + + # testing values with empty string + self.combo.set('') + self.combo['values'] = (1, 2, '', 3) + check_get_current('', 2) + + # testing values with empty string set through configure + self.combo.configure(values=[1, '', 2]) + self.assertEqual(self.combo['values'], + ('1', '', '2') if self.wantobjects else + '1 {} 2') + + # testing values with spaces + self.combo['values'] = ['a b', 'a\tb', 'a\nb'] + self.assertEqual(self.combo['values'], + ('a b', 'a\tb', 'a\nb') if self.wantobjects else + '{a b} {a\tb} {a\nb}') + + # testing values with special characters + self.combo['values'] = [r'a\tb', '"a"', '} {'] + self.assertEqual(self.combo['values'], + (r'a\tb', '"a"', '} {') if self.wantobjects else + r'a\\tb {"a"} \}\ \{') + + # out of range + self.assertRaises(tkinter.TclError, self.combo.current, + len(self.combo['values'])) + # it expects an integer (or something that can be converted to int) + self.assertRaises(tkinter.TclError, self.combo.current, '') + + # testing creating combobox with empty string in values + combo2 = ttk.Combobox(self.root, values=[1, 2, '']) + self.assertEqual(combo2['values'], + ('1', '2', '') if self.wantobjects else '1 2 {}') + combo2.destroy() + + +@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) +class PanedWindowTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'class', 'cursor', 'height', + 'orient', 'style', 'takefocus', 'width', + ) + + def setUp(self): + super().setUp() + self.paned = self.create() + + def create(self, **kwargs): + return ttk.PanedWindow(self.root, **kwargs) + + def test_configure_orient(self): + widget = self.create() + self.assertEqual(str(widget['orient']), 'vertical') + errmsg='attempt to change read-only option' + if get_tk_patchlevel() < (8, 6, 0, 'beta', 3): + errmsg='Attempt to change read-only option' + self.checkInvalidParam(widget, 'orient', 'horizontal', + errmsg=errmsg) + widget2 = self.create(orient='horizontal') + self.assertEqual(str(widget2['orient']), 'horizontal') + + def test_add(self): + # attempt to add a child that is not a direct child of the paned window + label = ttk.Label(self.paned) + child = ttk.Label(label) + self.assertRaises(tkinter.TclError, self.paned.add, child) + label.destroy() + child.destroy() + # another attempt + label = ttk.Label(self.root) + child = ttk.Label(label) + self.assertRaises(tkinter.TclError, self.paned.add, child) + child.destroy() + label.destroy() + + good_child = ttk.Label(self.root) + self.paned.add(good_child) + # re-adding a child is not accepted + self.assertRaises(tkinter.TclError, self.paned.add, good_child) + + other_child = ttk.Label(self.paned) + self.paned.add(other_child) + self.assertEqual(self.paned.pane(0), self.paned.pane(1)) + self.assertRaises(tkinter.TclError, self.paned.pane, 2) + good_child.destroy() + other_child.destroy() + self.assertRaises(tkinter.TclError, self.paned.pane, 0) + + def test_forget(self): + self.assertRaises(tkinter.TclError, self.paned.forget, None) + self.assertRaises(tkinter.TclError, self.paned.forget, 0) + + self.paned.add(ttk.Label(self.root)) + self.paned.forget(0) + self.assertRaises(tkinter.TclError, self.paned.forget, 0) + + def test_insert(self): + self.assertRaises(tkinter.TclError, self.paned.insert, None, 0) + self.assertRaises(tkinter.TclError, self.paned.insert, 0, None) + self.assertRaises(tkinter.TclError, self.paned.insert, 0, 0) + + child = ttk.Label(self.root) + child2 = ttk.Label(self.root) + child3 = ttk.Label(self.root) + + self.assertRaises(tkinter.TclError, self.paned.insert, 0, child) + + self.paned.insert('end', child2) + self.paned.insert(0, child) + self.assertEqual(self.paned.panes(), (str(child), str(child2))) + + self.paned.insert(0, child2) + self.assertEqual(self.paned.panes(), (str(child2), str(child))) + + self.paned.insert('end', child3) + self.assertEqual(self.paned.panes(), + (str(child2), str(child), str(child3))) + + # reinserting a child should move it to its current position + panes = self.paned.panes() + self.paned.insert('end', child3) + self.assertEqual(panes, self.paned.panes()) + + # moving child3 to child2 position should result in child2 ending up + # in previous child position and child ending up in previous child3 + # position + self.paned.insert(child2, child3) + self.assertEqual(self.paned.panes(), + (str(child3), str(child2), str(child))) + + def test_pane(self): + self.assertRaises(tkinter.TclError, self.paned.pane, 0) + + child = ttk.Label(self.root) + self.paned.add(child) + self.assertIsInstance(self.paned.pane(0), dict) + self.assertEqual(self.paned.pane(0, weight=None), + 0 if self.wantobjects else '0') + # newer form for querying a single option + self.assertEqual(self.paned.pane(0, 'weight'), + 0 if self.wantobjects else '0') + self.assertEqual(self.paned.pane(0), self.paned.pane(str(child))) + + self.assertRaises(tkinter.TclError, self.paned.pane, 0, + badoption='somevalue') + + def test_sashpos(self): + self.assertRaises(tkinter.TclError, self.paned.sashpos, None) + self.assertRaises(tkinter.TclError, self.paned.sashpos, '') + self.assertRaises(tkinter.TclError, self.paned.sashpos, 0) + + child = ttk.Label(self.paned, text='a') + self.paned.add(child, weight=1) + self.assertRaises(tkinter.TclError, self.paned.sashpos, 0) + child2 = ttk.Label(self.paned, text='b') + self.paned.add(child2) + self.assertRaises(tkinter.TclError, self.paned.sashpos, 1) + + self.paned.pack(expand=True, fill='both') + + curr_pos = self.paned.sashpos(0) + self.paned.sashpos(0, 1000) + self.assertNotEqual(curr_pos, self.paned.sashpos(0)) + self.assertIsInstance(self.paned.sashpos(0), int) + + +@add_standard_options(StandardTtkOptionsTests) +class RadiobuttonTest(AbstractLabelTest, unittest.TestCase): + OPTIONS = ( + 'class', 'command', 'compound', 'cursor', + 'image', + 'padding', 'state', 'style', + 'takefocus', 'text', 'textvariable', + 'underline', 'value', 'variable', 'width', + ) + + def create(self, **kwargs): + return ttk.Radiobutton(self.root, **kwargs) + + def test_configure_value(self): + widget = self.create() + self.checkParams(widget, 'value', 1, 2.3, '', 'any string') + + def test_configure_invoke(self): + success = [] + def cb_test(): + success.append(1) + return "cb test called" + + myvar = tkinter.IntVar(self.root) + cbtn = ttk.Radiobutton(self.root, command=cb_test, + variable=myvar, value=0) + cbtn2 = ttk.Radiobutton(self.root, command=cb_test, + variable=myvar, value=1) + + if self.wantobjects: + conv = lambda x: x + else: + conv = int + + res = cbtn.invoke() + self.assertEqual(res, "cb test called") + self.assertEqual(conv(cbtn['value']), myvar.get()) + self.assertEqual(myvar.get(), + conv(cbtn.tk.globalgetvar(cbtn['variable']))) + self.assertTrue(success) + + cbtn2['command'] = '' + res = cbtn2.invoke() + self.assertEqual(str(res), '') + self.assertLessEqual(len(success), 1) + self.assertEqual(conv(cbtn2['value']), myvar.get()) + self.assertEqual(myvar.get(), + conv(cbtn.tk.globalgetvar(cbtn['variable']))) + + self.assertEqual(str(cbtn['variable']), str(cbtn2['variable'])) + + +class MenubuttonTest(AbstractLabelTest, unittest.TestCase): + OPTIONS = ( + 'class', 'compound', 'cursor', 'direction', + 'image', 'menu', 'padding', 'state', 'style', + 'takefocus', 'text', 'textvariable', + 'underline', 'width', + ) + + def create(self, **kwargs): + return ttk.Menubutton(self.root, **kwargs) + + def test_direction(self): + widget = self.create() + self.checkEnumParam(widget, 'direction', + 'above', 'below', 'left', 'right', 'flush') + + def test_configure_menu(self): + widget = self.create() + menu = tkinter.Menu(widget, name='menu') + self.checkParam(widget, 'menu', menu, conv=str) + menu.destroy() + + +@add_standard_options(StandardTtkOptionsTests) +class ScaleTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'class', 'command', 'cursor', 'from', 'length', + 'orient', 'style', 'takefocus', 'to', 'value', 'variable', + ) + _conv_pixels = False + default_orient = 'horizontal' + + def setUp(self): + super().setUp() + self.scale = self.create() + self.scale.pack() + self.scale.update() + + def create(self, **kwargs): + return ttk.Scale(self.root, **kwargs) + + def test_configure_from(self): + widget = self.create() + self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=False) + + def test_configure_length(self): + widget = self.create() + self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i') + + def test_configure_to(self): + widget = self.create() + self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=False) + + def test_configure_value(self): + widget = self.create() + self.checkFloatParam(widget, 'value', 300, 14.9, 15.1, -10, conv=False) + + def test_custom_event(self): + failure = [1, 1, 1] # will need to be empty + + funcid = self.scale.bind('<>', lambda evt: failure.pop()) + + self.scale['from'] = 10 + self.scale['from_'] = 10 + self.scale['to'] = 3 + + self.assertFalse(failure) + + failure = [1, 1, 1] + self.scale.configure(from_=2, to=5) + self.scale.configure(from_=0, to=-2) + self.scale.configure(to=10) + + self.assertFalse(failure) + + def test_get(self): + if self.wantobjects: + conv = lambda x: x + else: + conv = float + + scale_width = self.scale.winfo_width() + self.assertEqual(self.scale.get(scale_width, 0), self.scale['to']) + + self.assertEqual(conv(self.scale.get(0, 0)), conv(self.scale['from'])) + self.assertEqual(self.scale.get(), self.scale['value']) + self.scale['value'] = 30 + self.assertEqual(self.scale.get(), self.scale['value']) + + self.assertRaises(tkinter.TclError, self.scale.get, '', 0) + self.assertRaises(tkinter.TclError, self.scale.get, 0, '') + + def test_set(self): + if self.wantobjects: + conv = lambda x: x + else: + conv = float + + # set restricts the max/min values according to the current range + max = conv(self.scale['to']) + new_max = max + 10 + self.scale.set(new_max) + self.assertEqual(conv(self.scale.get()), max) + min = conv(self.scale['from']) + self.scale.set(min - 1) + self.assertEqual(conv(self.scale.get()), min) + + # changing directly the variable doesn't impose this limitation tho + var = tkinter.DoubleVar(self.root) + self.scale['variable'] = var + var.set(max + 5) + self.assertEqual(conv(self.scale.get()), var.get()) + self.assertEqual(conv(self.scale.get()), max + 5) + del var + gc_collect() # For PyPy or other GCs. + + # the same happens with the value option + self.scale['value'] = max + 10 + self.assertEqual(conv(self.scale.get()), max + 10) + self.assertEqual(conv(self.scale.get()), conv(self.scale['value'])) + + # nevertheless, note that the max/min values we can get specifying + # x, y coords are the ones according to the current range + self.assertEqual(conv(self.scale.get(0, 0)), min) + self.assertEqual(conv(self.scale.get(self.scale.winfo_width(), 0)), max) + + self.assertRaises(tkinter.TclError, self.scale.set, None) + + +@add_standard_options(StandardTtkOptionsTests) +class ProgressbarTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'class', 'cursor', 'orient', 'length', + 'mode', 'maximum', 'phase', + 'style', 'takefocus', 'value', 'variable', + ) + _conv_pixels = False + default_orient = 'horizontal' + + def create(self, **kwargs): + return ttk.Progressbar(self.root, **kwargs) + + def test_configure_length(self): + widget = self.create() + self.checkPixelsParam(widget, 'length', 100.1, 56.7, '2i') + + def test_configure_maximum(self): + widget = self.create() + self.checkFloatParam(widget, 'maximum', 150.2, 77.7, 0, -10, conv=False) + + def test_configure_mode(self): + widget = self.create() + self.checkEnumParam(widget, 'mode', 'determinate', 'indeterminate') + + def test_configure_phase(self): + # XXX + pass + + def test_configure_value(self): + widget = self.create() + self.checkFloatParam(widget, 'value', 150.2, 77.7, 0, -10, + conv=False) + + +@unittest.skipIf(sys.platform == 'darwin', + 'ttk.Scrollbar is special on MacOSX') +@add_standard_options(StandardTtkOptionsTests) +class ScrollbarTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'class', 'command', 'cursor', 'orient', 'style', 'takefocus', + ) + default_orient = 'vertical' + + def create(self, **kwargs): + return ttk.Scrollbar(self.root, **kwargs) + + +@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) +class NotebookTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'class', 'cursor', 'height', 'padding', 'style', 'takefocus', 'width', + ) + + def setUp(self): + super().setUp() + self.nb = self.create(padding=0) + self.child1 = ttk.Label(self.root) + self.child2 = ttk.Label(self.root) + self.nb.add(self.child1, text='a') + self.nb.add(self.child2, text='b') + + def create(self, **kwargs): + return ttk.Notebook(self.root, **kwargs) + + def test_tab_identifiers(self): + self.nb.forget(0) + self.nb.hide(self.child2) + self.assertRaises(tkinter.TclError, self.nb.tab, self.child1) + self.assertEqual(self.nb.index('end'), 1) + self.nb.add(self.child2) + self.assertEqual(self.nb.index('end'), 1) + self.nb.select(self.child2) + + self.assertTrue(self.nb.tab('current')) + self.nb.add(self.child1, text='a') + + self.nb.pack() + self.nb.update() + if sys.platform == 'darwin': + tb_idx = "@20,5" + else: + tb_idx = "@5,5" + self.assertEqual(self.nb.tab(tb_idx), self.nb.tab('current')) + + for i in range(5, 100, 5): + try: + if self.nb.tab('@%d, 5' % i, text=None) == 'a': + break + except tkinter.TclError: + pass + + else: + self.fail("Tab with text 'a' not found") + + def test_add_and_hidden(self): + self.assertRaises(tkinter.TclError, self.nb.hide, -1) + self.assertRaises(tkinter.TclError, self.nb.hide, 'hi') + self.assertRaises(tkinter.TclError, self.nb.hide, None) + self.assertRaises(tkinter.TclError, self.nb.add, None) + self.assertRaises(tkinter.TclError, self.nb.add, ttk.Label(self.root), + unknown='option') + + tabs = self.nb.tabs() + self.nb.hide(self.child1) + self.nb.add(self.child1) + self.assertEqual(self.nb.tabs(), tabs) + + child = ttk.Label(self.root) + self.nb.add(child, text='c') + tabs = self.nb.tabs() + + curr = self.nb.index('current') + # verify that the tab gets re-added at its previous position + child2_index = self.nb.index(self.child2) + self.nb.hide(self.child2) + self.nb.add(self.child2) + self.assertEqual(self.nb.tabs(), tabs) + self.assertEqual(self.nb.index(self.child2), child2_index) + self.assertEqual(str(self.child2), self.nb.tabs()[child2_index]) + # but the tab next to it (not hidden) is the one selected now + self.assertEqual(self.nb.index('current'), curr + 1) + + def test_forget(self): + self.assertRaises(tkinter.TclError, self.nb.forget, -1) + self.assertRaises(tkinter.TclError, self.nb.forget, 'hi') + self.assertRaises(tkinter.TclError, self.nb.forget, None) + + tabs = self.nb.tabs() + child1_index = self.nb.index(self.child1) + self.nb.forget(self.child1) + self.assertNotIn(str(self.child1), self.nb.tabs()) + self.assertEqual(len(tabs) - 1, len(self.nb.tabs())) + + self.nb.add(self.child1) + self.assertEqual(self.nb.index(self.child1), 1) + self.assertNotEqual(child1_index, self.nb.index(self.child1)) + + def test_index(self): + self.assertRaises(tkinter.TclError, self.nb.index, -1) + self.assertRaises(tkinter.TclError, self.nb.index, None) + + self.assertIsInstance(self.nb.index('end'), int) + self.assertEqual(self.nb.index(self.child1), 0) + self.assertEqual(self.nb.index(self.child2), 1) + self.assertEqual(self.nb.index('end'), 2) + + def test_insert(self): + # moving tabs + tabs = self.nb.tabs() + self.nb.insert(1, tabs[0]) + self.assertEqual(self.nb.tabs(), (tabs[1], tabs[0])) + self.nb.insert(self.child1, self.child2) + self.assertEqual(self.nb.tabs(), tabs) + self.nb.insert('end', self.child1) + self.assertEqual(self.nb.tabs(), (tabs[1], tabs[0])) + self.nb.insert('end', 0) + self.assertEqual(self.nb.tabs(), tabs) + # bad moves + self.assertRaises(tkinter.TclError, self.nb.insert, 2, tabs[0]) + self.assertRaises(tkinter.TclError, self.nb.insert, -1, tabs[0]) + + # new tab + child3 = ttk.Label(self.root) + self.nb.insert(1, child3) + self.assertEqual(self.nb.tabs(), (tabs[0], str(child3), tabs[1])) + self.nb.forget(child3) + self.assertEqual(self.nb.tabs(), tabs) + self.nb.insert(self.child1, child3) + self.assertEqual(self.nb.tabs(), (str(child3), ) + tabs) + self.nb.forget(child3) + self.assertRaises(tkinter.TclError, self.nb.insert, 2, child3) + self.assertRaises(tkinter.TclError, self.nb.insert, -1, child3) + + # bad inserts + self.assertRaises(tkinter.TclError, self.nb.insert, 'end', None) + self.assertRaises(tkinter.TclError, self.nb.insert, None, 0) + self.assertRaises(tkinter.TclError, self.nb.insert, None, None) + + def test_select(self): + self.nb.pack() + self.nb.update() + + success = [] + tab_changed = [] + + self.child1.bind('', lambda evt: success.append(True)) + self.nb.bind('<>', + lambda evt: tab_changed.append(True)) + + self.assertEqual(self.nb.select(), str(self.child1)) + self.nb.select(self.child2) + self.assertTrue(success) + self.assertEqual(self.nb.select(), str(self.child2)) + + self.nb.update() + self.assertTrue(tab_changed) + + def test_tab(self): + self.assertRaises(tkinter.TclError, self.nb.tab, -1) + self.assertRaises(tkinter.TclError, self.nb.tab, 'notab') + self.assertRaises(tkinter.TclError, self.nb.tab, None) + + self.assertIsInstance(self.nb.tab(self.child1), dict) + self.assertEqual(self.nb.tab(self.child1, text=None), 'a') + # newer form for querying a single option + self.assertEqual(self.nb.tab(self.child1, 'text'), 'a') + self.nb.tab(self.child1, text='abc') + self.assertEqual(self.nb.tab(self.child1, text=None), 'abc') + self.assertEqual(self.nb.tab(self.child1, 'text'), 'abc') + + def test_configure_tabs(self): + self.assertEqual(len(self.nb.tabs()), 2) + + self.nb.forget(self.child1) + self.nb.forget(self.child2) + + self.assertEqual(self.nb.tabs(), ()) + + def test_traversal(self): + self.nb.pack() + self.nb.update() + + self.nb.select(0) + + focus_identify_as = 'focus' if sys.platform != 'darwin' else '' + self.assertEqual(self.nb.identify(5, 5), focus_identify_as) + simulate_mouse_click(self.nb, 5, 5) + self.nb.focus_force() + self.nb.event_generate('') + self.assertEqual(self.nb.select(), str(self.child2)) + self.nb.focus_force() + self.nb.event_generate('') + self.assertEqual(self.nb.select(), str(self.child1)) + self.nb.focus_force() + self.nb.event_generate('') + self.assertEqual(self.nb.select(), str(self.child2)) + + self.nb.tab(self.child1, text='a', underline=0) + self.nb.tab(self.child2, text='e', underline=0) + self.nb.enable_traversal() + self.nb.focus_force() + self.assertEqual(self.nb.identify(5, 5), focus_identify_as) + simulate_mouse_click(self.nb, 5, 5) + # on macOS Emacs-style keyboard shortcuts are region-dependent; + # let's use the regular arrow keys instead + if sys.platform == 'darwin': + begin = '' + end = '' + else: + begin = '' + end = '' + self.nb.event_generate(begin) + self.assertEqual(self.nb.select(), str(self.child1)) + self.nb.event_generate(end) + self.assertEqual(self.nb.select(), str(self.child2)) + + +@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) +class SpinboxTest(EntryTest, unittest.TestCase): + OPTIONS = ( + 'background', 'class', 'command', 'cursor', 'exportselection', + 'font', 'foreground', 'format', 'from', 'increment', + 'invalidcommand', 'justify', 'show', 'state', 'style', + 'takefocus', 'textvariable', 'to', 'validate', 'validatecommand', + 'values', 'width', 'wrap', 'xscrollcommand', + ) + IDENTIFY_AS = 'Spinbox.field' if sys.platform == 'darwin' else 'textarea' + + def setUp(self): + super().setUp() + self.spin = self.create() + self.spin.pack() + + def create(self, **kwargs): + return ttk.Spinbox(self.root, **kwargs) + + def _click_increment_arrow(self): + width = self.spin.winfo_width() + height = self.spin.winfo_height() + x = width - 5 + y = height//2 - 5 + self.assertRegex(self.spin.identify(x, y), r'.*uparrow\Z') + self.spin.event_generate('', x=x, y=y) + self.spin.event_generate('', x=x, y=y) + self.spin.update_idletasks() + + def _click_decrement_arrow(self): + width = self.spin.winfo_width() + height = self.spin.winfo_height() + x = width - 5 + y = height//2 + 4 + self.assertRegex(self.spin.identify(x, y), r'.*downarrow\Z') + self.spin.event_generate('', x=x, y=y) + self.spin.event_generate('', x=x, y=y) + self.spin.update_idletasks() + + def test_configure_command(self): + success = [] + + self.spin['command'] = lambda: success.append(True) + self.spin.update() + self._click_increment_arrow() + self.spin.update() + self.assertTrue(success) + + self._click_decrement_arrow() + self.assertEqual(len(success), 2) + + # testing postcommand removal + self.spin['command'] = '' + self.spin.update_idletasks() + self._click_increment_arrow() + self._click_decrement_arrow() + self.spin.update() + self.assertEqual(len(success), 2) + + def test_configure_to(self): + self.spin['from'] = 0 + self.spin['to'] = 5 + self.spin.set(4) + self.spin.update() + self._click_increment_arrow() # 5 + + self.assertEqual(self.spin.get(), '5') + + self._click_increment_arrow() # 5 + self.assertEqual(self.spin.get(), '5') + + def test_configure_from(self): + self.spin['from'] = 1 + self.spin['to'] = 10 + self.spin.set(2) + self.spin.update() + self._click_decrement_arrow() # 1 + self.assertEqual(self.spin.get(), '1') + self._click_decrement_arrow() # 1 + self.assertEqual(self.spin.get(), '1') + + def test_configure_increment(self): + self.spin['from'] = 0 + self.spin['to'] = 10 + self.spin['increment'] = 4 + self.spin.set(1) + self.spin.update() + + self._click_increment_arrow() # 5 + self.assertEqual(self.spin.get(), '5') + self.spin['increment'] = 2 + self.spin.update() + self._click_decrement_arrow() # 3 + self.assertEqual(self.spin.get(), '3') + + def test_configure_format(self): + self.spin.set(1) + self.spin['format'] = '%10.3f' + self.spin.update() + self._click_increment_arrow() + value = self.spin.get() + + self.assertEqual(len(value), 10) + self.assertEqual(value.index('.'), 6) + + self.spin['format'] = '' + self.spin.update() + self._click_increment_arrow() + value = self.spin.get() + self.assertTrue('.' not in value) + self.assertEqual(len(value), 1) + + def test_configure_wrap(self): + self.spin['to'] = 10 + self.spin['from'] = 1 + self.spin.set(1) + self.spin['wrap'] = True + self.spin.update() + + self._click_decrement_arrow() + self.assertEqual(self.spin.get(), '10') + + self._click_increment_arrow() + self.assertEqual(self.spin.get(), '1') + + self.spin['wrap'] = False + self.spin.update() + + self._click_decrement_arrow() + self.assertEqual(self.spin.get(), '1') + + def test_configure_values(self): + self.assertEqual(self.spin['values'], '') + self.checkParam(self.spin, 'values', 'mon tue wed thur', + expected=('mon', 'tue', 'wed', 'thur')) + self.checkParam(self.spin, 'values', ('mon', 'tue', 'wed', 'thur')) + self.checkParam(self.spin, 'values', (42, 3.14, '', 'any string')) + self.checkParam(self.spin, 'values', '') + + self.spin['values'] = ['a', 1, 'c'] + + # test incrementing / decrementing values + self.spin.set('a') + self.spin.update() + self._click_increment_arrow() + self.assertEqual(self.spin.get(), '1') + + self._click_decrement_arrow() + self.assertEqual(self.spin.get(), 'a') + + # testing values with empty string set through configure + self.spin.configure(values=[1, '', 2]) + self.assertEqual(self.spin['values'], + ('1', '', '2') if self.wantobjects else + '1 {} 2') + + # testing values with spaces + self.spin['values'] = ['a b', 'a\tb', 'a\nb'] + self.assertEqual(self.spin['values'], + ('a b', 'a\tb', 'a\nb') if self.wantobjects else + '{a b} {a\tb} {a\nb}') + + # testing values with special characters + self.spin['values'] = [r'a\tb', '"a"', '} {'] + self.assertEqual(self.spin['values'], + (r'a\tb', '"a"', '} {') if self.wantobjects else + r'a\\tb {"a"} \}\ \{') + + # testing creating spinbox with empty string in values + spin2 = ttk.Spinbox(self.root, values=[1, 2, '']) + self.assertEqual(spin2['values'], + ('1', '2', '') if self.wantobjects else '1 2 {}') + spin2.destroy() + + +@add_standard_options(StandardTtkOptionsTests) +class TreeviewTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'class', 'columns', 'cursor', 'displaycolumns', + 'height', 'padding', 'selectmode', 'show', + 'style', 'takefocus', 'xscrollcommand', 'yscrollcommand', + ) + + def setUp(self): + super().setUp() + self.tv = self.create(padding=0) + + def create(self, **kwargs): + return ttk.Treeview(self.root, **kwargs) + + def test_configure_columns(self): + widget = self.create() + self.checkParam(widget, 'columns', 'a b c', + expected=('a', 'b', 'c')) + self.checkParam(widget, 'columns', ('a', 'b', 'c')) + self.checkParam(widget, 'columns', '') + + def test_configure_displaycolumns(self): + widget = self.create() + widget['columns'] = ('a', 'b', 'c') + self.checkParam(widget, 'displaycolumns', 'b a c', + expected=('b', 'a', 'c')) + self.checkParam(widget, 'displaycolumns', ('b', 'a', 'c')) + self.checkParam(widget, 'displaycolumns', '#all', + expected=('#all',)) + self.checkParam(widget, 'displaycolumns', (2, 1, 0)) + self.checkInvalidParam(widget, 'displaycolumns', ('a', 'b', 'd'), + errmsg='Invalid column index d') + self.checkInvalidParam(widget, 'displaycolumns', (1, 2, 3), + errmsg='Column index 3 out of bounds') + self.checkInvalidParam(widget, 'displaycolumns', (1, -2), + errmsg='Column index -2 out of bounds') + + def test_configure_height(self): + widget = self.create() + self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c', conv=False) + self.checkPixelsParam(widget, 'height', 101.2, 102.6, conv=False) + + def test_configure_selectmode(self): + widget = self.create() + self.checkEnumParam(widget, 'selectmode', + 'none', 'browse', 'extended') + + def test_configure_show(self): + widget = self.create() + self.checkParam(widget, 'show', 'tree headings', + expected=('tree', 'headings')) + self.checkParam(widget, 'show', ('tree', 'headings')) + self.checkParam(widget, 'show', ('headings', 'tree')) + self.checkParam(widget, 'show', 'tree', expected=('tree',)) + self.checkParam(widget, 'show', 'headings', expected=('headings',)) + + def test_bbox(self): + self.tv.pack() + self.assertEqual(self.tv.bbox(''), '') + self.tv.update() + + item_id = self.tv.insert('', 'end') + children = self.tv.get_children() + self.assertTrue(children) + + bbox = self.tv.bbox(children[0]) + self.assertIsBoundingBox(bbox) + + # compare width in bboxes + self.tv['columns'] = ['test'] + self.tv.column('test', width=50) + bbox_column0 = self.tv.bbox(children[0], 0) + root_width = self.tv.column('#0', width=None) + if not self.wantobjects: + root_width = int(root_width) + self.assertEqual(bbox_column0[0], bbox[0] + root_width) + + # verify that bbox of a closed item is the empty string + child1 = self.tv.insert(item_id, 'end') + self.assertEqual(self.tv.bbox(child1), '') + + def test_children(self): + # no children yet, should get an empty tuple + self.assertEqual(self.tv.get_children(), ()) + + item_id = self.tv.insert('', 'end') + self.assertIsInstance(self.tv.get_children(), tuple) + self.assertEqual(self.tv.get_children()[0], item_id) + + # add item_id and child3 as children of child2 + child2 = self.tv.insert('', 'end') + child3 = self.tv.insert('', 'end') + self.tv.set_children(child2, item_id, child3) + self.assertEqual(self.tv.get_children(child2), (item_id, child3)) + + # child3 has child2 as parent, thus trying to set child2 as a children + # of child3 should result in an error + self.assertRaises(tkinter.TclError, + self.tv.set_children, child3, child2) + + # remove child2 children + self.tv.set_children(child2) + self.assertEqual(self.tv.get_children(child2), ()) + + # remove root's children + self.tv.set_children('') + self.assertEqual(self.tv.get_children(), ()) + + def test_column(self): + # return a dict with all options/values + self.assertIsInstance(self.tv.column('#0'), dict) + # return a single value of the given option + if self.wantobjects: + self.assertIsInstance(self.tv.column('#0', width=None), int) + # set a new value for an option + self.tv.column('#0', width=10) + # testing new way to get option value + self.assertEqual(self.tv.column('#0', 'width'), + 10 if self.wantobjects else '10') + self.assertEqual(self.tv.column('#0', width=None), + 10 if self.wantobjects else '10') + # check read-only option + self.assertRaises(tkinter.TclError, self.tv.column, '#0', id='X') + + self.assertRaises(tkinter.TclError, self.tv.column, 'invalid') + invalid_kws = [ + {'unknown_option': 'some value'}, {'stretch': 'wrong'}, + {'anchor': 'wrong'}, {'width': 'wrong'}, {'minwidth': 'wrong'} + ] + for kw in invalid_kws: + self.assertRaises(tkinter.TclError, self.tv.column, '#0', + **kw) + + def test_delete(self): + self.assertRaises(tkinter.TclError, self.tv.delete, '#0') + + item_id = self.tv.insert('', 'end') + item2 = self.tv.insert(item_id, 'end') + self.assertEqual(self.tv.get_children(), (item_id, )) + self.assertEqual(self.tv.get_children(item_id), (item2, )) + + self.tv.delete(item_id) + self.assertFalse(self.tv.get_children()) + + # reattach should fail + self.assertRaises(tkinter.TclError, + self.tv.reattach, item_id, '', 'end') + + # test multiple item delete + item1 = self.tv.insert('', 'end') + item2 = self.tv.insert('', 'end') + self.assertEqual(self.tv.get_children(), (item1, item2)) + + self.tv.delete(item1, item2) + self.assertFalse(self.tv.get_children()) + + def test_detach_reattach(self): + item_id = self.tv.insert('', 'end') + item2 = self.tv.insert(item_id, 'end') + + # calling detach without items is valid, although it does nothing + prev = self.tv.get_children() + self.tv.detach() # this should do nothing + self.assertEqual(prev, self.tv.get_children()) + + self.assertEqual(self.tv.get_children(), (item_id, )) + self.assertEqual(self.tv.get_children(item_id), (item2, )) + + # detach item with children + self.tv.detach(item_id) + self.assertFalse(self.tv.get_children()) + + # reattach item with children + self.tv.reattach(item_id, '', 'end') + self.assertEqual(self.tv.get_children(), (item_id, )) + self.assertEqual(self.tv.get_children(item_id), (item2, )) + + # move a children to the root + self.tv.move(item2, '', 'end') + self.assertEqual(self.tv.get_children(), (item_id, item2)) + self.assertEqual(self.tv.get_children(item_id), ()) + + # bad values + self.assertRaises(tkinter.TclError, + self.tv.reattach, 'nonexistent', '', 'end') + self.assertRaises(tkinter.TclError, + self.tv.detach, 'nonexistent') + self.assertRaises(tkinter.TclError, + self.tv.reattach, item2, 'otherparent', 'end') + self.assertRaises(tkinter.TclError, + self.tv.reattach, item2, '', 'invalid') + + # multiple detach + self.tv.detach(item_id, item2) + self.assertEqual(self.tv.get_children(), ()) + self.assertEqual(self.tv.get_children(item_id), ()) + + def test_exists(self): + self.assertEqual(self.tv.exists('something'), False) + self.assertEqual(self.tv.exists(''), True) + self.assertEqual(self.tv.exists({}), False) + + # the following will make a tk.call equivalent to + # tk.call(treeview, "exists") which should result in an error + # in the tcl interpreter since tk requires an item. + self.assertRaises(tkinter.TclError, self.tv.exists, None) + + def test_focus(self): + # nothing is focused right now + self.assertEqual(self.tv.focus(), '') + + item1 = self.tv.insert('', 'end') + self.tv.focus(item1) + self.assertEqual(self.tv.focus(), item1) + + self.tv.delete(item1) + self.assertEqual(self.tv.focus(), '') + + # try focusing inexistent item + self.assertRaises(tkinter.TclError, self.tv.focus, 'hi') + + def test_heading(self): + # check a dict is returned + self.assertIsInstance(self.tv.heading('#0'), dict) + + # check a value is returned + self.tv.heading('#0', text='hi') + self.assertEqual(self.tv.heading('#0', 'text'), 'hi') + self.assertEqual(self.tv.heading('#0', text=None), 'hi') + + # invalid option + self.assertRaises(tkinter.TclError, self.tv.heading, '#0', + background=None) + # invalid value + self.assertRaises(tkinter.TclError, self.tv.heading, '#0', + anchor=1) + + def test_heading_callback(self): + def simulate_heading_click(x, y): + if tcl_version >= (8, 6): + self.assertEqual(self.tv.identify_column(x), '#0') + self.assertEqual(self.tv.identify_region(x, y), 'heading') + simulate_mouse_click(self.tv, x, y) + self.tv.update() + + success = [] # no success for now + + self.tv.pack() + self.tv.heading('#0', command=lambda: success.append(True)) + self.tv.column('#0', width=100) + self.tv.update() + + # assuming that the coords (5, 5) fall into heading #0 + simulate_heading_click(5, 5) + if not success: + self.fail("The command associated to the treeview heading wasn't " + "invoked.") + + success = [] + commands = self.tv.master._tclCommands + self.tv.heading('#0', command=str(self.tv.heading('#0', command=None))) + self.assertEqual(commands, self.tv.master._tclCommands) + simulate_heading_click(5, 5) + if not success: + self.fail("The command associated to the treeview heading wasn't " + "invoked.") + + # XXX The following raises an error in a tcl interpreter, but not in + # Python + #self.tv.heading('#0', command='I dont exist') + #simulate_heading_click(5, 5) + + def test_index(self): + # item 'what' doesn't exist + self.assertRaises(tkinter.TclError, self.tv.index, 'what') + + self.assertEqual(self.tv.index(''), 0) + + item1 = self.tv.insert('', 'end') + item2 = self.tv.insert('', 'end') + c1 = self.tv.insert(item1, 'end') + c2 = self.tv.insert(item1, 'end') + self.assertEqual(self.tv.index(item1), 0) + self.assertEqual(self.tv.index(c1), 0) + self.assertEqual(self.tv.index(c2), 1) + self.assertEqual(self.tv.index(item2), 1) + + self.tv.move(item2, '', 0) + self.assertEqual(self.tv.index(item2), 0) + self.assertEqual(self.tv.index(item1), 1) + + # check that index still works even after its parent and siblings + # have been detached + self.tv.detach(item1) + self.assertEqual(self.tv.index(c2), 1) + self.tv.detach(c1) + self.assertEqual(self.tv.index(c2), 0) + + # but it fails after item has been deleted + self.tv.delete(item1) + self.assertRaises(tkinter.TclError, self.tv.index, c2) + + def test_insert_item(self): + # parent 'none' doesn't exist + self.assertRaises(tkinter.TclError, self.tv.insert, 'none', 'end') + + # open values + self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', + open='') + self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', + open='please') + self.assertFalse(self.tv.delete(self.tv.insert('', 'end', open=True))) + self.assertFalse(self.tv.delete(self.tv.insert('', 'end', open=False))) + + # invalid index + self.assertRaises(tkinter.TclError, self.tv.insert, '', 'middle') + + # trying to duplicate item id is invalid + itemid = self.tv.insert('', 'end', 'first-item') + self.assertEqual(itemid, 'first-item') + self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', + 'first-item') + self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', + MockTclObj('first-item')) + + # unicode values + value = '\xe1ba' + item = self.tv.insert('', 'end', values=(value, )) + self.assertEqual(self.tv.item(item, 'values'), + (value,) if self.wantobjects else value) + self.assertEqual(self.tv.item(item, values=None), + (value,) if self.wantobjects else value) + + self.tv.item(item, values=self.root.splitlist(self.tv.item(item, values=None))) + self.assertEqual(self.tv.item(item, values=None), + (value,) if self.wantobjects else value) + + self.assertIsInstance(self.tv.item(item), dict) + + # erase item values + self.tv.item(item, values='') + self.assertFalse(self.tv.item(item, values=None)) + + # item tags + item = self.tv.insert('', 'end', tags=[1, 2, value]) + self.assertEqual(self.tv.item(item, tags=None), + ('1', '2', value) if self.wantobjects else + '1 2 %s' % value) + self.tv.item(item, tags=[]) + self.assertFalse(self.tv.item(item, tags=None)) + self.tv.item(item, tags=(1, 2)) + self.assertEqual(self.tv.item(item, tags=None), + ('1', '2') if self.wantobjects else '1 2') + + # values with spaces + item = self.tv.insert('', 'end', values=('a b c', + '%s %s' % (value, value))) + self.assertEqual(self.tv.item(item, values=None), + ('a b c', '%s %s' % (value, value)) if self.wantobjects else + '{a b c} {%s %s}' % (value, value)) + + # text + self.assertEqual(self.tv.item( + self.tv.insert('', 'end', text="Label here"), text=None), + "Label here") + self.assertEqual(self.tv.item( + self.tv.insert('', 'end', text=value), text=None), + value) + + # test for values which are not None + itemid = self.tv.insert('', 'end', 0) + self.assertEqual(itemid, '0') + itemid = self.tv.insert('', 'end', 0.0) + self.assertEqual(itemid, '0.0') + # this is because False resolves to 0 and element with 0 iid is already present + self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', False) + self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', '') + + def test_selection(self): + self.assertRaises(TypeError, self.tv.selection, 'spam') + # item 'none' doesn't exist + self.assertRaises(tkinter.TclError, self.tv.selection_set, 'none') + self.assertRaises(tkinter.TclError, self.tv.selection_add, 'none') + self.assertRaises(tkinter.TclError, self.tv.selection_remove, 'none') + self.assertRaises(tkinter.TclError, self.tv.selection_toggle, 'none') + + item1 = self.tv.insert('', 'end') + item2 = self.tv.insert('', 'end') + c1 = self.tv.insert(item1, 'end') + c2 = self.tv.insert(item1, 'end') + c3 = self.tv.insert(item1, 'end') + self.assertEqual(self.tv.selection(), ()) + + self.tv.selection_set(c1, item2) + self.assertEqual(self.tv.selection(), (c1, item2)) + self.tv.selection_set(c2) + self.assertEqual(self.tv.selection(), (c2,)) + + self.tv.selection_add(c1, item2) + self.assertEqual(self.tv.selection(), (c1, c2, item2)) + self.tv.selection_add(item1) + self.assertEqual(self.tv.selection(), (item1, c1, c2, item2)) + self.tv.selection_add() + self.assertEqual(self.tv.selection(), (item1, c1, c2, item2)) + + self.tv.selection_remove(item1, c3) + self.assertEqual(self.tv.selection(), (c1, c2, item2)) + self.tv.selection_remove(c2) + self.assertEqual(self.tv.selection(), (c1, item2)) + self.tv.selection_remove() + self.assertEqual(self.tv.selection(), (c1, item2)) + + self.tv.selection_toggle(c1, c3) + self.assertEqual(self.tv.selection(), (c3, item2)) + self.tv.selection_toggle(item2) + self.assertEqual(self.tv.selection(), (c3,)) + self.tv.selection_toggle() + self.assertEqual(self.tv.selection(), (c3,)) + + self.tv.insert('', 'end', id='with spaces') + self.tv.selection_set('with spaces') + self.assertEqual(self.tv.selection(), ('with spaces',)) + + self.tv.insert('', 'end', id='{brace') + self.tv.selection_set('{brace') + self.assertEqual(self.tv.selection(), ('{brace',)) + + self.tv.insert('', 'end', id='unicode\u20ac') + self.tv.selection_set('unicode\u20ac') + self.assertEqual(self.tv.selection(), ('unicode\u20ac',)) + + self.tv.insert('', 'end', id=b'bytes\xe2\x82\xac') + self.tv.selection_set(b'bytes\xe2\x82\xac') + self.assertEqual(self.tv.selection(), ('bytes\xe2\x82\xac',)) + + self.tv.selection_set() + self.assertEqual(self.tv.selection(), ()) + + # Old interface + self.tv.selection_set((c1, item2)) + self.assertEqual(self.tv.selection(), (c1, item2)) + self.tv.selection_add((c1, item1)) + self.assertEqual(self.tv.selection(), (item1, c1, item2)) + self.tv.selection_remove((item1, c3)) + self.assertEqual(self.tv.selection(), (c1, item2)) + self.tv.selection_toggle((c1, c3)) + self.assertEqual(self.tv.selection(), (c3, item2)) + + def test_set(self): + self.tv['columns'] = ['A', 'B'] + item = self.tv.insert('', 'end', values=['a', 'b']) + self.assertEqual(self.tv.set(item), {'A': 'a', 'B': 'b'}) + + self.tv.set(item, 'B', 'a') + self.assertEqual(self.tv.item(item, values=None), + ('a', 'a') if self.wantobjects else 'a a') + + self.tv['columns'] = ['B'] + self.assertEqual(self.tv.set(item), {'B': 'a'}) + + self.tv.set(item, 'B', 'b') + self.assertEqual(self.tv.set(item, column='B'), 'b') + self.assertEqual(self.tv.item(item, values=None), + ('b', 'a') if self.wantobjects else 'b a') + + self.tv.set(item, 'B', 123) + self.assertEqual(self.tv.set(item, 'B'), + 123 if self.wantobjects else '123') + self.assertEqual(self.tv.item(item, values=None), + (123, 'a') if self.wantobjects else '123 a') + self.assertEqual(self.tv.set(item), + {'B': 123} if self.wantobjects else {'B': '123'}) + + # inexistent column + self.assertRaises(tkinter.TclError, self.tv.set, item, 'A') + self.assertRaises(tkinter.TclError, self.tv.set, item, 'A', 'b') + + # inexistent item + self.assertRaises(tkinter.TclError, self.tv.set, 'notme') + + def test_tag_bind(self): + events = [] + item1 = self.tv.insert('', 'end', tags=['call']) + item2 = self.tv.insert('', 'end', tags=['call']) + self.tv.tag_bind('call', '', + lambda evt: events.append(1)) + self.tv.tag_bind('call', '', + lambda evt: events.append(2)) + + self.tv.pack() + self.tv.update() + + pos_y = set() + found = set() + for i in range(0, 100, 10): + if len(found) == 2: # item1 and item2 already found + break + item_id = self.tv.identify_row(i) + if item_id and item_id not in found: + pos_y.add(i) + found.add(item_id) + + self.assertEqual(len(pos_y), 2) # item1 and item2 y pos + for y in pos_y: + simulate_mouse_click(self.tv, 0, y) + + # by now there should be 4 things in the events list, since each + # item had a bind for two events that were simulated above + self.assertEqual(len(events), 4) + for evt in zip(events[::2], events[1::2]): + self.assertEqual(evt, (1, 2)) + + def test_tag_configure(self): + # Just testing parameter passing for now + self.assertRaises(TypeError, self.tv.tag_configure) + self.assertRaises(tkinter.TclError, self.tv.tag_configure, + 'test', sky='blue') + self.tv.tag_configure('test', foreground='blue') + self.assertEqual(str(self.tv.tag_configure('test', 'foreground')), + 'blue') + self.assertEqual(str(self.tv.tag_configure('test', foreground=None)), + 'blue') + self.assertIsInstance(self.tv.tag_configure('test'), dict) + + def test_tag_has(self): + item1 = self.tv.insert('', 'end', text='Item 1', tags=['tag1']) + item2 = self.tv.insert('', 'end', text='Item 2', tags=['tag2']) + self.assertRaises(TypeError, self.tv.tag_has) + self.assertRaises(TclError, self.tv.tag_has, 'tag1', 'non-existing') + self.assertTrue(self.tv.tag_has('tag1', item1)) + self.assertFalse(self.tv.tag_has('tag1', item2)) + self.assertFalse(self.tv.tag_has('tag2', item1)) + self.assertTrue(self.tv.tag_has('tag2', item2)) + self.assertFalse(self.tv.tag_has('tag3', item1)) + self.assertFalse(self.tv.tag_has('tag3', item2)) + self.assertEqual(self.tv.tag_has('tag1'), (item1,)) + self.assertEqual(self.tv.tag_has('tag2'), (item2,)) + self.assertEqual(self.tv.tag_has('tag3'), ()) + + +@add_standard_options(StandardTtkOptionsTests) +class SeparatorTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'class', 'cursor', 'orient', 'style', 'takefocus', + # 'state'? + ) + default_orient = 'horizontal' + + def create(self, **kwargs): + return ttk.Separator(self.root, **kwargs) + + +@add_standard_options(StandardTtkOptionsTests) +class SizegripTest(AbstractWidgetTest, unittest.TestCase): + OPTIONS = ( + 'class', 'cursor', 'style', 'takefocus', + # 'state'? + ) + + 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, DefaultRootTest, + ) + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_ttk_guionly.py b/Lib/test/test_ttk_guionly.py deleted file mode 100644 index c491904..0000000 --- a/Lib/test/test_ttk_guionly.py +++ /dev/null @@ -1,40 +0,0 @@ -import unittest -from test import support -from test.support import import_helper -from test.support import check_sanitizer - -if check_sanitizer(address=True, memory=True): - raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds") - -# Skip this test if _tkinter wasn't built. -import_helper.import_module('_tkinter') - -# Skip test if tk cannot be initialized. -support.requires('gui') - -import tkinter -from _tkinter import TclError -from tkinter import ttk - - -def setUpModule(): - root = None - try: - root = tkinter.Tk() - button = ttk.Button(root) - button.destroy() - del button - except TclError as msg: - # assuming ttk is not available - raise unittest.SkipTest("ttk not available: %s" % msg) - finally: - if root is not None: - root.destroy() - del root - -def load_tests(loader, tests, pattern): - return loader.discover('tkinter.test.test_ttk') - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/tkinter/test/README b/Lib/tkinter/test/README deleted file mode 100644 index 79cd16c..0000000 --- a/Lib/tkinter/test/README +++ /dev/null @@ -1,14 +0,0 @@ -Writing new tests -================= - -Precaution ----------- - - New tests should always use only one Tk window at once, like all the - current tests do. This means that you have to destroy the current window - before creating another one, and clean up after the test. The motivation - behind this is that some tests may depend on having its window focused - while it is running to work properly, and it may be hard to force focus - on your window across platforms (right now only test_traversal at - test_ttk.test_widgets.NotebookTest depends on this). - diff --git a/Lib/tkinter/test/__init__.py b/Lib/tkinter/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py deleted file mode 100644 index 9154eba..0000000 --- a/Lib/tkinter/test/support.py +++ /dev/null @@ -1,135 +0,0 @@ -import functools -import tkinter -import unittest - -class AbstractTkTest: - - @classmethod - def setUpClass(cls): - cls._old_support_default_root = tkinter._support_default_root - destroy_default_root() - tkinter.NoDefaultRoot() - cls.root = tkinter.Tk() - cls.wantobjects = cls.root.wantobjects() - # De-maximize main window. - # Some window managers can maximize new windows. - cls.root.wm_state('normal') - try: - cls.root.wm_attributes('-zoomed', False) - except tkinter.TclError: - pass - - @classmethod - def tearDownClass(cls): - cls.root.update_idletasks() - cls.root.destroy() - del cls.root - tkinter._default_root = None - tkinter._support_default_root = cls._old_support_default_root - - def setUp(self): - self.root.deiconify() - - def tearDown(self): - for w in self.root.winfo_children(): - 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() - tkinter._default_root.destroy() - tkinter._default_root = None - -def simulate_mouse_click(widget, x, y): - """Generate proper events to click at the x, y position (tries to act - like an X server).""" - widget.event_generate('', x=0, y=0) - widget.event_generate('', x=x, y=y) - widget.event_generate('', x=x, y=y) - widget.event_generate('', x=x, y=y) - - -import _tkinter -tcl_version = tuple(map(int, _tkinter.TCL_VERSION.split('.'))) - -def requires_tcl(*version): - if len(version) <= 2: - return unittest.skipUnless(tcl_version >= version, - 'requires Tcl version >= ' + '.'.join(map(str, version))) - - def deco(test): - @functools.wraps(test) - def newtest(self): - if get_tk_patchlevel() < version: - self.skipTest('requires Tcl version >= ' + - '.'.join(map(str, version))) - test(self) - return newtest - return deco - -_tk_patchlevel = None -def get_tk_patchlevel(): - global _tk_patchlevel - if _tk_patchlevel is None: - tcl = tkinter.Tcl() - _tk_patchlevel = tcl.info_patchlevel() - return _tk_patchlevel - -units = { - 'c': 72 / 2.54, # centimeters - 'i': 72, # inches - 'm': 72 / 25.4, # millimeters - 'p': 1, # points -} - -def pixels_conv(value): - return float(value[:-1]) * units[value[-1:]] - -def tcl_obj_eq(actual, expected): - if actual == expected: - return True - if isinstance(actual, _tkinter.Tcl_Obj): - if isinstance(expected, str): - return str(actual) == expected - if isinstance(actual, tuple): - if isinstance(expected, tuple): - return (len(actual) == len(expected) and - all(tcl_obj_eq(act, exp) - for act, exp in zip(actual, expected))) - return False - -def widget_eq(actual, expected): - if actual == expected: - return True - if isinstance(actual, (str, tkinter.Widget)): - if isinstance(expected, (str, tkinter.Widget)): - return str(actual) == str(expected) - return False diff --git a/Lib/tkinter/test/test_tkinter/__init__.py b/Lib/tkinter/test/test_tkinter/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Lib/tkinter/test/test_tkinter/test_colorchooser.py b/Lib/tkinter/test/test_tkinter/test_colorchooser.py deleted file mode 100644 index 488162f..0000000 --- a/Lib/tkinter/test/test_tkinter/test_colorchooser.py +++ /dev/null @@ -1,68 +0,0 @@ -import unittest -import tkinter -from test.support import requires, swap_attr -from tkinter.test.support import AbstractDefaultRootTest, AbstractTkTest -from tkinter import colorchooser -from tkinter.colorchooser import askcolor -from tkinter.commondialog import Dialog - -requires('gui') - - -class ChooserTest(AbstractTkTest, unittest.TestCase): - - @classmethod - def setUpClass(cls): - AbstractTkTest.setUpClass.__func__(cls) - cls.cc = colorchooser.Chooser(initialcolor='dark blue slate') - - def test_fixoptions(self): - cc = self.cc - cc._fixoptions() - self.assertEqual(cc.options['initialcolor'], 'dark blue slate') - - cc.options['initialcolor'] = '#D2D269691E1E' - cc._fixoptions() - self.assertEqual(cc.options['initialcolor'], '#D2D269691E1E') - - cc.options['initialcolor'] = (210, 105, 30) - cc._fixoptions() - self.assertEqual(cc.options['initialcolor'], '#d2691e') - - def test_fixresult(self): - cc = self.cc - self.assertEqual(cc._fixresult(self.root, ()), (None, None)) - self.assertEqual(cc._fixresult(self.root, ''), (None, None)) - self.assertEqual(cc._fixresult(self.root, 'chocolate'), - ((210, 105, 30), 'chocolate')) - self.assertEqual(cc._fixresult(self.root, '#4a3c8c'), - ((74, 60, 140), '#4a3c8c')) - - -class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): - - def test_askcolor(self): - def test_callback(dialog, master): - nonlocal ismapped - master.update() - ismapped = master.winfo_ismapped() - raise ZeroDivisionError - - with swap_attr(Dialog, '_test_callback', test_callback): - ismapped = None - self.assertRaises(ZeroDivisionError, askcolor) - #askcolor() - self.assertEqual(ismapped, False) - - root = tkinter.Tk() - ismapped = None - self.assertRaises(ZeroDivisionError, askcolor) - self.assertEqual(ismapped, True) - root.destroy() - - tkinter.NoDefaultRoot() - self.assertRaises(RuntimeError, askcolor) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_tkinter/test_font.py b/Lib/tkinter/test/test_tkinter/test_font.py deleted file mode 100644 index 058c53a..0000000 --- a/Lib/tkinter/test/test_tkinter/test_font.py +++ /dev/null @@ -1,163 +0,0 @@ -import unittest -import tkinter -from tkinter import font -from test.support import requires, gc_collect, ALWAYS_EQ -from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest - -requires('gui') - -fontname = "TkDefaultFont" - -class FontTest(AbstractTkTest, unittest.TestCase): - - @classmethod - def setUpClass(cls): - AbstractTkTest.setUpClass.__func__(cls) - try: - cls.font = font.Font(root=cls.root, name=fontname, exists=True) - except tkinter.TclError: - cls.font = font.Font(root=cls.root, name=fontname, exists=False) - - def test_configure(self): - options = self.font.configure() - self.assertGreaterEqual(set(options), - {'family', 'size', 'weight', 'slant', 'underline', 'overstrike'}) - for key in options: - self.assertEqual(self.font.cget(key), options[key]) - self.assertEqual(self.font[key], options[key]) - for key in 'family', 'weight', 'slant': - self.assertIsInstance(options[key], str) - self.assertIsInstance(self.font.cget(key), str) - self.assertIsInstance(self.font[key], str) - sizetype = int if self.wantobjects else str - for key in 'size', 'underline', 'overstrike': - self.assertIsInstance(options[key], sizetype) - self.assertIsInstance(self.font.cget(key), sizetype) - self.assertIsInstance(self.font[key], sizetype) - - def test_unicode_family(self): - family = 'MS \u30b4\u30b7\u30c3\u30af' - try: - f = font.Font(root=self.root, family=family, exists=True) - except tkinter.TclError: - f = font.Font(root=self.root, family=family, exists=False) - self.assertEqual(f.cget('family'), family) - del f - gc_collect() - - def test_actual(self): - options = self.font.actual() - self.assertGreaterEqual(set(options), - {'family', 'size', 'weight', 'slant', 'underline', 'overstrike'}) - for key in options: - self.assertEqual(self.font.actual(key), options[key]) - for key in 'family', 'weight', 'slant': - self.assertIsInstance(options[key], str) - self.assertIsInstance(self.font.actual(key), str) - sizetype = int if self.wantobjects else str - for key in 'size', 'underline', 'overstrike': - self.assertIsInstance(options[key], sizetype) - self.assertIsInstance(self.font.actual(key), sizetype) - - def test_name(self): - self.assertEqual(self.font.name, fontname) - self.assertEqual(str(self.font), fontname) - - def test_equality(self): - font1 = font.Font(root=self.root, name=fontname, exists=True) - font2 = font.Font(root=self.root, name=fontname, exists=True) - self.assertIsNot(font1, font2) - self.assertEqual(font1, font2) - self.assertNotEqual(font1, font1.copy()) - - self.assertNotEqual(font1, 0) - self.assertEqual(font1, ALWAYS_EQ) - - root2 = tkinter.Tk() - self.addCleanup(root2.destroy) - font3 = font.Font(root=root2, name=fontname, exists=True) - self.assertEqual(str(font1), str(font3)) - self.assertNotEqual(font1, font3) - - def test_measure(self): - self.assertIsInstance(self.font.measure('abc'), int) - - def test_metrics(self): - metrics = self.font.metrics() - self.assertGreaterEqual(set(metrics), - {'ascent', 'descent', 'linespace', 'fixed'}) - for key in metrics: - self.assertEqual(self.font.metrics(key), metrics[key]) - self.assertIsInstance(metrics[key], int) - self.assertIsInstance(self.font.metrics(key), int) - - def test_families(self): - families = font.families(self.root) - self.assertIsInstance(families, tuple) - self.assertTrue(families) - for family in families: - self.assertIsInstance(family, str) - self.assertTrue(family) - - def test_names(self): - names = font.names(self.root) - self.assertIsInstance(names, tuple) - self.assertTrue(names) - for name in names: - self.assertIsInstance(name, str) - self.assertTrue(name) - self.assertIn(fontname, names) - - def test_nametofont(self): - testfont = font.nametofont(fontname, root=self.root) - self.assertIsInstance(testfont, font.Font) - self.assertEqual(testfont.name, fontname) - - def test_repr(self): - self.assertEqual( - repr(self.font), f'' - ) - - -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) - - def test_nametofont(self): - self.assertRaises(RuntimeError, font.nametofont, fontname) - root = tkinter.Tk() - testfont = font.nametofont(fontname) - self.assertIsInstance(testfont, font.Font) - self.assertEqual(testfont.name, fontname) - root.destroy() - tkinter.NoDefaultRoot() - self.assertRaises(RuntimeError, font.nametofont, fontname) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_tkinter/test_geometry_managers.py b/Lib/tkinter/test/test_tkinter/test_geometry_managers.py deleted file mode 100644 index c89bc8d..0000000 --- a/Lib/tkinter/test/test_tkinter/test_geometry_managers.py +++ /dev/null @@ -1,899 +0,0 @@ -import unittest -import re -import tkinter -from tkinter import TclError -from test.support import requires - -from tkinter.test.support import pixels_conv -from tkinter.test.widget_tests import AbstractWidgetTest - -requires('gui') - - -class PackTest(AbstractWidgetTest, unittest.TestCase): - - test_keys = None - - def create2(self): - pack = tkinter.Toplevel(self.root, name='pack') - pack.wm_geometry('300x200+0+0') - pack.wm_minsize(1, 1) - a = tkinter.Frame(pack, name='a', width=20, height=40, bg='red') - b = tkinter.Frame(pack, name='b', width=50, height=30, bg='blue') - c = tkinter.Frame(pack, name='c', width=80, height=80, bg='green') - d = tkinter.Frame(pack, name='d', width=40, height=30, bg='yellow') - return pack, a, b, c, d - - def test_pack_configure_after(self): - pack, a, b, c, d = self.create2() - with self.assertRaisesRegex(TclError, 'window "%s" isn\'t packed' % b): - a.pack_configure(after=b) - with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'): - a.pack_configure(after='.foo') - a.pack_configure(side='top') - b.pack_configure(side='top') - c.pack_configure(side='top') - d.pack_configure(side='top') - self.assertEqual(pack.pack_slaves(), [a, b, c, d]) - a.pack_configure(after=b) - self.assertEqual(pack.pack_slaves(), [b, a, c, d]) - a.pack_configure(after=a) - self.assertEqual(pack.pack_slaves(), [b, a, c, d]) - - def test_pack_configure_anchor(self): - pack, a, b, c, d = self.create2() - def check(anchor, geom): - a.pack_configure(side='top', ipadx=5, padx=10, ipady=15, pady=20, - expand=True, anchor=anchor) - self.root.update() - self.assertEqual(a.winfo_geometry(), geom) - check('n', '30x70+135+20') - check('ne', '30x70+260+20') - check('e', '30x70+260+65') - check('se', '30x70+260+110') - check('s', '30x70+135+110') - check('sw', '30x70+10+110') - check('w', '30x70+10+65') - check('nw', '30x70+10+20') - check('center', '30x70+135+65') - - def test_pack_configure_before(self): - pack, a, b, c, d = self.create2() - with self.assertRaisesRegex(TclError, 'window "%s" isn\'t packed' % b): - a.pack_configure(before=b) - with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'): - a.pack_configure(before='.foo') - a.pack_configure(side='top') - b.pack_configure(side='top') - c.pack_configure(side='top') - d.pack_configure(side='top') - self.assertEqual(pack.pack_slaves(), [a, b, c, d]) - a.pack_configure(before=d) - self.assertEqual(pack.pack_slaves(), [b, c, a, d]) - a.pack_configure(before=a) - self.assertEqual(pack.pack_slaves(), [b, c, a, d]) - - def test_pack_configure_expand(self): - pack, a, b, c, d = self.create2() - def check(*geoms): - self.root.update() - self.assertEqual(a.winfo_geometry(), geoms[0]) - self.assertEqual(b.winfo_geometry(), geoms[1]) - self.assertEqual(c.winfo_geometry(), geoms[2]) - self.assertEqual(d.winfo_geometry(), geoms[3]) - a.pack_configure(side='left') - b.pack_configure(side='top') - c.pack_configure(side='right') - d.pack_configure(side='bottom') - check('20x40+0+80', '50x30+135+0', '80x80+220+75', '40x30+100+170') - a.pack_configure(side='left', expand='yes') - b.pack_configure(side='top', expand='on') - c.pack_configure(side='right', expand=True) - d.pack_configure(side='bottom', expand=1) - check('20x40+40+80', '50x30+175+35', '80x80+180+110', '40x30+100+135') - a.pack_configure(side='left', expand='yes', fill='both') - b.pack_configure(side='top', expand='on', fill='both') - c.pack_configure(side='right', expand=True, fill='both') - d.pack_configure(side='bottom', expand=1, fill='both') - check('100x200+0+0', '200x100+100+0', '160x100+140+100', '40x100+100+100') - - def test_pack_configure_in(self): - pack, a, b, c, d = self.create2() - a.pack_configure(side='top') - b.pack_configure(side='top') - c.pack_configure(side='top') - d.pack_configure(side='top') - a.pack_configure(in_=pack) - self.assertEqual(pack.pack_slaves(), [b, c, d, a]) - a.pack_configure(in_=c) - self.assertEqual(pack.pack_slaves(), [b, c, d]) - self.assertEqual(c.pack_slaves(), [a]) - with self.assertRaisesRegex(TclError, - 'can\'t pack %s inside itself' % (a,)): - a.pack_configure(in_=a) - with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'): - a.pack_configure(in_='.foo') - - def test_pack_configure_padx_ipadx_fill(self): - pack, a, b, c, d = self.create2() - def check(geom1, geom2, **kwargs): - a.pack_forget() - b.pack_forget() - a.pack_configure(**kwargs) - b.pack_configure(expand=True, fill='both') - self.root.update() - self.assertEqual(a.winfo_geometry(), geom1) - self.assertEqual(b.winfo_geometry(), geom2) - check('20x40+260+80', '240x200+0+0', side='right', padx=20) - check('20x40+250+80', '240x200+0+0', side='right', padx=(10, 30)) - check('60x40+240+80', '240x200+0+0', side='right', ipadx=20) - check('30x40+260+80', '250x200+0+0', side='right', ipadx=5, padx=10) - check('20x40+260+80', '240x200+0+0', side='right', padx=20, fill='x') - check('20x40+249+80', '240x200+0+0', - side='right', padx=(9, 31), fill='x') - check('60x40+240+80', '240x200+0+0', side='right', ipadx=20, fill='x') - check('30x40+260+80', '250x200+0+0', - side='right', ipadx=5, padx=10, fill='x') - check('30x40+255+80', '250x200+0+0', - side='right', ipadx=5, padx=(5, 15), fill='x') - check('20x40+140+0', '300x160+0+40', side='top', padx=20) - check('20x40+120+0', '300x160+0+40', side='top', padx=(0, 40)) - check('60x40+120+0', '300x160+0+40', side='top', ipadx=20) - check('30x40+135+0', '300x160+0+40', side='top', ipadx=5, padx=10) - check('30x40+130+0', '300x160+0+40', side='top', ipadx=5, padx=(5, 15)) - check('260x40+20+0', '300x160+0+40', side='top', padx=20, fill='x') - check('260x40+25+0', '300x160+0+40', - side='top', padx=(25, 15), fill='x') - check('300x40+0+0', '300x160+0+40', side='top', ipadx=20, fill='x') - check('280x40+10+0', '300x160+0+40', - side='top', ipadx=5, padx=10, fill='x') - check('280x40+5+0', '300x160+0+40', - side='top', ipadx=5, padx=(5, 15), fill='x') - a.pack_configure(padx='1c') - self.assertEqual(a.pack_info()['padx'], - self._str(pack.winfo_pixels('1c'))) - a.pack_configure(ipadx='1c') - self.assertEqual(a.pack_info()['ipadx'], - self._str(pack.winfo_pixels('1c'))) - - def test_pack_configure_pady_ipady_fill(self): - pack, a, b, c, d = self.create2() - def check(geom1, geom2, **kwargs): - a.pack_forget() - b.pack_forget() - a.pack_configure(**kwargs) - b.pack_configure(expand=True, fill='both') - self.root.update() - self.assertEqual(a.winfo_geometry(), geom1) - self.assertEqual(b.winfo_geometry(), geom2) - check('20x40+280+80', '280x200+0+0', side='right', pady=20) - check('20x40+280+70', '280x200+0+0', side='right', pady=(10, 30)) - check('20x80+280+60', '280x200+0+0', side='right', ipady=20) - check('20x50+280+75', '280x200+0+0', side='right', ipady=5, pady=10) - check('20x40+280+80', '280x200+0+0', side='right', pady=20, fill='x') - check('20x40+280+69', '280x200+0+0', - side='right', pady=(9, 31), fill='x') - check('20x80+280+60', '280x200+0+0', side='right', ipady=20, fill='x') - check('20x50+280+75', '280x200+0+0', - side='right', ipady=5, pady=10, fill='x') - check('20x50+280+70', '280x200+0+0', - side='right', ipady=5, pady=(5, 15), fill='x') - check('20x40+140+20', '300x120+0+80', side='top', pady=20) - check('20x40+140+0', '300x120+0+80', side='top', pady=(0, 40)) - check('20x80+140+0', '300x120+0+80', side='top', ipady=20) - check('20x50+140+10', '300x130+0+70', side='top', ipady=5, pady=10) - check('20x50+140+5', '300x130+0+70', side='top', ipady=5, pady=(5, 15)) - check('300x40+0+20', '300x120+0+80', side='top', pady=20, fill='x') - check('300x40+0+25', '300x120+0+80', - side='top', pady=(25, 15), fill='x') - check('300x80+0+0', '300x120+0+80', side='top', ipady=20, fill='x') - check('300x50+0+10', '300x130+0+70', - side='top', ipady=5, pady=10, fill='x') - check('300x50+0+5', '300x130+0+70', - side='top', ipady=5, pady=(5, 15), fill='x') - a.pack_configure(pady='1c') - self.assertEqual(a.pack_info()['pady'], - self._str(pack.winfo_pixels('1c'))) - a.pack_configure(ipady='1c') - self.assertEqual(a.pack_info()['ipady'], - self._str(pack.winfo_pixels('1c'))) - - def test_pack_configure_side(self): - pack, a, b, c, d = self.create2() - def check(side, geom1, geom2): - a.pack_configure(side=side) - self.assertEqual(a.pack_info()['side'], side) - b.pack_configure(expand=True, fill='both') - self.root.update() - self.assertEqual(a.winfo_geometry(), geom1) - self.assertEqual(b.winfo_geometry(), geom2) - check('top', '20x40+140+0', '300x160+0+40') - check('bottom', '20x40+140+160', '300x160+0+0') - check('left', '20x40+0+80', '280x200+20+0') - check('right', '20x40+280+80', '280x200+0+0') - - def test_pack_forget(self): - pack, a, b, c, d = self.create2() - a.pack_configure() - b.pack_configure() - c.pack_configure() - self.assertEqual(pack.pack_slaves(), [a, b, c]) - b.pack_forget() - self.assertEqual(pack.pack_slaves(), [a, c]) - b.pack_forget() - self.assertEqual(pack.pack_slaves(), [a, c]) - d.pack_forget() - - def test_pack_info(self): - pack, a, b, c, d = self.create2() - with self.assertRaisesRegex(TclError, 'window "%s" isn\'t packed' % a): - a.pack_info() - a.pack_configure() - b.pack_configure(side='right', in_=a, anchor='s', expand=True, fill='x', - ipadx=5, padx=10, ipady=2, pady=(5, 15)) - info = a.pack_info() - self.assertIsInstance(info, dict) - self.assertEqual(info['anchor'], 'center') - self.assertEqual(info['expand'], self._str(0)) - self.assertEqual(info['fill'], 'none') - self.assertEqual(info['in'], pack) - self.assertEqual(info['ipadx'], self._str(0)) - self.assertEqual(info['ipady'], self._str(0)) - self.assertEqual(info['padx'], self._str(0)) - self.assertEqual(info['pady'], self._str(0)) - self.assertEqual(info['side'], 'top') - info = b.pack_info() - self.assertIsInstance(info, dict) - self.assertEqual(info['anchor'], 's') - self.assertEqual(info['expand'], self._str(1)) - self.assertEqual(info['fill'], 'x') - self.assertEqual(info['in'], a) - self.assertEqual(info['ipadx'], self._str(5)) - self.assertEqual(info['ipady'], self._str(2)) - self.assertEqual(info['padx'], self._str(10)) - self.assertEqual(info['pady'], self._str((5, 15))) - self.assertEqual(info['side'], 'right') - - def test_pack_propagate(self): - pack, a, b, c, d = self.create2() - pack.configure(width=300, height=200) - a.pack_configure() - pack.pack_propagate(False) - self.root.update() - self.assertEqual(pack.winfo_reqwidth(), 300) - self.assertEqual(pack.winfo_reqheight(), 200) - pack.pack_propagate(True) - self.root.update() - self.assertEqual(pack.winfo_reqwidth(), 20) - self.assertEqual(pack.winfo_reqheight(), 40) - - def test_pack_slaves(self): - pack, a, b, c, d = self.create2() - self.assertEqual(pack.pack_slaves(), []) - a.pack_configure() - self.assertEqual(pack.pack_slaves(), [a]) - b.pack_configure() - self.assertEqual(pack.pack_slaves(), [a, b]) - - -class PlaceTest(AbstractWidgetTest, unittest.TestCase): - - test_keys = None - - def create2(self): - t = tkinter.Toplevel(self.root, width=300, height=200, bd=0) - t.wm_geometry('300x200+0+0') - f = tkinter.Frame(t, width=154, height=84, bd=2, relief='raised') - f.place_configure(x=48, y=38) - f2 = tkinter.Frame(t, width=30, height=60, bd=2, relief='raised') - self.root.update() - return t, f, f2 - - def test_place_configure_in(self): - t, f, f2 = self.create2() - self.assertEqual(f2.winfo_manager(), '') - with self.assertRaisesRegex(TclError, "can't place %s relative to " - "itself" % re.escape(str(f2))): - f2.place_configure(in_=f2) - self.assertEqual(f2.winfo_manager(), '') - with self.assertRaisesRegex(TclError, 'bad window path name'): - f2.place_configure(in_='spam') - f2.place_configure(in_=f) - self.assertEqual(f2.winfo_manager(), 'place') - - def test_place_configure_x(self): - t, f, f2 = self.create2() - f2.place_configure(in_=f) - self.assertEqual(f2.place_info()['x'], '0') - self.root.update() - self.assertEqual(f2.winfo_x(), 50) - f2.place_configure(x=100) - self.assertEqual(f2.place_info()['x'], '100') - self.root.update() - self.assertEqual(f2.winfo_x(), 150) - f2.place_configure(x=-10, relx=1) - self.assertEqual(f2.place_info()['x'], '-10') - self.root.update() - self.assertEqual(f2.winfo_x(), 190) - with self.assertRaisesRegex(TclError, 'bad screen distance "spam"'): - f2.place_configure(in_=f, x='spam') - - def test_place_configure_y(self): - t, f, f2 = self.create2() - f2.place_configure(in_=f) - self.assertEqual(f2.place_info()['y'], '0') - self.root.update() - self.assertEqual(f2.winfo_y(), 40) - f2.place_configure(y=50) - self.assertEqual(f2.place_info()['y'], '50') - self.root.update() - self.assertEqual(f2.winfo_y(), 90) - f2.place_configure(y=-10, rely=1) - self.assertEqual(f2.place_info()['y'], '-10') - self.root.update() - self.assertEqual(f2.winfo_y(), 110) - with self.assertRaisesRegex(TclError, 'bad screen distance "spam"'): - f2.place_configure(in_=f, y='spam') - - def test_place_configure_relx(self): - t, f, f2 = self.create2() - f2.place_configure(in_=f) - self.assertEqual(f2.place_info()['relx'], '0') - self.root.update() - self.assertEqual(f2.winfo_x(), 50) - f2.place_configure(relx=0.5) - self.assertEqual(f2.place_info()['relx'], '0.5') - self.root.update() - self.assertEqual(f2.winfo_x(), 125) - f2.place_configure(relx=1) - self.assertEqual(f2.place_info()['relx'], '1') - self.root.update() - self.assertEqual(f2.winfo_x(), 200) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "spam"'): - f2.place_configure(in_=f, relx='spam') - - def test_place_configure_rely(self): - t, f, f2 = self.create2() - f2.place_configure(in_=f) - self.assertEqual(f2.place_info()['rely'], '0') - self.root.update() - self.assertEqual(f2.winfo_y(), 40) - f2.place_configure(rely=0.5) - self.assertEqual(f2.place_info()['rely'], '0.5') - self.root.update() - self.assertEqual(f2.winfo_y(), 80) - f2.place_configure(rely=1) - self.assertEqual(f2.place_info()['rely'], '1') - self.root.update() - self.assertEqual(f2.winfo_y(), 120) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "spam"'): - f2.place_configure(in_=f, rely='spam') - - def test_place_configure_anchor(self): - f = tkinter.Frame(self.root) - with self.assertRaisesRegex(TclError, 'bad anchor "j"'): - f.place_configure(anchor='j') - with self.assertRaisesRegex(TclError, 'ambiguous anchor ""'): - f.place_configure(anchor='') - for value in 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center': - f.place_configure(anchor=value) - self.assertEqual(f.place_info()['anchor'], value) - - def test_place_configure_width(self): - t, f, f2 = self.create2() - f2.place_configure(in_=f, width=120) - self.root.update() - self.assertEqual(f2.winfo_width(), 120) - f2.place_configure(width='') - self.root.update() - self.assertEqual(f2.winfo_width(), 30) - with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'): - f2.place_configure(width='abcd') - - def test_place_configure_height(self): - t, f, f2 = self.create2() - f2.place_configure(in_=f, height=120) - self.root.update() - self.assertEqual(f2.winfo_height(), 120) - f2.place_configure(height='') - self.root.update() - self.assertEqual(f2.winfo_height(), 60) - with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'): - f2.place_configure(height='abcd') - - def test_place_configure_relwidth(self): - t, f, f2 = self.create2() - f2.place_configure(in_=f, relwidth=0.5) - self.root.update() - self.assertEqual(f2.winfo_width(), 75) - f2.place_configure(relwidth='') - self.root.update() - self.assertEqual(f2.winfo_width(), 30) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "abcd"'): - f2.place_configure(relwidth='abcd') - - def test_place_configure_relheight(self): - t, f, f2 = self.create2() - f2.place_configure(in_=f, relheight=0.5) - self.root.update() - self.assertEqual(f2.winfo_height(), 40) - f2.place_configure(relheight='') - self.root.update() - self.assertEqual(f2.winfo_height(), 60) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "abcd"'): - f2.place_configure(relheight='abcd') - - def test_place_configure_bordermode(self): - f = tkinter.Frame(self.root) - with self.assertRaisesRegex(TclError, 'bad bordermode "j"'): - f.place_configure(bordermode='j') - with self.assertRaisesRegex(TclError, 'ambiguous bordermode ""'): - f.place_configure(bordermode='') - for value in 'inside', 'outside', 'ignore': - f.place_configure(bordermode=value) - self.assertEqual(f.place_info()['bordermode'], value) - - def test_place_forget(self): - foo = tkinter.Frame(self.root) - foo.place_configure(width=50, height=50) - self.root.update() - foo.place_forget() - self.root.update() - self.assertFalse(foo.winfo_ismapped()) - with self.assertRaises(TypeError): - foo.place_forget(0) - - def test_place_info(self): - t, f, f2 = self.create2() - f2.place_configure(in_=f, x=1, y=2, width=3, height=4, - relx=0.1, rely=0.2, relwidth=0.3, relheight=0.4, - anchor='se', bordermode='outside') - info = f2.place_info() - self.assertIsInstance(info, dict) - self.assertEqual(info['x'], '1') - self.assertEqual(info['y'], '2') - self.assertEqual(info['width'], '3') - self.assertEqual(info['height'], '4') - self.assertEqual(info['relx'], '0.1') - self.assertEqual(info['rely'], '0.2') - self.assertEqual(info['relwidth'], '0.3') - self.assertEqual(info['relheight'], '0.4') - self.assertEqual(info['anchor'], 'se') - self.assertEqual(info['bordermode'], 'outside') - self.assertEqual(info['x'], '1') - self.assertEqual(info['x'], '1') - with self.assertRaises(TypeError): - f2.place_info(0) - - def test_place_slaves(self): - foo = tkinter.Frame(self.root) - bar = tkinter.Frame(self.root) - self.assertEqual(foo.place_slaves(), []) - bar.place_configure(in_=foo) - self.assertEqual(foo.place_slaves(), [bar]) - with self.assertRaises(TypeError): - foo.place_slaves(0) - - -class GridTest(AbstractWidgetTest, unittest.TestCase): - - test_keys = None - - def tearDown(self): - cols, rows = self.root.grid_size() - for i in range(cols + 1): - self.root.grid_columnconfigure(i, weight=0, minsize=0, pad=0, uniform='') - for i in range(rows + 1): - self.root.grid_rowconfigure(i, weight=0, minsize=0, pad=0, uniform='') - self.root.grid_propagate(1) - self.root.grid_anchor('nw') - super().tearDown() - - def test_grid_configure(self): - b = tkinter.Button(self.root) - self.assertEqual(b.grid_info(), {}) - b.grid_configure() - self.assertEqual(b.grid_info()['in'], self.root) - self.assertEqual(b.grid_info()['column'], self._str(0)) - self.assertEqual(b.grid_info()['row'], self._str(0)) - b.grid_configure({'column': 1}, row=2) - self.assertEqual(b.grid_info()['column'], self._str(1)) - self.assertEqual(b.grid_info()['row'], self._str(2)) - - def test_grid_configure_column(self): - b = tkinter.Button(self.root) - with self.assertRaisesRegex(TclError, 'bad column value "-1": ' - 'must be a non-negative integer'): - b.grid_configure(column=-1) - b.grid_configure(column=2) - self.assertEqual(b.grid_info()['column'], self._str(2)) - - def test_grid_configure_columnspan(self): - b = tkinter.Button(self.root) - with self.assertRaisesRegex(TclError, 'bad columnspan value "0": ' - 'must be a positive integer'): - b.grid_configure(columnspan=0) - b.grid_configure(columnspan=2) - self.assertEqual(b.grid_info()['columnspan'], self._str(2)) - - def test_grid_configure_in(self): - f = tkinter.Frame(self.root) - b = tkinter.Button(self.root) - self.assertEqual(b.grid_info(), {}) - b.grid_configure() - self.assertEqual(b.grid_info()['in'], self.root) - b.grid_configure(in_=f) - self.assertEqual(b.grid_info()['in'], f) - b.grid_configure({'in': self.root}) - self.assertEqual(b.grid_info()['in'], self.root) - - def test_grid_configure_ipadx(self): - b = tkinter.Button(self.root) - with self.assertRaisesRegex(TclError, 'bad ipadx value "-1": ' - 'must be positive screen distance'): - b.grid_configure(ipadx=-1) - b.grid_configure(ipadx=1) - self.assertEqual(b.grid_info()['ipadx'], self._str(1)) - b.grid_configure(ipadx='.5c') - self.assertEqual(b.grid_info()['ipadx'], - self._str(round(pixels_conv('.5c') * self.scaling))) - - def test_grid_configure_ipady(self): - b = tkinter.Button(self.root) - with self.assertRaisesRegex(TclError, 'bad ipady value "-1": ' - 'must be positive screen distance'): - b.grid_configure(ipady=-1) - b.grid_configure(ipady=1) - self.assertEqual(b.grid_info()['ipady'], self._str(1)) - b.grid_configure(ipady='.5c') - self.assertEqual(b.grid_info()['ipady'], - self._str(round(pixels_conv('.5c') * self.scaling))) - - def test_grid_configure_padx(self): - b = tkinter.Button(self.root) - with self.assertRaisesRegex(TclError, 'bad pad value "-1": ' - 'must be positive screen distance'): - b.grid_configure(padx=-1) - b.grid_configure(padx=1) - self.assertEqual(b.grid_info()['padx'], self._str(1)) - b.grid_configure(padx=(10, 5)) - self.assertEqual(b.grid_info()['padx'], self._str((10, 5))) - b.grid_configure(padx='.5c') - self.assertEqual(b.grid_info()['padx'], - self._str(round(pixels_conv('.5c') * self.scaling))) - - def test_grid_configure_pady(self): - b = tkinter.Button(self.root) - with self.assertRaisesRegex(TclError, 'bad pad value "-1": ' - 'must be positive screen distance'): - b.grid_configure(pady=-1) - b.grid_configure(pady=1) - self.assertEqual(b.grid_info()['pady'], self._str(1)) - b.grid_configure(pady=(10, 5)) - self.assertEqual(b.grid_info()['pady'], self._str((10, 5))) - b.grid_configure(pady='.5c') - self.assertEqual(b.grid_info()['pady'], - self._str(round(pixels_conv('.5c') * self.scaling))) - - def test_grid_configure_row(self): - b = tkinter.Button(self.root) - with self.assertRaisesRegex(TclError, 'bad (row|grid) value "-1": ' - 'must be a non-negative integer'): - b.grid_configure(row=-1) - b.grid_configure(row=2) - self.assertEqual(b.grid_info()['row'], self._str(2)) - - def test_grid_configure_rownspan(self): - b = tkinter.Button(self.root) - with self.assertRaisesRegex(TclError, 'bad rowspan value "0": ' - 'must be a positive integer'): - b.grid_configure(rowspan=0) - b.grid_configure(rowspan=2) - self.assertEqual(b.grid_info()['rowspan'], self._str(2)) - - def test_grid_configure_sticky(self): - f = tkinter.Frame(self.root, bg='red') - with self.assertRaisesRegex(TclError, 'bad stickyness value "glue"'): - f.grid_configure(sticky='glue') - f.grid_configure(sticky='ne') - self.assertEqual(f.grid_info()['sticky'], 'ne') - f.grid_configure(sticky='n,s,e,w') - self.assertEqual(f.grid_info()['sticky'], 'nesw') - - def test_grid_columnconfigure(self): - with self.assertRaises(TypeError): - self.root.grid_columnconfigure() - self.assertEqual(self.root.grid_columnconfigure(0), - {'minsize': 0, 'pad': 0, 'uniform': None, 'weight': 0}) - with self.assertRaisesRegex(TclError, 'bad option "-foo"'): - self.root.grid_columnconfigure(0, 'foo') - self.root.grid_columnconfigure((0, 3), weight=2) - with self.assertRaisesRegex(TclError, - 'must specify a single element on retrieval'): - self.root.grid_columnconfigure((0, 3)) - b = tkinter.Button(self.root) - b.grid_configure(column=0, row=0) - self.root.grid_columnconfigure('all', weight=3) - with self.assertRaisesRegex(TclError, 'expected integer but got "all"'): - self.root.grid_columnconfigure('all') - self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 3) - self.assertEqual(self.root.grid_columnconfigure(3, 'weight'), 2) - self.assertEqual(self.root.grid_columnconfigure(265, 'weight'), 0) - self.root.grid_columnconfigure(b, weight=4) - self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 4) - - def test_grid_columnconfigure_minsize(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): - self.root.grid_columnconfigure(0, minsize='foo') - self.root.grid_columnconfigure(0, minsize=10) - self.assertEqual(self.root.grid_columnconfigure(0, 'minsize'), 10) - self.assertEqual(self.root.grid_columnconfigure(0)['minsize'], 10) - - def test_grid_columnconfigure_weight(self): - with self.assertRaisesRegex(TclError, 'expected integer but got "bad"'): - self.root.grid_columnconfigure(0, weight='bad') - with self.assertRaisesRegex(TclError, 'invalid arg "-weight": ' - 'should be non-negative'): - self.root.grid_columnconfigure(0, weight=-3) - self.root.grid_columnconfigure(0, weight=3) - self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 3) - self.assertEqual(self.root.grid_columnconfigure(0)['weight'], 3) - - def test_grid_columnconfigure_pad(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): - self.root.grid_columnconfigure(0, pad='foo') - with self.assertRaisesRegex(TclError, 'invalid arg "-pad": ' - 'should be non-negative'): - self.root.grid_columnconfigure(0, pad=-3) - self.root.grid_columnconfigure(0, pad=3) - self.assertEqual(self.root.grid_columnconfigure(0, 'pad'), 3) - self.assertEqual(self.root.grid_columnconfigure(0)['pad'], 3) - - def test_grid_columnconfigure_uniform(self): - self.root.grid_columnconfigure(0, uniform='foo') - self.assertEqual(self.root.grid_columnconfigure(0, 'uniform'), 'foo') - self.assertEqual(self.root.grid_columnconfigure(0)['uniform'], 'foo') - - def test_grid_rowconfigure(self): - with self.assertRaises(TypeError): - self.root.grid_rowconfigure() - self.assertEqual(self.root.grid_rowconfigure(0), - {'minsize': 0, 'pad': 0, 'uniform': None, 'weight': 0}) - with self.assertRaisesRegex(TclError, 'bad option "-foo"'): - self.root.grid_rowconfigure(0, 'foo') - self.root.grid_rowconfigure((0, 3), weight=2) - with self.assertRaisesRegex(TclError, - 'must specify a single element on retrieval'): - self.root.grid_rowconfigure((0, 3)) - b = tkinter.Button(self.root) - b.grid_configure(column=0, row=0) - self.root.grid_rowconfigure('all', weight=3) - with self.assertRaisesRegex(TclError, 'expected integer but got "all"'): - self.root.grid_rowconfigure('all') - self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 3) - self.assertEqual(self.root.grid_rowconfigure(3, 'weight'), 2) - self.assertEqual(self.root.grid_rowconfigure(265, 'weight'), 0) - self.root.grid_rowconfigure(b, weight=4) - self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 4) - - def test_grid_rowconfigure_minsize(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): - self.root.grid_rowconfigure(0, minsize='foo') - self.root.grid_rowconfigure(0, minsize=10) - self.assertEqual(self.root.grid_rowconfigure(0, 'minsize'), 10) - self.assertEqual(self.root.grid_rowconfigure(0)['minsize'], 10) - - def test_grid_rowconfigure_weight(self): - with self.assertRaisesRegex(TclError, 'expected integer but got "bad"'): - self.root.grid_rowconfigure(0, weight='bad') - with self.assertRaisesRegex(TclError, 'invalid arg "-weight": ' - 'should be non-negative'): - self.root.grid_rowconfigure(0, weight=-3) - self.root.grid_rowconfigure(0, weight=3) - self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 3) - self.assertEqual(self.root.grid_rowconfigure(0)['weight'], 3) - - def test_grid_rowconfigure_pad(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): - self.root.grid_rowconfigure(0, pad='foo') - with self.assertRaisesRegex(TclError, 'invalid arg "-pad": ' - 'should be non-negative'): - self.root.grid_rowconfigure(0, pad=-3) - self.root.grid_rowconfigure(0, pad=3) - self.assertEqual(self.root.grid_rowconfigure(0, 'pad'), 3) - self.assertEqual(self.root.grid_rowconfigure(0)['pad'], 3) - - def test_grid_rowconfigure_uniform(self): - self.root.grid_rowconfigure(0, uniform='foo') - self.assertEqual(self.root.grid_rowconfigure(0, 'uniform'), 'foo') - self.assertEqual(self.root.grid_rowconfigure(0)['uniform'], 'foo') - - def test_grid_forget(self): - b = tkinter.Button(self.root) - c = tkinter.Button(self.root) - b.grid_configure(row=2, column=2, rowspan=2, columnspan=2, - padx=3, pady=4, sticky='ns') - self.assertEqual(self.root.grid_slaves(), [b]) - b.grid_forget() - c.grid_forget() - self.assertEqual(self.root.grid_slaves(), []) - self.assertEqual(b.grid_info(), {}) - b.grid_configure(row=0, column=0) - info = b.grid_info() - self.assertEqual(info['row'], self._str(0)) - self.assertEqual(info['column'], self._str(0)) - self.assertEqual(info['rowspan'], self._str(1)) - self.assertEqual(info['columnspan'], self._str(1)) - self.assertEqual(info['padx'], self._str(0)) - self.assertEqual(info['pady'], self._str(0)) - self.assertEqual(info['sticky'], '') - - def test_grid_remove(self): - b = tkinter.Button(self.root) - c = tkinter.Button(self.root) - b.grid_configure(row=2, column=2, rowspan=2, columnspan=2, - padx=3, pady=4, sticky='ns') - self.assertEqual(self.root.grid_slaves(), [b]) - b.grid_remove() - c.grid_remove() - self.assertEqual(self.root.grid_slaves(), []) - self.assertEqual(b.grid_info(), {}) - b.grid_configure(row=0, column=0) - info = b.grid_info() - self.assertEqual(info['row'], self._str(0)) - self.assertEqual(info['column'], self._str(0)) - self.assertEqual(info['rowspan'], self._str(2)) - self.assertEqual(info['columnspan'], self._str(2)) - self.assertEqual(info['padx'], self._str(3)) - self.assertEqual(info['pady'], self._str(4)) - self.assertEqual(info['sticky'], 'ns') - - def test_grid_info(self): - b = tkinter.Button(self.root) - self.assertEqual(b.grid_info(), {}) - b.grid_configure(row=2, column=2, rowspan=2, columnspan=2, - padx=3, pady=4, sticky='ns') - info = b.grid_info() - self.assertIsInstance(info, dict) - self.assertEqual(info['in'], self.root) - self.assertEqual(info['row'], self._str(2)) - self.assertEqual(info['column'], self._str(2)) - self.assertEqual(info['rowspan'], self._str(2)) - self.assertEqual(info['columnspan'], self._str(2)) - self.assertEqual(info['padx'], self._str(3)) - self.assertEqual(info['pady'], self._str(4)) - self.assertEqual(info['sticky'], 'ns') - - def test_grid_anchor(self): - with self.assertRaisesRegex(TclError, 'bad anchor "x"'): - self.root.grid_anchor('x') - with self.assertRaisesRegex(TclError, 'ambiguous anchor ""'): - self.root.grid_anchor('') - with self.assertRaises(TypeError): - self.root.grid_anchor('se', 'nw') - self.root.grid_anchor('se') - self.assertEqual(self.root.tk.call('grid', 'anchor', self.root), 'se') - - def test_grid_bbox(self): - self.assertEqual(self.root.grid_bbox(), (0, 0, 0, 0)) - self.assertEqual(self.root.grid_bbox(0, 0), (0, 0, 0, 0)) - self.assertEqual(self.root.grid_bbox(0, 0, 1, 1), (0, 0, 0, 0)) - with self.assertRaisesRegex(TclError, 'expected integer but got "x"'): - self.root.grid_bbox('x', 0) - with self.assertRaisesRegex(TclError, 'expected integer but got "x"'): - self.root.grid_bbox(0, 'x') - with self.assertRaisesRegex(TclError, 'expected integer but got "x"'): - self.root.grid_bbox(0, 0, 'x', 0) - with self.assertRaisesRegex(TclError, 'expected integer but got "x"'): - self.root.grid_bbox(0, 0, 0, 'x') - with self.assertRaises(TypeError): - self.root.grid_bbox(0, 0, 0, 0, 0) - t = self.root - # de-maximize - t.wm_geometry('1x1+0+0') - t.wm_geometry('') - f1 = tkinter.Frame(t, width=75, height=75, bg='red') - f2 = tkinter.Frame(t, width=90, height=90, bg='blue') - f1.grid_configure(row=0, column=0) - f2.grid_configure(row=1, column=1) - self.root.update() - self.assertEqual(t.grid_bbox(), (0, 0, 165, 165)) - self.assertEqual(t.grid_bbox(0, 0), (0, 0, 75, 75)) - self.assertEqual(t.grid_bbox(0, 0, 1, 1), (0, 0, 165, 165)) - self.assertEqual(t.grid_bbox(1, 1), (75, 75, 90, 90)) - self.assertEqual(t.grid_bbox(10, 10, 0, 0), (0, 0, 165, 165)) - self.assertEqual(t.grid_bbox(-2, -2, -1, -1), (0, 0, 0, 0)) - self.assertEqual(t.grid_bbox(10, 10, 12, 12), (165, 165, 0, 0)) - - def test_grid_location(self): - with self.assertRaises(TypeError): - self.root.grid_location() - with self.assertRaises(TypeError): - self.root.grid_location(0) - with self.assertRaises(TypeError): - self.root.grid_location(0, 0, 0) - with self.assertRaisesRegex(TclError, 'bad screen distance "x"'): - self.root.grid_location('x', 'y') - with self.assertRaisesRegex(TclError, 'bad screen distance "y"'): - self.root.grid_location('1c', 'y') - t = self.root - # de-maximize - t.wm_geometry('1x1+0+0') - t.wm_geometry('') - f = tkinter.Frame(t, width=200, height=100, - highlightthickness=0, bg='red') - self.assertEqual(f.grid_location(10, 10), (-1, -1)) - f.grid_configure() - self.root.update() - self.assertEqual(t.grid_location(-10, -10), (-1, -1)) - self.assertEqual(t.grid_location(-10, 0), (-1, 0)) - self.assertEqual(t.grid_location(-1, 0), (-1, 0)) - self.assertEqual(t.grid_location(0, -10), (0, -1)) - self.assertEqual(t.grid_location(0, -1), (0, -1)) - self.assertEqual(t.grid_location(0, 0), (0, 0)) - self.assertEqual(t.grid_location(200, 0), (0, 0)) - self.assertEqual(t.grid_location(201, 0), (1, 0)) - self.assertEqual(t.grid_location(0, 100), (0, 0)) - self.assertEqual(t.grid_location(0, 101), (0, 1)) - self.assertEqual(t.grid_location(201, 101), (1, 1)) - - def test_grid_propagate(self): - self.assertEqual(self.root.grid_propagate(), True) - with self.assertRaises(TypeError): - self.root.grid_propagate(False, False) - self.root.grid_propagate(False) - self.assertFalse(self.root.grid_propagate()) - f = tkinter.Frame(self.root, width=100, height=100, bg='red') - f.grid_configure(row=0, column=0) - self.root.update() - self.assertEqual(f.winfo_width(), 100) - self.assertEqual(f.winfo_height(), 100) - f.grid_propagate(False) - g = tkinter.Frame(self.root, width=75, height=85, bg='green') - g.grid_configure(in_=f, row=0, column=0) - self.root.update() - self.assertEqual(f.winfo_width(), 100) - self.assertEqual(f.winfo_height(), 100) - f.grid_propagate(True) - self.root.update() - self.assertEqual(f.winfo_width(), 75) - self.assertEqual(f.winfo_height(), 85) - - def test_grid_size(self): - with self.assertRaises(TypeError): - self.root.grid_size(0) - self.assertEqual(self.root.grid_size(), (0, 0)) - f = tkinter.Scale(self.root) - f.grid_configure(row=0, column=0) - self.assertEqual(self.root.grid_size(), (1, 1)) - f.grid_configure(row=4, column=5) - self.assertEqual(self.root.grid_size(), (6, 5)) - - def test_grid_slaves(self): - self.assertEqual(self.root.grid_slaves(), []) - a = tkinter.Label(self.root) - a.grid_configure(row=0, column=1) - b = tkinter.Label(self.root) - b.grid_configure(row=1, column=0) - c = tkinter.Label(self.root) - c.grid_configure(row=1, column=1) - d = tkinter.Label(self.root) - d.grid_configure(row=1, column=1) - self.assertEqual(self.root.grid_slaves(), [d, c, b, a]) - self.assertEqual(self.root.grid_slaves(row=0), [a]) - self.assertEqual(self.root.grid_slaves(row=1), [d, c, b]) - self.assertEqual(self.root.grid_slaves(column=0), [b]) - self.assertEqual(self.root.grid_slaves(column=1), [d, c, a]) - self.assertEqual(self.root.grid_slaves(row=1, column=1), [d, c]) - - -tests_gui = ( - PackTest, PlaceTest, GridTest, -) - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/tkinter/test/test_tkinter/test_images.py b/Lib/tkinter/test/test_tkinter/test_images.py deleted file mode 100644 index cc69cca..0000000 --- a/Lib/tkinter/test/test_tkinter/test_images.py +++ /dev/null @@ -1,380 +0,0 @@ -import unittest -import tkinter -from test import support -from test.support import os_helper -from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest, requires_tcl - -support.requires('gui') - - -class MiscTest(AbstractTkTest, unittest.TestCase): - - def test_image_types(self): - image_types = self.root.image_types() - self.assertIsInstance(image_types, tuple) - self.assertIn('photo', image_types) - self.assertIn('bitmap', image_types) - - def test_image_names(self): - image_names = self.root.image_names() - 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 - def setUpClass(cls): - AbstractTkTest.setUpClass.__func__(cls) - cls.testfile = support.findfile('python.xbm', subdir='imghdrdata') - - def test_create_from_file(self): - image = tkinter.BitmapImage('::img::test', master=self.root, - foreground='yellow', background='blue', - file=self.testfile) - self.assertEqual(str(image), '::img::test') - self.assertEqual(image.type(), 'bitmap') - self.assertEqual(image.width(), 16) - self.assertEqual(image.height(), 16) - self.assertIn('::img::test', self.root.image_names()) - del image - support.gc_collect() # For PyPy or other GCs. - self.assertNotIn('::img::test', self.root.image_names()) - - def test_create_from_data(self): - with open(self.testfile, 'rb') as f: - data = f.read() - image = tkinter.BitmapImage('::img::test', master=self.root, - foreground='yellow', background='blue', - data=data) - self.assertEqual(str(image), '::img::test') - self.assertEqual(image.type(), 'bitmap') - self.assertEqual(image.width(), 16) - self.assertEqual(image.height(), 16) - self.assertIn('::img::test', self.root.image_names()) - del image - support.gc_collect() # For PyPy or other GCs. - self.assertNotIn('::img::test', self.root.image_names()) - - def assertEqualStrList(self, actual, expected): - self.assertIsInstance(actual, str) - self.assertEqual(self.root.splitlist(actual), expected) - - def test_configure_data(self): - image = tkinter.BitmapImage('::img::test', master=self.root) - self.assertEqual(image['data'], '-data {} {} {} {}') - with open(self.testfile, 'rb') as f: - data = f.read() - image.configure(data=data) - self.assertEqualStrList(image['data'], - ('-data', '', '', '', data.decode('ascii'))) - self.assertEqual(image.width(), 16) - self.assertEqual(image.height(), 16) - - self.assertEqual(image['maskdata'], '-maskdata {} {} {} {}') - image.configure(maskdata=data) - self.assertEqualStrList(image['maskdata'], - ('-maskdata', '', '', '', data.decode('ascii'))) - - def test_configure_file(self): - image = tkinter.BitmapImage('::img::test', master=self.root) - self.assertEqual(image['file'], '-file {} {} {} {}') - image.configure(file=self.testfile) - self.assertEqualStrList(image['file'], - ('-file', '', '', '',self.testfile)) - self.assertEqual(image.width(), 16) - self.assertEqual(image.height(), 16) - - self.assertEqual(image['maskfile'], '-maskfile {} {} {} {}') - image.configure(maskfile=self.testfile) - self.assertEqualStrList(image['maskfile'], - ('-maskfile', '', '', '', self.testfile)) - - def test_configure_background(self): - image = tkinter.BitmapImage('::img::test', master=self.root) - self.assertEqual(image['background'], '-background {} {} {} {}') - image.configure(background='blue') - self.assertEqual(image['background'], '-background {} {} {} blue') - - def test_configure_foreground(self): - image = tkinter.BitmapImage('::img::test', master=self.root) - self.assertEqual(image['foreground'], - '-foreground {} {} #000000 #000000') - image.configure(foreground='yellow') - self.assertEqual(image['foreground'], - '-foreground {} {} #000000 yellow') - - -class PhotoImageTest(AbstractTkTest, unittest.TestCase): - - @classmethod - def setUpClass(cls): - AbstractTkTest.setUpClass.__func__(cls) - cls.testfile = support.findfile('python.gif', subdir='imghdrdata') - - def create(self): - return tkinter.PhotoImage('::img::test', master=self.root, - file=self.testfile) - - def colorlist(self, *args): - if tkinter.TkVersion >= 8.6 and self.wantobjects: - return args - else: - return tkinter._join(args) - - def check_create_from_file(self, ext): - testfile = support.findfile('python.' + ext, subdir='imghdrdata') - image = tkinter.PhotoImage('::img::test', master=self.root, - file=testfile) - self.assertEqual(str(image), '::img::test') - self.assertEqual(image.type(), 'photo') - self.assertEqual(image.width(), 16) - self.assertEqual(image.height(), 16) - self.assertEqual(image['data'], '') - self.assertEqual(image['file'], testfile) - self.assertIn('::img::test', self.root.image_names()) - del image - support.gc_collect() # For PyPy or other GCs. - self.assertNotIn('::img::test', self.root.image_names()) - - def check_create_from_data(self, ext): - testfile = support.findfile('python.' + ext, subdir='imghdrdata') - with open(testfile, 'rb') as f: - data = f.read() - image = tkinter.PhotoImage('::img::test', master=self.root, - data=data) - self.assertEqual(str(image), '::img::test') - self.assertEqual(image.type(), 'photo') - self.assertEqual(image.width(), 16) - self.assertEqual(image.height(), 16) - self.assertEqual(image['data'], data if self.wantobjects - else data.decode('latin1')) - self.assertEqual(image['file'], '') - self.assertIn('::img::test', self.root.image_names()) - del image - support.gc_collect() # For PyPy or other GCs. - self.assertNotIn('::img::test', self.root.image_names()) - - def test_create_from_ppm_file(self): - self.check_create_from_file('ppm') - - def test_create_from_ppm_data(self): - self.check_create_from_data('ppm') - - def test_create_from_pgm_file(self): - self.check_create_from_file('pgm') - - def test_create_from_pgm_data(self): - self.check_create_from_data('pgm') - - def test_create_from_gif_file(self): - self.check_create_from_file('gif') - - def test_create_from_gif_data(self): - self.check_create_from_data('gif') - - @requires_tcl(8, 6) - def test_create_from_png_file(self): - self.check_create_from_file('png') - - @requires_tcl(8, 6) - def test_create_from_png_data(self): - self.check_create_from_data('png') - - def test_configure_data(self): - image = tkinter.PhotoImage('::img::test', master=self.root) - self.assertEqual(image['data'], '') - with open(self.testfile, 'rb') as f: - data = f.read() - image.configure(data=data) - self.assertEqual(image['data'], data if self.wantobjects - else data.decode('latin1')) - self.assertEqual(image.width(), 16) - self.assertEqual(image.height(), 16) - - def test_configure_format(self): - image = tkinter.PhotoImage('::img::test', master=self.root) - self.assertEqual(image['format'], '') - image.configure(file=self.testfile, format='gif') - self.assertEqual(image['format'], ('gif',) if self.wantobjects - else 'gif') - self.assertEqual(image.width(), 16) - self.assertEqual(image.height(), 16) - - def test_configure_file(self): - image = tkinter.PhotoImage('::img::test', master=self.root) - self.assertEqual(image['file'], '') - image.configure(file=self.testfile) - self.assertEqual(image['file'], self.testfile) - self.assertEqual(image.width(), 16) - self.assertEqual(image.height(), 16) - - def test_configure_gamma(self): - image = tkinter.PhotoImage('::img::test', master=self.root) - self.assertEqual(image['gamma'], '1.0') - image.configure(gamma=2.0) - self.assertEqual(image['gamma'], '2.0') - - def test_configure_width_height(self): - image = tkinter.PhotoImage('::img::test', master=self.root) - self.assertEqual(image['width'], '0') - self.assertEqual(image['height'], '0') - image.configure(width=20) - image.configure(height=10) - self.assertEqual(image['width'], '20') - self.assertEqual(image['height'], '10') - self.assertEqual(image.width(), 20) - self.assertEqual(image.height(), 10) - - def test_configure_palette(self): - image = tkinter.PhotoImage('::img::test', master=self.root) - self.assertEqual(image['palette'], '') - image.configure(palette=256) - self.assertEqual(image['palette'], '256') - image.configure(palette='3/4/2') - self.assertEqual(image['palette'], '3/4/2') - - def test_blank(self): - image = self.create() - image.blank() - self.assertEqual(image.width(), 16) - self.assertEqual(image.height(), 16) - self.assertEqual(image.get(4, 6), self.colorlist(0, 0, 0)) - - def test_copy(self): - image = self.create() - image2 = image.copy() - self.assertEqual(image2.width(), 16) - self.assertEqual(image2.height(), 16) - self.assertEqual(image.get(4, 6), image.get(4, 6)) - - def test_subsample(self): - image = self.create() - image2 = image.subsample(2, 3) - self.assertEqual(image2.width(), 8) - self.assertEqual(image2.height(), 6) - self.assertEqual(image2.get(2, 2), image.get(4, 6)) - - image2 = image.subsample(2) - self.assertEqual(image2.width(), 8) - self.assertEqual(image2.height(), 8) - self.assertEqual(image2.get(2, 3), image.get(4, 6)) - - def test_zoom(self): - image = self.create() - image2 = image.zoom(2, 3) - self.assertEqual(image2.width(), 32) - self.assertEqual(image2.height(), 48) - self.assertEqual(image2.get(8, 18), image.get(4, 6)) - self.assertEqual(image2.get(9, 20), image.get(4, 6)) - - image2 = image.zoom(2) - self.assertEqual(image2.width(), 32) - self.assertEqual(image2.height(), 32) - self.assertEqual(image2.get(8, 12), image.get(4, 6)) - self.assertEqual(image2.get(9, 13), image.get(4, 6)) - - def test_put(self): - image = self.create() - image.put('{red green} {blue yellow}', to=(4, 6)) - self.assertEqual(image.get(4, 6), self.colorlist(255, 0, 0)) - self.assertEqual(image.get(5, 6), - self.colorlist(0, 128 if tkinter.TkVersion >= 8.6 - else 255, 0)) - self.assertEqual(image.get(4, 7), self.colorlist(0, 0, 255)) - self.assertEqual(image.get(5, 7), self.colorlist(255, 255, 0)) - - image.put((('#f00', '#00ff00'), ('#000000fff', '#ffffffff0000'))) - self.assertEqual(image.get(0, 0), self.colorlist(255, 0, 0)) - self.assertEqual(image.get(1, 0), self.colorlist(0, 255, 0)) - self.assertEqual(image.get(0, 1), self.colorlist(0, 0, 255)) - self.assertEqual(image.get(1, 1), self.colorlist(255, 255, 0)) - - def test_get(self): - image = self.create() - self.assertEqual(image.get(4, 6), self.colorlist(62, 116, 162)) - self.assertEqual(image.get(0, 0), self.colorlist(0, 0, 0)) - self.assertEqual(image.get(15, 15), self.colorlist(0, 0, 0)) - self.assertRaises(tkinter.TclError, image.get, -1, 0) - self.assertRaises(tkinter.TclError, image.get, 0, -1) - self.assertRaises(tkinter.TclError, image.get, 16, 15) - self.assertRaises(tkinter.TclError, image.get, 15, 16) - - def test_write(self): - image = self.create() - self.addCleanup(os_helper.unlink, os_helper.TESTFN) - - image.write(os_helper.TESTFN) - image2 = tkinter.PhotoImage('::img::test2', master=self.root, - format='ppm', - file=os_helper.TESTFN) - self.assertEqual(str(image2), '::img::test2') - self.assertEqual(image2.type(), 'photo') - self.assertEqual(image2.width(), 16) - self.assertEqual(image2.height(), 16) - self.assertEqual(image2.get(0, 0), image.get(0, 0)) - self.assertEqual(image2.get(15, 8), image.get(15, 8)) - - image.write(os_helper.TESTFN, format='gif', from_coords=(4, 6, 6, 9)) - image3 = tkinter.PhotoImage('::img::test3', master=self.root, - format='gif', - file=os_helper.TESTFN) - self.assertEqual(str(image3), '::img::test3') - self.assertEqual(image3.type(), 'photo') - self.assertEqual(image3.width(), 2) - self.assertEqual(image3.height(), 3) - self.assertEqual(image3.get(0, 0), image.get(4, 6)) - self.assertEqual(image3.get(1, 2), image.get(5, 8)) - - def test_transparency(self): - image = self.create() - self.assertEqual(image.transparency_get(0, 0), True) - self.assertEqual(image.transparency_get(4, 6), False) - image.transparency_set(4, 6, True) - self.assertEqual(image.transparency_get(4, 6), True) - image.transparency_set(4, 6, False) - self.assertEqual(image.transparency_get(4, 6), False) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_tkinter/test_loadtk.py b/Lib/tkinter/test/test_tkinter/test_loadtk.py deleted file mode 100644 index 61b0eda..0000000 --- a/Lib/tkinter/test/test_tkinter/test_loadtk.py +++ /dev/null @@ -1,46 +0,0 @@ -import os -import sys -import unittest -import test.support as test_support -from test.support import os_helper -from tkinter import Tcl, TclError - -test_support.requires('gui') - -class TkLoadTest(unittest.TestCase): - - @unittest.skipIf('DISPLAY' not in os.environ, 'No $DISPLAY set.') - def testLoadTk(self): - tcl = Tcl() - self.assertRaises(TclError,tcl.winfo_geometry) - tcl.loadtk() - self.assertEqual('1x1+0+0', tcl.winfo_geometry()) - tcl.destroy() - - def testLoadTkFailure(self): - old_display = None - if sys.platform.startswith(('win', 'darwin', 'cygwin')): - # no failure possible on windows? - - # XXX Maybe on tk older than 8.4.13 it would be possible, - # see tkinter.h. - return - with os_helper.EnvironmentVarGuard() as env: - if 'DISPLAY' in os.environ: - del env['DISPLAY'] - # on some platforms, deleting environment variables - # doesn't actually carry through to the process level - # because they don't support unsetenv - # If that's the case, abort. - with os.popen('echo $DISPLAY') as pipe: - display = pipe.read().strip() - if display: - return - - tcl = Tcl() - self.assertRaises(TclError, tcl.winfo_geometry) - self.assertRaises(TclError, tcl.loadtk) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_tkinter/test_messagebox.py b/Lib/tkinter/test/test_tkinter/test_messagebox.py deleted file mode 100644 index d38541a..0000000 --- a/Lib/tkinter/test/test_tkinter/test_messagebox.py +++ /dev/null @@ -1,36 +0,0 @@ -import unittest -import tkinter -from test.support import requires, swap_attr -from tkinter.test.support import AbstractDefaultRootTest -from tkinter.commondialog import Dialog -from tkinter.messagebox import showinfo - -requires('gui') - - -class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): - - def test_showinfo(self): - def test_callback(dialog, master): - nonlocal ismapped - master.update() - ismapped = master.winfo_ismapped() - raise ZeroDivisionError - - with swap_attr(Dialog, '_test_callback', test_callback): - ismapped = None - self.assertRaises(ZeroDivisionError, showinfo, "Spam", "Egg Information") - self.assertEqual(ismapped, False) - - root = tkinter.Tk() - ismapped = None - self.assertRaises(ZeroDivisionError, showinfo, "Spam", "Egg Information") - self.assertEqual(ismapped, True) - root.destroy() - - tkinter.NoDefaultRoot() - self.assertRaises(RuntimeError, showinfo, "Spam", "Egg Information") - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_tkinter/test_misc.py b/Lib/tkinter/test/test_tkinter/test_misc.py deleted file mode 100644 index 620b6ed..0000000 --- a/Lib/tkinter/test/test_tkinter/test_misc.py +++ /dev/null @@ -1,430 +0,0 @@ -import functools -import unittest -import tkinter -import enum -from test import support -from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest - -support.requires('gui') - -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): - t = tkinter.Toplevel(self.root, name='top') - f = tkinter.Frame(t, name='child') - self.assertEqual(repr(f), '') - - def test_generated_names(self): - t = tkinter.Toplevel(self.root) - f = tkinter.Frame(t) - f2 = tkinter.Frame(t) - b = tkinter.Button(f2) - for name in str(b).split('.'): - self.assertFalse(name.isidentifier(), msg=repr(name)) - - def test_tk_setPalette(self): - root = self.root - root.tk_setPalette('black') - self.assertEqual(root['background'], 'black') - root.tk_setPalette('white') - self.assertEqual(root['background'], 'white') - self.assertRaisesRegex(tkinter.TclError, - '^unknown color name "spam"$', - root.tk_setPalette, 'spam') - - root.tk_setPalette(background='black') - self.assertEqual(root['background'], 'black') - root.tk_setPalette(background='blue', highlightColor='yellow') - self.assertEqual(root['background'], 'blue') - self.assertEqual(root['highlightcolor'], 'yellow') - root.tk_setPalette(background='yellow', highlightColor='blue') - self.assertEqual(root['background'], 'yellow') - self.assertEqual(root['highlightcolor'], 'blue') - self.assertRaisesRegex(tkinter.TclError, - '^unknown color name "spam"$', - root.tk_setPalette, background='spam') - self.assertRaisesRegex(tkinter.TclError, - '^must specify a background color$', - root.tk_setPalette, spam='white') - self.assertRaisesRegex(tkinter.TclError, - '^must specify a background color$', - root.tk_setPalette, highlightColor='blue') - - def test_after(self): - root = self.root - - def callback(start=0, step=1): - nonlocal count - count = start + step - - # Without function, sleeps for ms. - self.assertIsNone(root.after(1)) - - # Set up with callback with no args. - count = 0 - timer1 = root.after(0, callback) - self.assertIn(timer1, root.tk.call('after', 'info')) - (script, _) = root.tk.splitlist(root.tk.call('after', 'info', timer1)) - root.update() # Process all pending events. - self.assertEqual(count, 1) - with self.assertRaises(tkinter.TclError): - root.tk.call(script) - - # Set up with callback with args. - count = 0 - timer1 = root.after(0, callback, 42, 11) - root.update() # Process all pending events. - self.assertEqual(count, 53) - - # Cancel before called. - timer1 = root.after(1000, callback) - self.assertIn(timer1, root.tk.call('after', 'info')) - (script, _) = root.tk.splitlist(root.tk.call('after', 'info', timer1)) - root.after_cancel(timer1) # Cancel this event. - self.assertEqual(count, 53) - with self.assertRaises(tkinter.TclError): - root.tk.call(script) - - # Call with a callable class - count = 0 - timer1 = root.after(0, functools.partial(callback, 42, 11)) - root.update() # Process all pending events. - self.assertEqual(count, 53) - - def test_after_idle(self): - root = self.root - - def callback(start=0, step=1): - nonlocal count - count = start + step - - # Set up with callback with no args. - count = 0 - idle1 = root.after_idle(callback) - self.assertIn(idle1, root.tk.call('after', 'info')) - (script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1)) - root.update_idletasks() # Process all pending events. - self.assertEqual(count, 1) - with self.assertRaises(tkinter.TclError): - root.tk.call(script) - - # Set up with callback with args. - count = 0 - idle1 = root.after_idle(callback, 42, 11) - root.update_idletasks() # Process all pending events. - self.assertEqual(count, 53) - - # Cancel before called. - idle1 = root.after_idle(callback) - self.assertIn(idle1, root.tk.call('after', 'info')) - (script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1)) - root.after_cancel(idle1) # Cancel this event. - self.assertEqual(count, 53) - with self.assertRaises(tkinter.TclError): - root.tk.call(script) - - def test_after_cancel(self): - root = self.root - - def callback(): - nonlocal count - count += 1 - - timer1 = root.after(5000, callback) - idle1 = root.after_idle(callback) - - # No value for id raises a ValueError. - with self.assertRaises(ValueError): - root.after_cancel(None) - - # Cancel timer event. - count = 0 - (script, _) = root.tk.splitlist(root.tk.call('after', 'info', timer1)) - root.tk.call(script) - self.assertEqual(count, 1) - root.after_cancel(timer1) - with self.assertRaises(tkinter.TclError): - root.tk.call(script) - self.assertEqual(count, 1) - with self.assertRaises(tkinter.TclError): - root.tk.call('after', 'info', timer1) - - # Cancel same event - nothing happens. - root.after_cancel(timer1) - - # Cancel idle event. - count = 0 - (script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1)) - root.tk.call(script) - self.assertEqual(count, 1) - root.after_cancel(idle1) - with self.assertRaises(tkinter.TclError): - root.tk.call(script) - self.assertEqual(count, 1) - with self.assertRaises(tkinter.TclError): - root.tk.call('after', 'info', idle1) - - def test_clipboard(self): - root = self.root - root.clipboard_clear() - root.clipboard_append('Ùñî') - self.assertEqual(root.clipboard_get(), 'Ùñî') - root.clipboard_append('çōđě') - self.assertEqual(root.clipboard_get(), 'Ùñîçōđě') - root.clipboard_clear() - with self.assertRaises(tkinter.TclError): - root.clipboard_get() - - def test_clipboard_astral(self): - root = self.root - root.clipboard_clear() - root.clipboard_append('𝔘𝔫𝔦') - self.assertEqual(root.clipboard_get(), '𝔘𝔫𝔦') - root.clipboard_append('𝔠𝔬𝔡𝔢') - self.assertEqual(root.clipboard_get(), '𝔘𝔫𝔦𝔠𝔬𝔡𝔢') - root.clipboard_clear() - with self.assertRaises(tkinter.TclError): - root.clipboard_get() - - def test_winfo_rgb(self): - - def assertApprox(col1, col2): - # A small amount of flexibility is required (bpo-45496) - # 33 is ~0.05% of 65535, which is a reasonable margin - for col1_channel, col2_channel in zip(col1, col2): - self.assertAlmostEqual(col1_channel, col2_channel, delta=33) - - root = self.root - rgb = root.winfo_rgb - - # Color name. - self.assertEqual(rgb('red'), (65535, 0, 0)) - self.assertEqual(rgb('dark slate blue'), (18504, 15677, 35723)) - # #RGB - extends each 4-bit hex value to be 16-bit. - self.assertEqual(rgb('#F0F'), (0xFFFF, 0x0000, 0xFFFF)) - # #RRGGBB - extends each 8-bit hex value to be 16-bit. - assertApprox(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c)) - # #RRRRGGGGBBBB - assertApprox(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939)) - # Invalid string. - with self.assertRaises(tkinter.TclError): - rgb('#123456789a') - # RGB triplet is invalid input. - with self.assertRaises(tkinter.TclError): - rgb((111, 78, 55)) - - def test_event_repr_defaults(self): - e = tkinter.Event() - e.serial = 12345 - e.num = '??' - e.height = '??' - e.keycode = '??' - e.state = 0 - e.time = 123456789 - e.width = '??' - e.x = '??' - e.y = '??' - e.char = '' - e.keysym = '??' - e.keysym_num = '??' - e.type = '100' - e.widget = '??' - e.x_root = '??' - e.y_root = '??' - e.delta = 0 - self.assertEqual(repr(e), '<100 event>') - - def test_event_repr(self): - e = tkinter.Event() - e.serial = 12345 - e.num = 3 - e.focus = True - e.height = 200 - e.keycode = 65 - e.state = 0x30405 - e.time = 123456789 - e.width = 300 - e.x = 10 - e.y = 20 - e.char = 'A' - e.send_event = True - e.keysym = 'Key-A' - e.keysym_num = ord('A') - e.type = tkinter.EventType.Configure - e.widget = '.text' - e.x_root = 1010 - e.y_root = 1020 - e.delta = -1 - self.assertEqual(repr(e), - "") - - def test_eventtype_enum(self): - class CheckedEventType(enum.StrEnum): - KeyPress = '2' - Key = KeyPress - KeyRelease = '3' - ButtonPress = '4' - Button = ButtonPress - ButtonRelease = '5' - Motion = '6' - Enter = '7' - Leave = '8' - FocusIn = '9' - FocusOut = '10' - Keymap = '11' # undocumented - Expose = '12' - GraphicsExpose = '13' # undocumented - NoExpose = '14' # undocumented - Visibility = '15' - Create = '16' - Destroy = '17' - Unmap = '18' - Map = '19' - MapRequest = '20' - Reparent = '21' - Configure = '22' - ConfigureRequest = '23' - Gravity = '24' - ResizeRequest = '25' - Circulate = '26' - CirculateRequest = '27' - Property = '28' - SelectionClear = '29' # undocumented - SelectionRequest = '30' # undocumented - Selection = '31' # undocumented - Colormap = '32' - ClientMessage = '33' # undocumented - Mapping = '34' # undocumented - VirtualEvent = '35' # undocumented - Activate = '36' - Deactivate = '37' - MouseWheel = '38' - enum._test_simple_enum(CheckedEventType, tkinter.EventType) - - 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()) - - def test_info_patchlevel(self): - vi = self.root.info_patchlevel() - f = tkinter.Frame(self.root) - self.assertEqual(f.info_patchlevel(), vi) - # The following is almost a copy of tests for sys.version_info. - self.assertIsInstance(vi[:], tuple) - self.assertEqual(len(vi), 5) - self.assertIsInstance(vi[0], int) - self.assertIsInstance(vi[1], int) - self.assertIsInstance(vi[2], int) - self.assertIn(vi[3], ("alpha", "beta", "candidate", "final")) - self.assertIsInstance(vi[4], int) - self.assertIsInstance(vi.major, int) - self.assertIsInstance(vi.minor, int) - self.assertIsInstance(vi.micro, int) - self.assertIn(vi.releaselevel, ("alpha", "beta", "final")) - self.assertIsInstance(vi.serial, int) - self.assertEqual(vi[0], vi.major) - self.assertEqual(vi[1], vi.minor) - self.assertEqual(vi[2], vi.micro) - self.assertEqual(vi[3], vi.releaselevel) - self.assertEqual(vi[4], vi.serial) - self.assertTrue(vi > (1,0,0)) - if vi.releaselevel == 'final': - self.assertEqual(vi.serial, 0) - else: - self.assertEqual(vi.micro, 0) - self.assertTrue(str(vi).startswith(f'{vi.major}.{vi.minor}')) - - -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) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_tkinter/test_simpledialog.py b/Lib/tkinter/test/test_tkinter/test_simpledialog.py deleted file mode 100644 index 18cd271..0000000 --- a/Lib/tkinter/test/test_tkinter/test_simpledialog.py +++ /dev/null @@ -1,35 +0,0 @@ -import unittest -import tkinter -from test.support import requires, 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): - @staticmethod - def mock_wait_window(w): - nonlocal ismapped - ismapped = w.master.winfo_ismapped() - w.destroy() - - with swap_attr(Dialog, 'wait_window', mock_wait_window): - ismapped = None - askinteger("Go To Line", "Line number") - self.assertEqual(ismapped, False) - - root = tkinter.Tk() - ismapped = None - askinteger("Go To Line", "Line number") - self.assertEqual(ismapped, True) - root.destroy() - - tkinter.NoDefaultRoot() - self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number") - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_tkinter/test_text.py b/Lib/tkinter/test/test_tkinter/test_text.py deleted file mode 100644 index 482f150..0000000 --- a/Lib/tkinter/test/test_tkinter/test_text.py +++ /dev/null @@ -1,45 +0,0 @@ -import unittest -import tkinter -from test.support import requires -from tkinter.test.support import AbstractTkTest - -requires('gui') - -class TextTest(AbstractTkTest, unittest.TestCase): - - def setUp(self): - super().setUp() - self.text = tkinter.Text(self.root) - - def test_debug(self): - text = self.text - olddebug = text.debug() - try: - text.debug(0) - self.assertEqual(text.debug(), 0) - text.debug(1) - self.assertEqual(text.debug(), 1) - finally: - text.debug(olddebug) - self.assertEqual(text.debug(), olddebug) - - def test_search(self): - text = self.text - - # pattern and index are obligatory arguments. - self.assertRaises(tkinter.TclError, text.search, None, '1.0') - self.assertRaises(tkinter.TclError, text.search, 'a', None) - self.assertRaises(tkinter.TclError, text.search, None, None) - - # Invalid text index. - self.assertRaises(tkinter.TclError, text.search, '', 0) - - # Check if we are getting the indices as strings -- you are likely - # to get Tcl_Obj under Tk 8.5 if Tkinter doesn't convert it. - text.insert('1.0', 'hi-test') - self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') - self.assertEqual(text.search('test', '1.0', 'end'), '1.3') - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py deleted file mode 100644 index 427e168..0000000 --- a/Lib/tkinter/test/test_tkinter/test_variables.py +++ /dev/null @@ -1,342 +0,0 @@ -import unittest -from test import support - -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): - - _default = "default" - side_effect = False - - def set(self, value): - self.side_effect = True - super().set(value) - - -class TestBase(unittest.TestCase): - - def setUp(self): - self.root = Tcl() - - def tearDown(self): - del self.root - - -class TestVariable(TestBase): - - def info_exists(self, *args): - return self.root.getboolean(self.root.call("info", "exists", *args)) - - def test_default(self): - v = Variable(self.root) - self.assertEqual("", v.get()) - self.assertRegex(str(v), r"^PY_VAR(\d+)$") - - def test_name_and_value(self): - v = Variable(self.root, "sample string", "varname") - self.assertEqual("sample string", v.get()) - self.assertEqual("varname", str(v)) - - def test___del__(self): - self.assertFalse(self.info_exists("varname")) - v = Variable(self.root, "sample string", "varname") - self.assertTrue(self.info_exists("varname")) - del v - support.gc_collect() # For PyPy or other GCs. - self.assertFalse(self.info_exists("varname")) - - def test_dont_unset_not_existing(self): - self.assertFalse(self.info_exists("varname")) - v1 = Variable(self.root, name="name") - v2 = Variable(self.root, name="name") - del v1 - support.gc_collect() # For PyPy or other GCs. - self.assertFalse(self.info_exists("name")) - # shouldn't raise exception - del v2 - support.gc_collect() # For PyPy or other GCs. - self.assertFalse(self.info_exists("name")) - - def test_equality(self): - # values doesn't matter, only class and name are checked - v1 = Variable(self.root, name="abc") - v2 = Variable(self.root, name="abc") - self.assertIsNot(v1, v2) - self.assertEqual(v1, v2) - - v3 = Variable(self.root, name="cba") - self.assertNotEqual(v1, v3) - - v4 = StringVar(self.root, name="abc") - self.assertEqual(str(v1), str(v4)) - self.assertNotEqual(v1, v4) - - V = type('Variable', (), {}) - self.assertNotEqual(v1, V()) - - self.assertNotEqual(v1, object()) - self.assertEqual(v1, ALWAYS_EQ) - - root2 = tkinter.Tk() - self.addCleanup(root2.destroy) - v5 = Variable(root2, name="abc") - self.assertEqual(str(v1), str(v5)) - self.assertNotEqual(v1, v5) - - def test_invalid_name(self): - with self.assertRaises(TypeError): - Variable(self.root, name=123) - - def test_null_in_name(self): - with self.assertRaises(ValueError): - Variable(self.root, name='var\x00name') - with self.assertRaises(ValueError): - self.root.globalsetvar('var\x00name', "value") - with self.assertRaises(ValueError): - self.root.globalsetvar(b'var\x00name', "value") - with self.assertRaises(ValueError): - self.root.setvar('var\x00name', "value") - with self.assertRaises(ValueError): - self.root.setvar(b'var\x00name', "value") - - def test_initialize(self): - v = Var(self.root) - self.assertFalse(v.side_effect) - v.set("value") - self.assertTrue(v.side_effect) - - def test_trace_old(self): - # Old interface - v = Variable(self.root) - vname = str(v) - trace = [] - def read_tracer(*args): - trace.append(('read',) + args) - def write_tracer(*args): - trace.append(('write',) + args) - cb1 = v.trace_variable('r', read_tracer) - cb2 = v.trace_variable('wu', write_tracer) - self.assertEqual(sorted(v.trace_vinfo()), [('r', cb1), ('wu', cb2)]) - self.assertEqual(trace, []) - - v.set('spam') - self.assertEqual(trace, [('write', vname, '', 'w')]) - - trace = [] - v.get() - self.assertEqual(trace, [('read', vname, '', 'r')]) - - trace = [] - info = sorted(v.trace_vinfo()) - v.trace_vdelete('w', cb1) # Wrong mode - self.assertEqual(sorted(v.trace_vinfo()), info) - with self.assertRaises(TclError): - v.trace_vdelete('r', 'spam') # Wrong command name - self.assertEqual(sorted(v.trace_vinfo()), info) - v.trace_vdelete('r', (cb1, 43)) # Wrong arguments - self.assertEqual(sorted(v.trace_vinfo()), info) - v.get() - self.assertEqual(trace, [('read', vname, '', 'r')]) - - trace = [] - v.trace_vdelete('r', cb1) - self.assertEqual(v.trace_vinfo(), [('wu', cb2)]) - v.get() - self.assertEqual(trace, []) - - trace = [] - del write_tracer - gc.collect() - v.set('eggs') - self.assertEqual(trace, [('write', vname, '', 'w')]) - - trace = [] - del v - gc.collect() - self.assertEqual(trace, [('write', vname, '', 'u')]) - - def test_trace(self): - v = Variable(self.root) - vname = str(v) - trace = [] - def read_tracer(*args): - trace.append(('read',) + args) - def write_tracer(*args): - trace.append(('write',) + args) - tr1 = v.trace_add('read', read_tracer) - tr2 = v.trace_add(['write', 'unset'], write_tracer) - self.assertEqual(sorted(v.trace_info()), [ - (('read',), tr1), - (('write', 'unset'), tr2)]) - self.assertEqual(trace, []) - - v.set('spam') - self.assertEqual(trace, [('write', vname, '', 'write')]) - - trace = [] - v.get() - self.assertEqual(trace, [('read', vname, '', 'read')]) - - trace = [] - info = sorted(v.trace_info()) - v.trace_remove('write', tr1) # Wrong mode - self.assertEqual(sorted(v.trace_info()), info) - with self.assertRaises(TclError): - v.trace_remove('read', 'spam') # Wrong command name - self.assertEqual(sorted(v.trace_info()), info) - v.get() - self.assertEqual(trace, [('read', vname, '', 'read')]) - - trace = [] - v.trace_remove('read', tr1) - self.assertEqual(v.trace_info(), [(('write', 'unset'), tr2)]) - v.get() - self.assertEqual(trace, []) - - trace = [] - del write_tracer - gc.collect() - v.set('eggs') - self.assertEqual(trace, [('write', vname, '', 'write')]) - - trace = [] - del v - gc.collect() - self.assertEqual(trace, [('write', vname, '', 'unset')]) - - -class TestStringVar(TestBase): - - def test_default(self): - v = StringVar(self.root) - self.assertEqual("", v.get()) - - def test_get(self): - v = StringVar(self.root, "abc", "name") - self.assertEqual("abc", v.get()) - self.root.globalsetvar("name", "value") - self.assertEqual("value", v.get()) - - def test_get_null(self): - v = StringVar(self.root, "abc\x00def", "name") - self.assertEqual("abc\x00def", v.get()) - self.root.globalsetvar("name", "val\x00ue") - self.assertEqual("val\x00ue", v.get()) - - -class TestIntVar(TestBase): - - def test_default(self): - v = IntVar(self.root) - self.assertEqual(0, v.get()) - - def test_get(self): - v = IntVar(self.root, 123, "name") - self.assertEqual(123, v.get()) - self.root.globalsetvar("name", "345") - self.assertEqual(345, v.get()) - self.root.globalsetvar("name", "876.5") - self.assertEqual(876, v.get()) - - def test_invalid_value(self): - v = IntVar(self.root, name="name") - self.root.globalsetvar("name", "value") - with self.assertRaises((ValueError, TclError)): - v.get() - - -class TestDoubleVar(TestBase): - - def test_default(self): - v = DoubleVar(self.root) - self.assertEqual(0.0, v.get()) - - def test_get(self): - v = DoubleVar(self.root, 1.23, "name") - self.assertAlmostEqual(1.23, v.get()) - self.root.globalsetvar("name", "3.45") - self.assertAlmostEqual(3.45, v.get()) - - def test_get_from_int(self): - v = DoubleVar(self.root, 1.23, "name") - self.assertAlmostEqual(1.23, v.get()) - self.root.globalsetvar("name", "3.45") - self.assertAlmostEqual(3.45, v.get()) - self.root.globalsetvar("name", "456") - self.assertAlmostEqual(456, v.get()) - - def test_invalid_value(self): - v = DoubleVar(self.root, name="name") - self.root.globalsetvar("name", "value") - with self.assertRaises((ValueError, TclError)): - v.get() - - -class TestBooleanVar(TestBase): - - def test_default(self): - v = BooleanVar(self.root) - self.assertIs(v.get(), False) - - def test_get(self): - v = BooleanVar(self.root, True, "name") - self.assertIs(v.get(), True) - self.root.globalsetvar("name", "0") - self.assertIs(v.get(), False) - self.root.globalsetvar("name", 42 if self.root.wantobjects() else 1) - self.assertIs(v.get(), True) - self.root.globalsetvar("name", 0) - self.assertIs(v.get(), False) - self.root.globalsetvar("name", "on") - self.assertIs(v.get(), True) - - def test_set(self): - true = 1 if self.root.wantobjects() else "1" - false = 0 if self.root.wantobjects() else "0" - v = BooleanVar(self.root, name="name") - v.set(True) - self.assertEqual(self.root.globalgetvar("name"), true) - v.set("0") - self.assertEqual(self.root.globalgetvar("name"), false) - v.set(42) - self.assertEqual(self.root.globalgetvar("name"), true) - v.set(0) - self.assertEqual(self.root.globalgetvar("name"), false) - v.set("on") - self.assertEqual(self.root.globalgetvar("name"), true) - - def test_invalid_value_domain(self): - false = 0 if self.root.wantobjects() else "0" - v = BooleanVar(self.root, name="name") - with self.assertRaises(TclError): - v.set("value") - self.assertEqual(self.root.globalgetvar("name"), false) - self.root.globalsetvar("name", "value") - with self.assertRaises(ValueError): - v.get() - self.root.globalsetvar("name", "1.0") - with self.assertRaises(ValueError): - 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) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_tkinter/test_widgets.py b/Lib/tkinter/test/test_tkinter/test_widgets.py deleted file mode 100644 index fe8ecfe..0000000 --- a/Lib/tkinter/test/test_tkinter/test_widgets.py +++ /dev/null @@ -1,1292 +0,0 @@ -import unittest -import tkinter -from tkinter import TclError -import os -from test.support import requires - -from tkinter.test.support import (requires_tcl, - get_tk_patchlevel, widget_eq, - AbstractDefaultRootTest) -from tkinter.test.widget_tests import ( - add_standard_options, - AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, - setUpModule) - -requires('gui') - - -def float_round(x): - return float(round(x)) - - -class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests): - _conv_pad_pixels = False - - def test_configure_class(self): - widget = self.create() - self.assertEqual(widget['class'], - widget.__class__.__name__.title()) - self.checkInvalidParam(widget, 'class', 'Foo', - errmsg="can't modify -class option after widget is created") - widget2 = self.create(class_='Foo') - self.assertEqual(widget2['class'], 'Foo') - - def test_configure_colormap(self): - widget = self.create() - self.assertEqual(widget['colormap'], '') - self.checkInvalidParam(widget, 'colormap', 'new', - errmsg="can't modify -colormap option after widget is created") - widget2 = self.create(colormap='new') - self.assertEqual(widget2['colormap'], 'new') - - def test_configure_container(self): - widget = self.create() - self.assertEqual(widget['container'], 0 if self.wantobjects else '0') - self.checkInvalidParam(widget, 'container', 1, - errmsg="can't modify -container option after widget is created") - widget2 = self.create(container=True) - self.assertEqual(widget2['container'], 1 if self.wantobjects else '1') - - def test_configure_visual(self): - widget = self.create() - self.assertEqual(widget['visual'], '') - self.checkInvalidParam(widget, 'visual', 'default', - errmsg="can't modify -visual option after widget is created") - widget2 = self.create(visual='default') - self.assertEqual(widget2['visual'], 'default') - - -@add_standard_options(StandardOptionsTests) -class ToplevelTest(AbstractToplevelTest, unittest.TestCase): - OPTIONS = ( - 'background', 'borderwidth', - 'class', 'colormap', 'container', 'cursor', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'menu', 'padx', 'pady', 'relief', 'screen', - 'takefocus', 'use', 'visual', 'width', - ) - - def create(self, **kwargs): - return tkinter.Toplevel(self.root, **kwargs) - - def test_configure_menu(self): - widget = self.create() - menu = tkinter.Menu(self.root) - self.checkParam(widget, 'menu', menu, eq=widget_eq) - self.checkParam(widget, 'menu', '') - - def test_configure_screen(self): - widget = self.create() - self.assertEqual(widget['screen'], '') - try: - display = os.environ['DISPLAY'] - except KeyError: - self.skipTest('No $DISPLAY set.') - self.checkInvalidParam(widget, 'screen', display, - errmsg="can't modify -screen option after widget is created") - widget2 = self.create(screen=display) - self.assertEqual(widget2['screen'], display) - - def test_configure_use(self): - widget = self.create() - self.assertEqual(widget['use'], '') - parent = self.create(container=True) - wid = hex(parent.winfo_id()) - with self.subTest(wid=wid): - widget2 = self.create(use=wid) - self.assertEqual(widget2['use'], wid) - - -@add_standard_options(StandardOptionsTests) -class FrameTest(AbstractToplevelTest, unittest.TestCase): - OPTIONS = ( - 'background', 'borderwidth', - 'class', 'colormap', 'container', 'cursor', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'padx', 'pady', 'relief', 'takefocus', 'visual', 'width', - ) - - def create(self, **kwargs): - return tkinter.Frame(self.root, **kwargs) - - -@add_standard_options(StandardOptionsTests) -class LabelFrameTest(AbstractToplevelTest, unittest.TestCase): - OPTIONS = ( - 'background', 'borderwidth', - 'class', 'colormap', 'container', 'cursor', - 'font', 'foreground', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'labelanchor', 'labelwidget', 'padx', 'pady', 'relief', - 'takefocus', 'text', 'visual', 'width', - ) - - def create(self, **kwargs): - return tkinter.LabelFrame(self.root, **kwargs) - - def test_configure_labelanchor(self): - widget = self.create() - self.checkEnumParam(widget, 'labelanchor', - 'e', 'en', 'es', 'n', 'ne', 'nw', - 's', 'se', 'sw', 'w', 'wn', 'ws') - self.checkInvalidParam(widget, 'labelanchor', 'center') - - def test_configure_labelwidget(self): - widget = self.create() - label = tkinter.Label(self.root, text='Mupp', name='foo') - self.checkParam(widget, 'labelwidget', label, expected='.foo') - label.destroy() - - -class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests): - _conv_pixels = False - - def test_configure_highlightthickness(self): - widget = self.create() - self.checkPixelsParam(widget, 'highlightthickness', - 0, 1.3, 2.6, 6, -2, '10p') - - -@add_standard_options(StandardOptionsTests) -class LabelTest(AbstractLabelTest, unittest.TestCase): - OPTIONS = ( - 'activebackground', 'activeforeground', 'anchor', - 'background', 'bitmap', 'borderwidth', 'compound', 'cursor', - 'disabledforeground', 'font', 'foreground', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'image', 'justify', 'padx', 'pady', 'relief', 'state', - 'takefocus', 'text', 'textvariable', - 'underline', 'width', 'wraplength', - ) - - def create(self, **kwargs): - return tkinter.Label(self.root, **kwargs) - - -@add_standard_options(StandardOptionsTests) -class ButtonTest(AbstractLabelTest, unittest.TestCase): - OPTIONS = ( - 'activebackground', 'activeforeground', 'anchor', - 'background', 'bitmap', 'borderwidth', - 'command', 'compound', 'cursor', 'default', - 'disabledforeground', 'font', 'foreground', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'image', 'justify', 'overrelief', 'padx', 'pady', 'relief', - 'repeatdelay', 'repeatinterval', - 'state', 'takefocus', 'text', 'textvariable', - 'underline', 'width', 'wraplength') - - def create(self, **kwargs): - return tkinter.Button(self.root, **kwargs) - - def test_configure_default(self): - widget = self.create() - self.checkEnumParam(widget, 'default', 'active', 'disabled', 'normal') - - -@add_standard_options(StandardOptionsTests) -class CheckbuttonTest(AbstractLabelTest, unittest.TestCase): - OPTIONS = ( - 'activebackground', 'activeforeground', 'anchor', - 'background', 'bitmap', 'borderwidth', - 'command', 'compound', 'cursor', - 'disabledforeground', 'font', 'foreground', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'image', 'indicatoron', 'justify', - 'offrelief', 'offvalue', 'onvalue', 'overrelief', - 'padx', 'pady', 'relief', 'selectcolor', 'selectimage', 'state', - 'takefocus', 'text', 'textvariable', - 'tristateimage', 'tristatevalue', - 'underline', 'variable', 'width', 'wraplength', - ) - - def create(self, **kwargs): - return tkinter.Checkbutton(self.root, **kwargs) - - - def test_configure_offvalue(self): - widget = self.create() - self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string') - - def test_configure_onvalue(self): - widget = self.create() - self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string') - - -@add_standard_options(StandardOptionsTests) -class RadiobuttonTest(AbstractLabelTest, unittest.TestCase): - OPTIONS = ( - 'activebackground', 'activeforeground', 'anchor', - 'background', 'bitmap', 'borderwidth', - 'command', 'compound', 'cursor', - 'disabledforeground', 'font', 'foreground', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'image', 'indicatoron', 'justify', 'offrelief', 'overrelief', - 'padx', 'pady', 'relief', 'selectcolor', 'selectimage', 'state', - 'takefocus', 'text', 'textvariable', - 'tristateimage', 'tristatevalue', - 'underline', 'value', 'variable', 'width', 'wraplength', - ) - - def create(self, **kwargs): - return tkinter.Radiobutton(self.root, **kwargs) - - def test_configure_value(self): - widget = self.create() - self.checkParams(widget, 'value', 1, 2.3, '', 'any string') - - -@add_standard_options(StandardOptionsTests) -class MenubuttonTest(AbstractLabelTest, unittest.TestCase): - OPTIONS = ( - 'activebackground', 'activeforeground', 'anchor', - 'background', 'bitmap', 'borderwidth', - 'compound', 'cursor', 'direction', - 'disabledforeground', 'font', 'foreground', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'image', 'indicatoron', 'justify', 'menu', - 'padx', 'pady', 'relief', 'state', - 'takefocus', 'text', 'textvariable', - 'underline', 'width', 'wraplength', - ) - _conv_pixels = round - - def create(self, **kwargs): - return tkinter.Menubutton(self.root, **kwargs) - - def test_configure_direction(self): - widget = self.create() - self.checkEnumParam(widget, 'direction', - 'above', 'below', 'flush', 'left', 'right') - - def test_configure_height(self): - widget = self.create() - self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str) - - test_configure_highlightthickness = \ - StandardOptionsTests.test_configure_highlightthickness - - def test_configure_image(self): - widget = self.create() - image = tkinter.PhotoImage(master=self.root, name='image1') - self.checkParam(widget, 'image', image, conv=str) - errmsg = 'image "spam" doesn\'t exist' - with self.assertRaises(tkinter.TclError) as cm: - widget['image'] = 'spam' - if errmsg is not None: - self.assertEqual(str(cm.exception), errmsg) - with self.assertRaises(tkinter.TclError) as cm: - widget.configure({'image': 'spam'}) - if errmsg is not None: - self.assertEqual(str(cm.exception), errmsg) - - def test_configure_menu(self): - widget = self.create() - menu = tkinter.Menu(widget, name='menu') - self.checkParam(widget, 'menu', menu, eq=widget_eq) - menu.destroy() - - def test_configure_padx(self): - widget = self.create() - self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m') - self.checkParam(widget, 'padx', -2, expected=0) - - def test_configure_pady(self): - widget = self.create() - self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m') - self.checkParam(widget, 'pady', -2, expected=0) - - def test_configure_width(self): - widget = self.create() - self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str) - - -class OptionMenuTest(MenubuttonTest, unittest.TestCase): - - def create(self, default='b', values=('a', 'b', 'c'), **kwargs): - return tkinter.OptionMenu(self.root, None, default, *values, **kwargs) - - def test_bad_kwarg(self): - with self.assertRaisesRegex(TclError, r"^unknown option -image$"): - tkinter.OptionMenu(self.root, None, 'b', image='') - - -@add_standard_options(IntegerSizeTests, StandardOptionsTests) -class EntryTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'background', 'borderwidth', 'cursor', - 'disabledbackground', 'disabledforeground', - 'exportselection', 'font', 'foreground', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'insertbackground', 'insertborderwidth', - 'insertofftime', 'insertontime', 'insertwidth', - 'invalidcommand', 'justify', 'readonlybackground', 'relief', - 'selectbackground', 'selectborderwidth', 'selectforeground', - 'show', 'state', 'takefocus', 'textvariable', - 'validate', 'validatecommand', 'width', 'xscrollcommand', - ) - - def create(self, **kwargs): - return tkinter.Entry(self.root, **kwargs) - - def test_configure_disabledbackground(self): - widget = self.create() - self.checkColorParam(widget, 'disabledbackground') - - def test_configure_insertborderwidth(self): - widget = self.create(insertwidth=100) - self.checkPixelsParam(widget, 'insertborderwidth', - 0, 1.3, 2.6, 6, -2, '10p') - # insertborderwidth is bounded above by a half of insertwidth. - self.checkParam(widget, 'insertborderwidth', 60, expected=100//2) - - def test_configure_insertwidth(self): - widget = self.create() - self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p') - self.checkParam(widget, 'insertwidth', 0.1, expected=2) - self.checkParam(widget, 'insertwidth', -2, expected=2) - self.checkParam(widget, 'insertwidth', 0.9, expected=1) - - def test_configure_invalidcommand(self): - widget = self.create() - self.checkCommandParam(widget, 'invalidcommand') - self.checkCommandParam(widget, 'invcmd') - - def test_configure_readonlybackground(self): - widget = self.create() - self.checkColorParam(widget, 'readonlybackground') - - def test_configure_show(self): - widget = self.create() - self.checkParam(widget, 'show', '*') - self.checkParam(widget, 'show', '') - self.checkParam(widget, 'show', ' ') - - def test_configure_state(self): - widget = self.create() - self.checkEnumParam(widget, 'state', - 'disabled', 'normal', 'readonly') - - def test_configure_validate(self): - widget = self.create() - self.checkEnumParam(widget, 'validate', - 'all', 'key', 'focus', 'focusin', 'focusout', 'none') - - def test_configure_validatecommand(self): - widget = self.create() - self.checkCommandParam(widget, 'validatecommand') - self.checkCommandParam(widget, 'vcmd') - - def test_selection_methods(self): - widget = self.create() - widget.insert(0, '12345') - self.assertFalse(widget.selection_present()) - widget.selection_range(0, 'end') - self.assertEqual(widget.selection_get(), '12345') - self.assertTrue(widget.selection_present()) - widget.selection_from(1) - widget.selection_to(2) - self.assertEqual(widget.selection_get(), '2') - widget.selection_range(3, 4) - self.assertEqual(widget.selection_get(), '4') - widget.selection_clear() - self.assertFalse(widget.selection_present()) - widget.selection_range(0, 'end') - widget.selection_adjust(4) - self.assertEqual(widget.selection_get(), '1234') - widget.selection_adjust(1) - self.assertEqual(widget.selection_get(), '234') - widget.selection_adjust(5) - self.assertEqual(widget.selection_get(), '2345') - widget.selection_adjust(0) - self.assertEqual(widget.selection_get(), '12345') - widget.selection_adjust(0) - - -@add_standard_options(StandardOptionsTests) -class SpinboxTest(EntryTest, unittest.TestCase): - OPTIONS = ( - 'activebackground', 'background', 'borderwidth', - 'buttonbackground', 'buttoncursor', 'buttondownrelief', 'buttonuprelief', - 'command', 'cursor', 'disabledbackground', 'disabledforeground', - 'exportselection', 'font', 'foreground', 'format', 'from', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'increment', - 'insertbackground', 'insertborderwidth', - 'insertofftime', 'insertontime', 'insertwidth', - 'invalidcommand', 'justify', 'relief', 'readonlybackground', - 'repeatdelay', 'repeatinterval', - 'selectbackground', 'selectborderwidth', 'selectforeground', - 'state', 'takefocus', 'textvariable', 'to', - 'validate', 'validatecommand', 'values', - 'width', 'wrap', 'xscrollcommand', - ) - - def create(self, **kwargs): - return tkinter.Spinbox(self.root, **kwargs) - - test_configure_show = None - - def test_configure_buttonbackground(self): - widget = self.create() - self.checkColorParam(widget, 'buttonbackground') - - def test_configure_buttoncursor(self): - widget = self.create() - self.checkCursorParam(widget, 'buttoncursor') - - def test_configure_buttondownrelief(self): - widget = self.create() - self.checkReliefParam(widget, 'buttondownrelief') - - def test_configure_buttonuprelief(self): - widget = self.create() - self.checkReliefParam(widget, 'buttonuprelief') - - def test_configure_format(self): - widget = self.create() - self.checkParam(widget, 'format', '%2f') - self.checkParam(widget, 'format', '%2.2f') - self.checkParam(widget, 'format', '%.2f') - self.checkParam(widget, 'format', '%2.f') - self.checkInvalidParam(widget, 'format', '%2e-1f') - self.checkInvalidParam(widget, 'format', '2.2') - self.checkInvalidParam(widget, 'format', '%2.-2f') - self.checkParam(widget, 'format', '%-2.02f') - self.checkParam(widget, 'format', '% 2.02f') - self.checkParam(widget, 'format', '% -2.200f') - self.checkParam(widget, 'format', '%09.200f') - self.checkInvalidParam(widget, 'format', '%d') - - def test_configure_from(self): - widget = self.create() - self.checkParam(widget, 'to', 100.0) - self.checkFloatParam(widget, 'from', -10, 10.2, 11.7) - self.checkInvalidParam(widget, 'from', 200, - errmsg='-to value must be greater than -from value') - - def test_configure_increment(self): - widget = self.create() - self.checkFloatParam(widget, 'increment', -1, 1, 10.2, 12.8, 0) - - def test_configure_to(self): - widget = self.create() - self.checkParam(widget, 'from', -100.0) - self.checkFloatParam(widget, 'to', -10, 10.2, 11.7) - self.checkInvalidParam(widget, 'to', -200, - errmsg='-to value must be greater than -from value') - - def test_configure_values(self): - # XXX - widget = self.create() - self.assertEqual(widget['values'], '') - self.checkParam(widget, 'values', 'mon tue wed thur') - self.checkParam(widget, 'values', ('mon', 'tue', 'wed', 'thur'), - expected='mon tue wed thur') - self.checkParam(widget, 'values', (42, 3.14, '', 'any string'), - expected='42 3.14 {} {any string}') - self.checkParam(widget, 'values', '') - - def test_configure_wrap(self): - widget = self.create() - self.checkBooleanParam(widget, 'wrap') - - def test_bbox(self): - widget = self.create() - self.assertIsBoundingBox(widget.bbox(0)) - self.assertRaises(tkinter.TclError, widget.bbox, 'noindex') - self.assertRaises(tkinter.TclError, widget.bbox, None) - self.assertRaises(TypeError, widget.bbox) - self.assertRaises(TypeError, widget.bbox, 0, 1) - - def test_selection_methods(self): - widget = self.create() - widget.insert(0, '12345') - self.assertFalse(widget.selection_present()) - widget.selection_range(0, 'end') - self.assertEqual(widget.selection_get(), '12345') - self.assertTrue(widget.selection_present()) - widget.selection_from(1) - widget.selection_to(2) - self.assertEqual(widget.selection_get(), '2') - widget.selection_range(3, 4) - self.assertEqual(widget.selection_get(), '4') - widget.selection_clear() - self.assertFalse(widget.selection_present()) - widget.selection_range(0, 'end') - widget.selection_adjust(4) - self.assertEqual(widget.selection_get(), '1234') - widget.selection_adjust(1) - self.assertEqual(widget.selection_get(), '234') - widget.selection_adjust(5) - self.assertEqual(widget.selection_get(), '2345') - widget.selection_adjust(0) - self.assertEqual(widget.selection_get(), '12345') - - def test_selection_element(self): - widget = self.create() - self.assertEqual(widget.selection_element(), "none") - widget.selection_element("buttonup") - self.assertEqual(widget.selection_element(), "buttonup") - widget.selection_element("buttondown") - self.assertEqual(widget.selection_element(), "buttondown") - - -@add_standard_options(StandardOptionsTests) -class TextTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'autoseparators', 'background', 'blockcursor', 'borderwidth', - 'cursor', 'endline', 'exportselection', - 'font', 'foreground', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'inactiveselectbackground', 'insertbackground', 'insertborderwidth', - 'insertofftime', 'insertontime', 'insertunfocussed', 'insertwidth', - 'maxundo', 'padx', 'pady', 'relief', - 'selectbackground', 'selectborderwidth', 'selectforeground', - 'setgrid', 'spacing1', 'spacing2', 'spacing3', 'startline', 'state', - 'tabs', 'tabstyle', 'takefocus', 'undo', 'width', 'wrap', - 'xscrollcommand', 'yscrollcommand', - ) - - def create(self, **kwargs): - return tkinter.Text(self.root, **kwargs) - - def test_configure_autoseparators(self): - widget = self.create() - self.checkBooleanParam(widget, 'autoseparators') - - def test_configure_blockcursor(self): - widget = self.create() - self.checkBooleanParam(widget, 'blockcursor') - - def test_configure_endline(self): - widget = self.create() - text = '\n'.join('Line %d' for i in range(100)) - widget.insert('end', text) - self.checkParam(widget, 'endline', 200, expected='') - self.checkParam(widget, 'endline', -10, expected='') - self.checkInvalidParam(widget, 'endline', 'spam', - errmsg='expected integer but got "spam"') - self.checkParam(widget, 'endline', 50) - self.checkParam(widget, 'startline', 15) - self.checkInvalidParam(widget, 'endline', 10, - errmsg='-startline must be less than or equal to -endline') - - def test_configure_height(self): - widget = self.create() - self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c') - self.checkParam(widget, 'height', -100, expected=1) - self.checkParam(widget, 'height', 0, expected=1) - - def test_configure_maxundo(self): - widget = self.create() - self.checkIntegerParam(widget, 'maxundo', 0, 5, -1) - - def test_configure_inactiveselectbackground(self): - widget = self.create() - self.checkColorParam(widget, 'inactiveselectbackground') - - @requires_tcl(8, 6) - def test_configure_insertunfocussed(self): - widget = self.create() - self.checkEnumParam(widget, 'insertunfocussed', - 'hollow', 'none', 'solid') - - def test_configure_selectborderwidth(self): - widget = self.create() - self.checkPixelsParam(widget, 'selectborderwidth', - 1.3, 2.6, -2, '10p', conv=False) - - def test_configure_spacing1(self): - widget = self.create() - self.checkPixelsParam(widget, 'spacing1', 20, 21.4, 22.6, '0.5c') - self.checkParam(widget, 'spacing1', -5, expected=0) - - def test_configure_spacing2(self): - widget = self.create() - self.checkPixelsParam(widget, 'spacing2', 5, 6.4, 7.6, '0.1c') - self.checkParam(widget, 'spacing2', -1, expected=0) - - def test_configure_spacing3(self): - widget = self.create() - self.checkPixelsParam(widget, 'spacing3', 20, 21.4, 22.6, '0.5c') - self.checkParam(widget, 'spacing3', -10, expected=0) - - def test_configure_startline(self): - widget = self.create() - text = '\n'.join('Line %d' for i in range(100)) - widget.insert('end', text) - self.checkParam(widget, 'startline', 200, expected='') - self.checkParam(widget, 'startline', -10, expected='') - self.checkInvalidParam(widget, 'startline', 'spam', - errmsg='expected integer but got "spam"') - self.checkParam(widget, 'startline', 10) - self.checkParam(widget, 'endline', 50) - self.checkInvalidParam(widget, 'startline', 70, - errmsg='-startline must be less than or equal to -endline') - - def test_configure_state(self): - widget = self.create() - self.checkEnumParam(widget, 'state', 'disabled', 'normal') - - def test_configure_tabs(self): - widget = self.create() - self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i')) - self.checkParam(widget, 'tabs', '10.2 20.7 1i 2i', - expected=('10.2', '20.7', '1i', '2i')) - self.checkParam(widget, 'tabs', '2c left 4c 6c center', - expected=('2c', 'left', '4c', '6c', 'center')) - self.checkInvalidParam(widget, 'tabs', 'spam', - errmsg='bad screen distance "spam"') - - def test_configure_tabstyle(self): - widget = self.create() - self.checkEnumParam(widget, 'tabstyle', 'tabular', 'wordprocessor') - - def test_configure_undo(self): - widget = self.create() - self.checkBooleanParam(widget, 'undo') - - def test_configure_width(self): - widget = self.create() - self.checkIntegerParam(widget, 'width', 402) - self.checkParam(widget, 'width', -402, expected=1) - self.checkParam(widget, 'width', 0, expected=1) - - def test_configure_wrap(self): - widget = self.create() - self.checkEnumParam(widget, 'wrap', 'char', 'none', 'word') - - def test_bbox(self): - widget = self.create() - self.assertIsBoundingBox(widget.bbox('1.1')) - self.assertIsNone(widget.bbox('end')) - self.assertRaises(tkinter.TclError, widget.bbox, 'noindex') - self.assertRaises(tkinter.TclError, widget.bbox, None) - self.assertRaises(TypeError, widget.bbox) - self.assertRaises(TypeError, widget.bbox, '1.1', 'end') - - -@add_standard_options(PixelSizeTests, StandardOptionsTests) -class CanvasTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'background', 'borderwidth', - 'closeenough', 'confine', 'cursor', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'insertbackground', 'insertborderwidth', - 'insertofftime', 'insertontime', 'insertwidth', - 'offset', 'relief', 'scrollregion', - 'selectbackground', 'selectborderwidth', 'selectforeground', - 'state', 'takefocus', - 'xscrollcommand', 'xscrollincrement', - 'yscrollcommand', 'yscrollincrement', 'width', - ) - - _conv_pixels = round - _stringify = True - - def create(self, **kwargs): - return tkinter.Canvas(self.root, **kwargs) - - def test_configure_closeenough(self): - widget = self.create() - self.checkFloatParam(widget, 'closeenough', 24, 2.4, 3.6, -3, - conv=float) - - def test_configure_confine(self): - widget = self.create() - self.checkBooleanParam(widget, 'confine') - - def test_configure_offset(self): - widget = self.create() - self.assertEqual(widget['offset'], '0,0') - self.checkParams(widget, 'offset', - 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center') - self.checkParam(widget, 'offset', '10,20') - self.checkParam(widget, 'offset', '#5,6') - self.checkInvalidParam(widget, 'offset', 'spam') - - def test_configure_scrollregion(self): - widget = self.create() - self.checkParam(widget, 'scrollregion', '0 0 200 150') - self.checkParam(widget, 'scrollregion', (0, 0, 200, 150), - expected='0 0 200 150') - self.checkParam(widget, 'scrollregion', '') - self.checkInvalidParam(widget, 'scrollregion', 'spam', - errmsg='bad scrollRegion "spam"') - self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 'spam')) - self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200)) - self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 150, 0)) - - def test_configure_state(self): - widget = self.create() - self.checkEnumParam(widget, 'state', 'disabled', 'normal', - errmsg='bad state value "{}": must be normal or disabled') - - def test_configure_xscrollincrement(self): - widget = self.create() - self.checkPixelsParam(widget, 'xscrollincrement', - 40, 0, 41.2, 43.6, -40, '0.5i') - - def test_configure_yscrollincrement(self): - widget = self.create() - self.checkPixelsParam(widget, 'yscrollincrement', - 10, 0, 11.2, 13.6, -10, '0.1i') - - @requires_tcl(8, 6) - def test_moveto(self): - widget = self.create() - i1 = widget.create_rectangle(1, 1, 20, 20, tags='group') - i2 = widget.create_rectangle(30, 30, 50, 70, tags='group') - x1, y1, _, _ = widget.bbox(i1) - x2, y2, _, _ = widget.bbox(i2) - widget.moveto('group', 200, 100) - x1_2, y1_2, _, _ = widget.bbox(i1) - x2_2, y2_2, _, _ = widget.bbox(i2) - self.assertEqual(x1_2, 200) - self.assertEqual(y1_2, 100) - self.assertEqual(x2 - x1, x2_2 - x1_2) - self.assertEqual(y2 - y1, y2_2 - y1_2) - widget.tag_lower(i2, i1) - widget.moveto('group', y=50) - x1_3, y1_3, _, _ = widget.bbox(i1) - x2_3, y2_3, _, _ = widget.bbox(i2) - self.assertEqual(y2_3, 50) - self.assertEqual(x2_3, x2_2) - self.assertEqual(x2_2 - x1_2, x2_3 - x1_3) - self.assertEqual(y2_2 - y1_2, y2_3 - y1_3) - - -@add_standard_options(IntegerSizeTests, StandardOptionsTests) -class ListboxTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'activestyle', 'background', 'borderwidth', 'cursor', - 'disabledforeground', 'exportselection', - 'font', 'foreground', 'height', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'justify', 'listvariable', 'relief', - 'selectbackground', 'selectborderwidth', 'selectforeground', - 'selectmode', 'setgrid', 'state', - 'takefocus', 'width', 'xscrollcommand', 'yscrollcommand', - ) - - def create(self, **kwargs): - return tkinter.Listbox(self.root, **kwargs) - - def test_configure_activestyle(self): - widget = self.create() - self.checkEnumParam(widget, 'activestyle', - 'dotbox', 'none', 'underline') - - test_configure_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify) - - def test_configure_listvariable(self): - widget = self.create() - var = tkinter.DoubleVar(self.root) - self.checkVariableParam(widget, 'listvariable', var) - - def test_configure_selectmode(self): - widget = self.create() - self.checkParam(widget, 'selectmode', 'single') - self.checkParam(widget, 'selectmode', 'browse') - self.checkParam(widget, 'selectmode', 'multiple') - self.checkParam(widget, 'selectmode', 'extended') - - def test_configure_state(self): - widget = self.create() - self.checkEnumParam(widget, 'state', 'disabled', 'normal') - - def test_itemconfigure(self): - widget = self.create() - with self.assertRaisesRegex(TclError, 'item number "0" out of range'): - widget.itemconfigure(0) - colors = 'red orange yellow green blue white violet'.split() - widget.insert('end', *colors) - for i, color in enumerate(colors): - widget.itemconfigure(i, background=color) - with self.assertRaises(TypeError): - widget.itemconfigure() - with self.assertRaisesRegex(TclError, 'bad listbox index "red"'): - widget.itemconfigure('red') - self.assertEqual(widget.itemconfigure(0, 'background'), - ('background', 'background', 'Background', '', 'red')) - self.assertEqual(widget.itemconfigure('end', 'background'), - ('background', 'background', 'Background', '', 'violet')) - self.assertEqual(widget.itemconfigure('@0,0', 'background'), - ('background', 'background', 'Background', '', 'red')) - - d = widget.itemconfigure(0) - self.assertIsInstance(d, dict) - for k, v in d.items(): - self.assertIn(len(v), (2, 5)) - if len(v) == 5: - self.assertEqual(v, widget.itemconfigure(0, k)) - self.assertEqual(v[4], widget.itemcget(0, k)) - - def check_itemconfigure(self, name, value): - widget = self.create() - widget.insert('end', 'a', 'b', 'c', 'd') - widget.itemconfigure(0, **{name: value}) - self.assertEqual(widget.itemconfigure(0, name)[4], value) - self.assertEqual(widget.itemcget(0, name), value) - with self.assertRaisesRegex(TclError, 'unknown color name "spam"'): - widget.itemconfigure(0, **{name: 'spam'}) - - def test_itemconfigure_background(self): - self.check_itemconfigure('background', '#ff0000') - - def test_itemconfigure_bg(self): - self.check_itemconfigure('bg', '#ff0000') - - def test_itemconfigure_fg(self): - self.check_itemconfigure('fg', '#110022') - - def test_itemconfigure_foreground(self): - self.check_itemconfigure('foreground', '#110022') - - def test_itemconfigure_selectbackground(self): - self.check_itemconfigure('selectbackground', '#110022') - - def test_itemconfigure_selectforeground(self): - self.check_itemconfigure('selectforeground', '#654321') - - def test_box(self): - lb = self.create() - lb.insert(0, *('el%d' % i for i in range(8))) - lb.pack() - self.assertIsBoundingBox(lb.bbox(0)) - self.assertIsNone(lb.bbox(-1)) - self.assertIsNone(lb.bbox(10)) - self.assertRaises(TclError, lb.bbox, 'noindex') - self.assertRaises(TclError, lb.bbox, None) - self.assertRaises(TypeError, lb.bbox) - self.assertRaises(TypeError, lb.bbox, 0, 1) - - def test_curselection(self): - lb = self.create() - lb.insert(0, *('el%d' % i for i in range(8))) - lb.selection_clear(0, tkinter.END) - lb.selection_set(2, 4) - lb.selection_set(6) - self.assertEqual(lb.curselection(), (2, 3, 4, 6)) - self.assertRaises(TypeError, lb.curselection, 0) - - def test_get(self): - lb = self.create() - lb.insert(0, *('el%d' % i for i in range(8))) - self.assertEqual(lb.get(0), 'el0') - self.assertEqual(lb.get(3), 'el3') - self.assertEqual(lb.get('end'), 'el7') - self.assertEqual(lb.get(8), '') - self.assertEqual(lb.get(-1), '') - self.assertEqual(lb.get(3, 5), ('el3', 'el4', 'el5')) - self.assertEqual(lb.get(5, 'end'), ('el5', 'el6', 'el7')) - self.assertEqual(lb.get(5, 0), ()) - self.assertEqual(lb.get(0, 0), ('el0',)) - self.assertRaises(TclError, lb.get, 'noindex') - self.assertRaises(TclError, lb.get, None) - self.assertRaises(TypeError, lb.get) - self.assertRaises(TclError, lb.get, 'end', 'noindex') - self.assertRaises(TypeError, lb.get, 1, 2, 3) - self.assertRaises(TclError, lb.get, 2.4) - - -@add_standard_options(PixelSizeTests, StandardOptionsTests) -class ScaleTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'activebackground', 'background', 'bigincrement', 'borderwidth', - 'command', 'cursor', 'digits', 'font', 'foreground', 'from', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'label', 'length', 'orient', 'relief', - 'repeatdelay', 'repeatinterval', - 'resolution', 'showvalue', 'sliderlength', 'sliderrelief', 'state', - 'takefocus', 'tickinterval', 'to', 'troughcolor', 'variable', 'width', - ) - default_orient = 'vertical' - - def create(self, **kwargs): - return tkinter.Scale(self.root, **kwargs) - - def test_configure_bigincrement(self): - widget = self.create() - self.checkFloatParam(widget, 'bigincrement', 12.4, 23.6, -5) - - def test_configure_digits(self): - widget = self.create() - self.checkIntegerParam(widget, 'digits', 5, 0) - - def test_configure_from(self): - widget = self.create() - conv = float if get_tk_patchlevel() >= (8, 6, 10) else float_round - self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv) - - def test_configure_label(self): - widget = self.create() - self.checkParam(widget, 'label', 'any string') - self.checkParam(widget, 'label', '') - - def test_configure_length(self): - widget = self.create() - self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i') - - def test_configure_resolution(self): - widget = self.create() - self.checkFloatParam(widget, 'resolution', 4.2, 0, 6.7, -2) - - def test_configure_showvalue(self): - widget = self.create() - self.checkBooleanParam(widget, 'showvalue') - - def test_configure_sliderlength(self): - widget = self.create() - self.checkPixelsParam(widget, 'sliderlength', - 10, 11.2, 15.6, -3, '3m') - - def test_configure_sliderrelief(self): - widget = self.create() - self.checkReliefParam(widget, 'sliderrelief') - - def test_configure_tickinterval(self): - widget = self.create() - self.checkFloatParam(widget, 'tickinterval', 1, 4.3, 7.6, 0, - conv=float_round) - self.checkParam(widget, 'tickinterval', -2, expected=2, - conv=float_round) - - def test_configure_to(self): - widget = self.create() - self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, - conv=float_round) - - -@add_standard_options(PixelSizeTests, StandardOptionsTests) -class ScrollbarTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'activebackground', 'activerelief', - 'background', 'borderwidth', - 'command', 'cursor', 'elementborderwidth', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'jump', 'orient', 'relief', - 'repeatdelay', 'repeatinterval', - 'takefocus', 'troughcolor', 'width', - ) - _conv_pixels = round - _stringify = True - default_orient = 'vertical' - - def create(self, **kwargs): - return tkinter.Scrollbar(self.root, **kwargs) - - def test_configure_activerelief(self): - widget = self.create() - self.checkReliefParam(widget, 'activerelief') - - def test_configure_elementborderwidth(self): - widget = self.create() - self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m') - - def test_configure_orient(self): - widget = self.create() - self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal', - errmsg='bad orientation "{}": must be vertical or horizontal') - - def test_activate(self): - sb = self.create() - for e in ('arrow1', 'slider', 'arrow2'): - sb.activate(e) - self.assertEqual(sb.activate(), e) - sb.activate('') - self.assertIsNone(sb.activate()) - self.assertRaises(TypeError, sb.activate, 'arrow1', 'arrow2') - - def test_set(self): - sb = self.create() - sb.set(0.2, 0.4) - self.assertEqual(sb.get(), (0.2, 0.4)) - self.assertRaises(TclError, sb.set, 'abc', 'def') - self.assertRaises(TclError, sb.set, 0.6, 'def') - self.assertRaises(TclError, sb.set, 0.6, None) - self.assertRaises(TypeError, sb.set, 0.6) - self.assertRaises(TypeError, sb.set, 0.6, 0.7, 0.8) - - -@add_standard_options(StandardOptionsTests) -class PanedWindowTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'background', 'borderwidth', 'cursor', - 'handlepad', 'handlesize', 'height', - 'opaqueresize', 'orient', - 'proxybackground', 'proxyborderwidth', 'proxyrelief', - 'relief', - 'sashcursor', 'sashpad', 'sashrelief', 'sashwidth', - 'showhandle', 'width', - ) - default_orient = 'horizontal' - - def create(self, **kwargs): - return tkinter.PanedWindow(self.root, **kwargs) - - def test_configure_handlepad(self): - widget = self.create() - self.checkPixelsParam(widget, 'handlepad', 5, 6.4, 7.6, -3, '1m') - - def test_configure_handlesize(self): - widget = self.create() - self.checkPixelsParam(widget, 'handlesize', 8, 9.4, 10.6, -3, '2m', - conv=False) - - def test_configure_height(self): - widget = self.create() - self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i', - conv=False) - - def test_configure_opaqueresize(self): - widget = self.create() - self.checkBooleanParam(widget, 'opaqueresize') - - @requires_tcl(8, 6, 5) - def test_configure_proxybackground(self): - widget = self.create() - self.checkColorParam(widget, 'proxybackground') - - @requires_tcl(8, 6, 5) - def test_configure_proxyborderwidth(self): - widget = self.create() - self.checkPixelsParam(widget, 'proxyborderwidth', - 0, 1.3, 2.9, 6, -2, '10p', - conv=False) - - @requires_tcl(8, 6, 5) - def test_configure_proxyrelief(self): - widget = self.create() - self.checkReliefParam(widget, 'proxyrelief') - - def test_configure_sashcursor(self): - widget = self.create() - self.checkCursorParam(widget, 'sashcursor') - - def test_configure_sashpad(self): - widget = self.create() - self.checkPixelsParam(widget, 'sashpad', 8, 1.3, 2.6, -2, '2m') - - def test_configure_sashrelief(self): - widget = self.create() - self.checkReliefParam(widget, 'sashrelief') - - def test_configure_sashwidth(self): - widget = self.create() - self.checkPixelsParam(widget, 'sashwidth', 10, 11.1, 15.6, -3, '1m', - conv=False) - - def test_configure_showhandle(self): - widget = self.create() - self.checkBooleanParam(widget, 'showhandle') - - def test_configure_width(self): - widget = self.create() - self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i', - conv=False) - - def create2(self): - p = self.create() - b = tkinter.Button(p) - c = tkinter.Button(p) - p.add(b) - p.add(c) - return p, b, c - - def test_paneconfigure(self): - p, b, c = self.create2() - self.assertRaises(TypeError, p.paneconfigure) - d = p.paneconfigure(b) - self.assertIsInstance(d, dict) - for k, v in d.items(): - self.assertEqual(len(v), 5) - self.assertEqual(v, p.paneconfigure(b, k)) - self.assertEqual(v[4], p.panecget(b, k)) - - def check_paneconfigure(self, p, b, name, value, expected): - if not self.wantobjects: - expected = str(expected) - p.paneconfigure(b, **{name: value}) - self.assertEqual(p.paneconfigure(b, name)[4], expected) - self.assertEqual(p.panecget(b, name), expected) - - def check_paneconfigure_bad(self, p, b, name, msg): - with self.assertRaisesRegex(TclError, msg): - p.paneconfigure(b, **{name: 'badValue'}) - - def test_paneconfigure_after(self): - p, b, c = self.create2() - self.check_paneconfigure(p, b, 'after', c, str(c)) - self.check_paneconfigure_bad(p, b, 'after', - 'bad window path name "badValue"') - - def test_paneconfigure_before(self): - p, b, c = self.create2() - self.check_paneconfigure(p, b, 'before', c, str(c)) - self.check_paneconfigure_bad(p, b, 'before', - 'bad window path name "badValue"') - - def test_paneconfigure_height(self): - p, b, c = self.create2() - self.check_paneconfigure(p, b, 'height', 10, 10) - self.check_paneconfigure_bad(p, b, 'height', - 'bad screen distance "badValue"') - - def test_paneconfigure_hide(self): - p, b, c = self.create2() - self.check_paneconfigure(p, b, 'hide', False, 0) - self.check_paneconfigure_bad(p, b, 'hide', - 'expected boolean value but got "badValue"') - - def test_paneconfigure_minsize(self): - p, b, c = self.create2() - self.check_paneconfigure(p, b, 'minsize', 10, 10) - self.check_paneconfigure_bad(p, b, 'minsize', - 'bad screen distance "badValue"') - - def test_paneconfigure_padx(self): - p, b, c = self.create2() - self.check_paneconfigure(p, b, 'padx', 1.3, 1) - self.check_paneconfigure_bad(p, b, 'padx', - 'bad screen distance "badValue"') - - def test_paneconfigure_pady(self): - p, b, c = self.create2() - self.check_paneconfigure(p, b, 'pady', 1.3, 1) - self.check_paneconfigure_bad(p, b, 'pady', - 'bad screen distance "badValue"') - - def test_paneconfigure_sticky(self): - p, b, c = self.create2() - self.check_paneconfigure(p, b, 'sticky', 'nsew', 'nesw') - self.check_paneconfigure_bad(p, b, 'sticky', - 'bad stickyness value "badValue": must ' - 'be a string containing zero or more of ' - 'n, e, s, and w') - - def test_paneconfigure_stretch(self): - p, b, c = self.create2() - self.check_paneconfigure(p, b, 'stretch', 'alw', 'always') - self.check_paneconfigure_bad(p, b, 'stretch', - 'bad stretch "badValue": must be ' - 'always, first, last, middle, or never') - - def test_paneconfigure_width(self): - p, b, c = self.create2() - self.check_paneconfigure(p, b, 'width', 10, 10) - self.check_paneconfigure_bad(p, b, 'width', - 'bad screen distance "badValue"') - - -@add_standard_options(StandardOptionsTests) -class MenuTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'activebackground', 'activeborderwidth', 'activeforeground', - 'background', 'borderwidth', 'cursor', - 'disabledforeground', 'font', 'foreground', - 'postcommand', 'relief', 'selectcolor', 'takefocus', - 'tearoff', 'tearoffcommand', 'title', 'type', - ) - _conv_pixels = False - - def create(self, **kwargs): - return tkinter.Menu(self.root, **kwargs) - - def test_configure_postcommand(self): - widget = self.create() - self.checkCommandParam(widget, 'postcommand') - - def test_configure_tearoff(self): - widget = self.create() - self.checkBooleanParam(widget, 'tearoff') - - def test_configure_tearoffcommand(self): - widget = self.create() - self.checkCommandParam(widget, 'tearoffcommand') - - def test_configure_title(self): - widget = self.create() - self.checkParam(widget, 'title', 'any string') - - def test_configure_type(self): - widget = self.create() - self.checkEnumParam( - widget, 'type', - 'normal', 'tearoff', 'menubar', - errmsg='bad type "{}": must be normal, tearoff, or menubar', - ) - - def test_entryconfigure(self): - m1 = self.create() - m1.add_command(label='test') - self.assertRaises(TypeError, m1.entryconfigure) - with self.assertRaisesRegex(TclError, 'bad menu entry index "foo"'): - m1.entryconfigure('foo') - d = m1.entryconfigure(1) - self.assertIsInstance(d, dict) - for k, v in d.items(): - self.assertIsInstance(k, str) - self.assertIsInstance(v, tuple) - self.assertEqual(len(v), 5) - self.assertEqual(v[0], k) - self.assertEqual(m1.entrycget(1, k), v[4]) - m1.destroy() - - def test_entryconfigure_label(self): - m1 = self.create() - m1.add_command(label='test') - self.assertEqual(m1.entrycget(1, 'label'), 'test') - m1.entryconfigure(1, label='changed') - self.assertEqual(m1.entrycget(1, 'label'), 'changed') - - def test_entryconfigure_variable(self): - m1 = self.create() - v1 = tkinter.BooleanVar(self.root) - v2 = tkinter.BooleanVar(self.root) - m1.add_checkbutton(variable=v1, onvalue=True, offvalue=False, - label='Nonsense') - self.assertEqual(str(m1.entrycget(1, 'variable')), str(v1)) - m1.entryconfigure(1, variable=v2) - self.assertEqual(str(m1.entrycget(1, 'variable')), str(v2)) - - -@add_standard_options(PixelSizeTests, StandardOptionsTests) -class MessageTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'anchor', 'aspect', 'background', 'borderwidth', - 'cursor', 'font', 'foreground', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'justify', 'padx', 'pady', 'relief', - 'takefocus', 'text', 'textvariable', 'width', - ) - _conv_pad_pixels = False - - def create(self, **kwargs): - return tkinter.Message(self.root, **kwargs) - - def test_configure_aspect(self): - widget = self.create() - 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, DefaultRootTest, -) - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/tkinter/test/test_ttk/__init__.py b/Lib/tkinter/test/test_ttk/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py deleted file mode 100644 index 1220c48..0000000 --- a/Lib/tkinter/test/test_ttk/test_extensions.py +++ /dev/null @@ -1,328 +0,0 @@ -import sys -import unittest -import tkinter -from tkinter import ttk -from test.support import requires, gc_collect -from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest - -requires('gui') - -class LabeledScaleTest(AbstractTkTest, unittest.TestCase): - - def tearDown(self): - self.root.update_idletasks() - super().tearDown() - - def test_widget_destroy(self): - # automatically created variable - x = ttk.LabeledScale(self.root) - var = x._variable._name - x.destroy() - gc_collect() # For PyPy or other GCs. - self.assertRaises(tkinter.TclError, x.tk.globalgetvar, var) - - # manually created variable - myvar = tkinter.DoubleVar(self.root) - name = myvar._name - x = ttk.LabeledScale(self.root, variable=myvar) - x.destroy() - if self.wantobjects: - self.assertEqual(x.tk.globalgetvar(name), myvar.get()) - else: - self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get()) - del myvar - gc_collect() # For PyPy or other GCs. - self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name) - - # checking that the tracing callback is properly removed - myvar = tkinter.IntVar(self.root) - # LabeledScale will start tracing myvar - x = ttk.LabeledScale(self.root, variable=myvar) - x.destroy() - # Unless the tracing callback was removed, creating a new - # LabeledScale with the same var will cause an error now. This - # happens because the variable will be set to (possibly) a new - # value which causes the tracing callback to be called and then - # it tries calling instance attributes not yet defined. - ttk.LabeledScale(self.root, variable=myvar) - if hasattr(sys, 'last_type'): - self.assertNotEqual(sys.last_type, tkinter.TclError) - - def test_initialization(self): - # master passing - master = tkinter.Frame(self.root) - x = ttk.LabeledScale(master) - self.assertEqual(x.master, master) - x.destroy() - - # variable initialization/passing - passed_expected = (('0', 0), (0, 0), (10, 10), - (-1, -1), (sys.maxsize + 1, sys.maxsize + 1), - (2.5, 2), ('2.5', 2)) - for pair in passed_expected: - x = ttk.LabeledScale(self.root, from_=pair[0]) - self.assertEqual(x.value, pair[1]) - x.destroy() - x = ttk.LabeledScale(self.root, from_=None) - self.assertRaises((ValueError, tkinter.TclError), x._variable.get) - x.destroy() - # variable should have its default value set to the from_ value - myvar = tkinter.DoubleVar(self.root, value=20) - x = ttk.LabeledScale(self.root, variable=myvar) - self.assertEqual(x.value, 0) - x.destroy() - # check that it is really using a DoubleVar - x = ttk.LabeledScale(self.root, variable=myvar, from_=0.5) - self.assertEqual(x.value, 0.5) - self.assertEqual(x._variable._name, myvar._name) - x.destroy() - - # widget positionment - def check_positions(scale, scale_pos, label, label_pos): - self.assertEqual(scale.pack_info()['side'], scale_pos) - self.assertEqual(label.place_info()['anchor'], label_pos) - x = ttk.LabeledScale(self.root, compound='top') - check_positions(x.scale, 'bottom', x.label, 'n') - x.destroy() - x = ttk.LabeledScale(self.root, compound='bottom') - check_positions(x.scale, 'top', x.label, 's') - x.destroy() - # invert default positions - x = ttk.LabeledScale(self.root, compound='unknown') - check_positions(x.scale, 'top', x.label, 's') - x.destroy() - x = ttk.LabeledScale(self.root) # take default positions - check_positions(x.scale, 'bottom', x.label, 'n') - x.destroy() - - # extra, and invalid, kwargs - self.assertRaises(tkinter.TclError, ttk.LabeledScale, master, a='b') - - - def test_horizontal_range(self): - lscale = ttk.LabeledScale(self.root, from_=0, to=10) - lscale.pack() - lscale.update() - - linfo_1 = lscale.label.place_info() - prev_xcoord = lscale.scale.coords()[0] - self.assertEqual(prev_xcoord, int(linfo_1['x'])) - # change range to: from -5 to 5. This should change the x coord of - # the scale widget, since 0 is at the middle of the new - # range. - lscale.scale.configure(from_=-5, to=5) - # The following update is needed since the test doesn't use mainloop, - # at the same time this shouldn't affect test outcome - lscale.update() - curr_xcoord = lscale.scale.coords()[0] - self.assertNotEqual(prev_xcoord, curr_xcoord) - # the label widget should have been repositioned too - linfo_2 = lscale.label.place_info() - self.assertEqual(lscale.label['text'], 0 if self.wantobjects else '0') - self.assertEqual(curr_xcoord, int(linfo_2['x'])) - # change the range back - lscale.scale.configure(from_=0, to=10) - self.assertNotEqual(prev_xcoord, curr_xcoord) - self.assertEqual(prev_xcoord, int(linfo_1['x'])) - - lscale.destroy() - - - def test_variable_change(self): - x = ttk.LabeledScale(self.root) - x.pack() - x.update() - - curr_xcoord = x.scale.coords()[0] - newval = x.value + 1 - x.value = newval - # The following update is needed since the test doesn't use mainloop, - # at the same time this shouldn't affect test outcome - x.update() - self.assertEqual(x.value, newval) - self.assertEqual(x.label['text'], - newval if self.wantobjects else str(newval)) - self.assertEqual(float(x.scale.get()), newval) - self.assertGreater(x.scale.coords()[0], curr_xcoord) - self.assertEqual(x.scale.coords()[0], - int(x.label.place_info()['x'])) - - # value outside range - if self.wantobjects: - conv = lambda x: x - else: - conv = int - x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen - x.update() - self.assertEqual(x.value, newval) - self.assertEqual(conv(x.label['text']), newval) - self.assertEqual(float(x.scale.get()), newval) - self.assertEqual(x.scale.coords()[0], - int(x.label.place_info()['x'])) - - # non-integer value - x.value = newval = newval + 1.5 - x.update() - self.assertEqual(x.value, int(newval)) - self.assertEqual(conv(x.label['text']), int(newval)) - self.assertEqual(float(x.scale.get()), newval) - - x.destroy() - - - def test_resize(self): - x = ttk.LabeledScale(self.root) - x.pack(expand=True, fill='both') - gc_collect() # For PyPy or other GCs. - x.update() - - width, height = x.master.winfo_width(), x.master.winfo_height() - width_new, height_new = width * 2, height * 2 - - x.value = 3 - x.update() - x.master.wm_geometry("%dx%d" % (width_new, height_new)) - self.assertEqual(int(x.label.place_info()['x']), - x.scale.coords()[0]) - - # Reset geometry - x.master.wm_geometry("%dx%d" % (width, height)) - x.destroy() - - -class OptionMenuTest(AbstractTkTest, unittest.TestCase): - - def setUp(self): - super().setUp() - self.textvar = tkinter.StringVar(self.root) - - def tearDown(self): - del self.textvar - super().tearDown() - - - def test_widget_destroy(self): - var = tkinter.StringVar(self.root) - optmenu = ttk.OptionMenu(self.root, var) - name = var._name - optmenu.update_idletasks() - optmenu.destroy() - self.assertEqual(optmenu.tk.globalgetvar(name), var.get()) - del var - gc_collect() # For PyPy or other GCs. - self.assertRaises(tkinter.TclError, optmenu.tk.globalgetvar, name) - - - def test_initialization(self): - self.assertRaises(tkinter.TclError, - ttk.OptionMenu, self.root, self.textvar, invalid='thing') - - optmenu = ttk.OptionMenu(self.root, self.textvar, 'b', 'a', 'b') - self.assertEqual(optmenu._variable.get(), 'b') - - self.assertTrue(optmenu['menu']) - self.assertTrue(optmenu['textvariable']) - - optmenu.destroy() - - - def test_menu(self): - items = ('a', 'b', 'c') - default = 'a' - optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) - found_default = False - for i in range(len(items)): - value = optmenu['menu'].entrycget(i, 'value') - self.assertEqual(value, items[i]) - if value == default: - found_default = True - self.assertTrue(found_default) - optmenu.destroy() - - # default shouldn't be in menu if it is not part of values - default = 'd' - optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) - curr = None - i = 0 - while True: - last, curr = curr, optmenu['menu'].entryconfigure(i, 'value') - if last == curr: - # no more menu entries - break - self.assertNotEqual(curr, default) - i += 1 - self.assertEqual(i, len(items)) - - # check that variable is updated correctly - optmenu.pack() - gc_collect() # For PyPy or other GCs. - optmenu['menu'].invoke(0) - self.assertEqual(optmenu._variable.get(), items[0]) - - # changing to an invalid index shouldn't change the variable - self.assertRaises(tkinter.TclError, optmenu['menu'].invoke, -1) - self.assertEqual(optmenu._variable.get(), items[0]) - - optmenu.destroy() - - # specifying a callback - success = [] - def cb_test(item): - self.assertEqual(item, items[1]) - success.append(True) - optmenu = ttk.OptionMenu(self.root, self.textvar, 'a', command=cb_test, - *items) - optmenu['menu'].invoke(1) - if not success: - self.fail("Menu callback not invoked") - - optmenu.destroy() - - def test_unique_radiobuttons(self): - # check that radiobuttons are unique across instances (bpo25684) - items = ('a', 'b', 'c') - default = 'a' - optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items) - textvar2 = tkinter.StringVar(self.root) - optmenu2 = ttk.OptionMenu(self.root, textvar2, default, *items) - optmenu.pack() - optmenu2.pack() - optmenu['menu'].invoke(1) - optmenu2['menu'].invoke(2) - optmenu_stringvar_name = optmenu['menu'].entrycget(0, 'variable') - optmenu2_stringvar_name = optmenu2['menu'].entrycget(0, 'variable') - self.assertNotEqual(optmenu_stringvar_name, - optmenu2_stringvar_name) - self.assertEqual(self.root.tk.globalgetvar(optmenu_stringvar_name), - items[1]) - self.assertEqual(self.root.tk.globalgetvar(optmenu2_stringvar_name), - items[2]) - - optmenu.destroy() - optmenu2.destroy() - - def test_trace_variable(self): - # prior to bpo45160, tracing a variable would cause the callback to be made twice - success = [] - items = ('a', 'b', 'c') - textvar = tkinter.StringVar(self.root) - def cb_test(*args): - success.append(textvar.get()) - optmenu = ttk.OptionMenu(self.root, textvar, "a", *items) - optmenu.pack() - cb_name = textvar.trace_add("write", cb_test) - optmenu['menu'].invoke(1) - self.assertEqual(success, ['b']) - self.assertEqual(textvar.get(), 'b') - textvar.trace_remove("write", cb_name) - optmenu.destroy() - - -class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): - - def test_labeledscale(self): - self._test_widget(ttk.LabeledScale) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_ttk/test_style.py b/Lib/tkinter/test/test_ttk/test_style.py deleted file mode 100644 index 54ad343..0000000 --- a/Lib/tkinter/test/test_ttk/test_style.py +++ /dev/null @@ -1,181 +0,0 @@ -import unittest -import sys -import tkinter -from tkinter import ttk -from test import support -from test.support import requires -from tkinter.test.support import AbstractTkTest, get_tk_patchlevel - -requires('gui') - -CLASS_NAMES = [ - '.', 'ComboboxPopdownFrame', 'Heading', - 'Horizontal.TProgressbar', 'Horizontal.TScale', 'Item', 'Sash', - 'TButton', 'TCheckbutton', 'TCombobox', 'TEntry', - 'TLabelframe', 'TLabelframe.Label', 'TMenubutton', - 'TNotebook', 'TNotebook.Tab', 'Toolbutton', 'TProgressbar', - 'TRadiobutton', 'Treeview', 'TScale', 'TScrollbar', 'TSpinbox', - 'Vertical.TProgressbar', 'Vertical.TScale' -] - -class StyleTest(AbstractTkTest, unittest.TestCase): - - def setUp(self): - super().setUp() - self.style = ttk.Style(self.root) - - - def test_configure(self): - style = self.style - style.configure('TButton', background='yellow') - self.assertEqual(style.configure('TButton', 'background'), - 'yellow') - self.assertIsInstance(style.configure('TButton'), dict) - - - def test_map(self): - style = self.style - - # Single state - for states in ['active'], [('active',)]: - with self.subTest(states=states): - style.map('TButton', background=[(*states, 'white')]) - expected = [('active', 'white')] - self.assertEqual(style.map('TButton', 'background'), expected) - m = style.map('TButton') - self.assertIsInstance(m, dict) - self.assertEqual(m['background'], expected) - - # Multiple states - for states in ['pressed', '!disabled'], ['pressed !disabled'], [('pressed', '!disabled')]: - with self.subTest(states=states): - style.map('TButton', background=[(*states, 'black')]) - expected = [('pressed', '!disabled', 'black')] - self.assertEqual(style.map('TButton', 'background'), expected) - m = style.map('TButton') - self.assertIsInstance(m, dict) - self.assertEqual(m['background'], expected) - - # Default state - for states in [], [''], [()]: - with self.subTest(states=states): - style.map('TButton', background=[(*states, 'grey')]) - expected = [('grey',)] - self.assertEqual(style.map('TButton', 'background'), expected) - m = style.map('TButton') - self.assertIsInstance(m, dict) - self.assertEqual(m['background'], expected) - - - def test_lookup(self): - style = self.style - style.configure('TButton', background='yellow') - style.map('TButton', background=[('active', 'background', 'blue')]) - - self.assertEqual(style.lookup('TButton', 'background'), 'yellow') - self.assertEqual(style.lookup('TButton', 'background', - ['active', 'background']), 'blue') - self.assertEqual(style.lookup('TButton', 'optionnotdefined', - default='iknewit'), 'iknewit') - - - def test_layout(self): - style = self.style - self.assertRaises(tkinter.TclError, style.layout, 'NotALayout') - tv_style = style.layout('Treeview') - - # "erase" Treeview layout - style.layout('Treeview', '') - self.assertEqual(style.layout('Treeview'), - [('null', {'sticky': 'nswe'})] - ) - - # restore layout - style.layout('Treeview', tv_style) - self.assertEqual(style.layout('Treeview'), tv_style) - - # should return a list - self.assertIsInstance(style.layout('TButton'), list) - - # correct layout, but "option" doesn't exist as option - self.assertRaises(tkinter.TclError, style.layout, 'Treeview', - [('name', {'option': 'inexistent'})]) - - - def test_theme_use(self): - self.assertRaises(tkinter.TclError, self.style.theme_use, - 'nonexistingname') - - curr_theme = self.style.theme_use() - new_theme = None - for theme in self.style.theme_names(): - if theme != curr_theme: - new_theme = theme - self.style.theme_use(theme) - break - else: - # just one theme available, can't go on with tests - return - - self.assertFalse(curr_theme == new_theme) - self.assertFalse(new_theme != self.style.theme_use()) - - self.style.theme_use(curr_theme) - - - def test_configure_custom_copy(self): - style = self.style - - curr_theme = self.style.theme_use() - self.addCleanup(self.style.theme_use, curr_theme) - for theme in self.style.theme_names(): - self.style.theme_use(theme) - for name in CLASS_NAMES: - default = style.configure(name) - if not default: - continue - with self.subTest(theme=theme, name=name): - if support.verbose >= 2: - print('configure', theme, name, default) - if (theme in ('vista', 'xpnative') - and sys.getwindowsversion()[:2] == (6, 1)): - # Fails on the Windows 7 buildbot - continue - newname = f'C.{name}' - self.assertEqual(style.configure(newname), None) - style.configure(newname, **default) - self.assertEqual(style.configure(newname), default) - for key, value in default.items(): - self.assertEqual(style.configure(newname, key), value) - - - def test_map_custom_copy(self): - style = self.style - - curr_theme = self.style.theme_use() - self.addCleanup(self.style.theme_use, curr_theme) - for theme in self.style.theme_names(): - self.style.theme_use(theme) - for name in CLASS_NAMES: - default = style.map(name) - if not default: - continue - with self.subTest(theme=theme, name=name): - if support.verbose >= 2: - print('map', theme, name, default) - if (theme in ('vista', 'xpnative') - and sys.getwindowsversion()[:2] == (6, 1)): - # Fails on the Windows 7 buildbot - continue - newname = f'C.{name}' - self.assertEqual(style.map(newname), {}) - style.map(newname, **default) - if theme == 'alt' and name == '.' and get_tk_patchlevel() < (8, 6, 1): - default['embossed'] = [('disabled', '1')] - self.assertEqual(style.map(newname), default) - for key, value in default.items(): - self.assertEqual(style.map(newname, key), value) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py deleted file mode 100644 index c14c321..0000000 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ /dev/null @@ -1,1858 +0,0 @@ -import unittest -import tkinter -from tkinter import ttk, TclError -from test.support import requires, gc_collect -import sys - -from test.test_ttk_textonly import MockTclObj -from tkinter.test.support import (AbstractTkTest, tcl_version, get_tk_patchlevel, - simulate_mouse_click, AbstractDefaultRootTest) -from tkinter.test.widget_tests import (add_standard_options, - AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, - setUpModule) - -requires('gui') - - -class StandardTtkOptionsTests(StandardOptionsTests): - - def test_configure_class(self): - widget = self.create() - self.assertEqual(widget['class'], '') - errmsg='attempt to change read-only option' - if get_tk_patchlevel() < (8, 6, 0, 'beta', 3): - errmsg='Attempt to change read-only option' - self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg) - widget2 = self.create(class_='Foo') - self.assertEqual(widget2['class'], 'Foo') - - def test_configure_padding(self): - widget = self.create() - self.checkParam(widget, 'padding', 0, expected=('0',)) - self.checkParam(widget, 'padding', 5, expected=('5',)) - self.checkParam(widget, 'padding', (5, 6), expected=('5', '6')) - self.checkParam(widget, 'padding', (5, 6, 7), - expected=('5', '6', '7')) - self.checkParam(widget, 'padding', (5, 6, 7, 8), - expected=('5', '6', '7', '8')) - self.checkParam(widget, 'padding', ('5p', '6p', '7p', '8p')) - self.checkParam(widget, 'padding', (), expected='') - - def test_configure_style(self): - widget = self.create() - self.assertEqual(widget['style'], '') - errmsg = 'Layout Foo not found' - if hasattr(self, 'default_orient'): - errmsg = ('Layout %s.Foo not found' % - getattr(self, 'default_orient').title()) - self.checkInvalidParam(widget, 'style', 'Foo', - errmsg=errmsg) - widget2 = self.create(class_='Foo') - self.assertEqual(widget2['class'], 'Foo') - # XXX - pass - - -class WidgetTest(AbstractTkTest, unittest.TestCase): - """Tests methods available in every ttk widget.""" - - def setUp(self): - super().setUp() - self.widget = ttk.Button(self.root, width=0, text="Text") - self.widget.pack() - - def test_identify(self): - self.widget.update() - self.assertEqual(self.widget.identify( - int(self.widget.winfo_width() / 2), - int(self.widget.winfo_height() / 2) - ), "label") - self.assertEqual(self.widget.identify(-1, -1), "") - - self.assertRaises(tkinter.TclError, self.widget.identify, None, 5) - self.assertRaises(tkinter.TclError, self.widget.identify, 5, None) - self.assertRaises(tkinter.TclError, self.widget.identify, 5, '') - - def test_widget_state(self): - # XXX not sure about the portability of all these tests - self.assertEqual(self.widget.state(), ()) - self.assertEqual(self.widget.instate(['!disabled']), True) - - # changing from !disabled to disabled - self.assertEqual(self.widget.state(['disabled']), ('!disabled', )) - # no state change - self.assertEqual(self.widget.state(['disabled']), ()) - # change back to !disable but also active - self.assertEqual(self.widget.state(['!disabled', 'active']), - ('!active', 'disabled')) - # no state changes, again - self.assertEqual(self.widget.state(['!disabled', 'active']), ()) - self.assertEqual(self.widget.state(['active', '!disabled']), ()) - - def test_cb(arg1, **kw): - return arg1, kw - self.assertEqual(self.widget.instate(['!disabled'], - test_cb, "hi", **{"msg": "there"}), - ('hi', {'msg': 'there'})) - - # attempt to set invalid statespec - currstate = self.widget.state() - self.assertRaises(tkinter.TclError, self.widget.instate, - ['badstate']) - self.assertRaises(tkinter.TclError, self.widget.instate, - ['disabled', 'badstate']) - # verify that widget didn't change its state - self.assertEqual(currstate, self.widget.state()) - - # ensuring that passing None as state doesn't modify current state - self.widget.state(['active', '!disabled']) - self.assertEqual(self.widget.state(), ('active', )) - - -class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests): - _conv_pixels = False - - -@add_standard_options(StandardTtkOptionsTests) -class FrameTest(AbstractToplevelTest, unittest.TestCase): - OPTIONS = ( - 'borderwidth', 'class', 'cursor', 'height', - 'padding', 'relief', 'style', 'takefocus', - 'width', - ) - - def create(self, **kwargs): - return ttk.Frame(self.root, **kwargs) - - -@add_standard_options(StandardTtkOptionsTests) -class LabelFrameTest(AbstractToplevelTest, unittest.TestCase): - OPTIONS = ( - 'borderwidth', 'class', 'cursor', 'height', - 'labelanchor', 'labelwidget', - 'padding', 'relief', 'style', 'takefocus', - 'text', 'underline', 'width', - ) - - def create(self, **kwargs): - return ttk.LabelFrame(self.root, **kwargs) - - def test_configure_labelanchor(self): - widget = self.create() - self.checkEnumParam(widget, 'labelanchor', - 'e', 'en', 'es', 'n', 'ne', 'nw', 's', 'se', 'sw', 'w', 'wn', 'ws', - errmsg='Bad label anchor specification {}') - self.checkInvalidParam(widget, 'labelanchor', 'center') - - def test_configure_labelwidget(self): - widget = self.create() - label = ttk.Label(self.root, text='Mupp', name='foo') - self.checkParam(widget, 'labelwidget', label, expected='.foo') - label.destroy() - - -class AbstractLabelTest(AbstractWidgetTest): - - def checkImageParam(self, widget, name): - image = tkinter.PhotoImage(master=self.root, name='image1') - image2 = tkinter.PhotoImage(master=self.root, name='image2') - self.checkParam(widget, name, image, expected=('image1',)) - self.checkParam(widget, name, 'image1', expected=('image1',)) - self.checkParam(widget, name, (image,), expected=('image1',)) - self.checkParam(widget, name, (image, 'active', image2), - expected=('image1', 'active', 'image2')) - self.checkParam(widget, name, 'image1 active image2', - expected=('image1', 'active', 'image2')) - self.checkInvalidParam(widget, name, 'spam', - errmsg='image "spam" doesn\'t exist') - - def test_configure_compound(self): - options = 'none text image center top bottom left right'.split() - errmsg = ( - 'bad compound "{}": must be' - f' {", ".join(options[:-1])}, or {options[-1]}' - ) - widget = self.create() - self.checkEnumParam(widget, 'compound', *options, errmsg=errmsg) - - def test_configure_state(self): - widget = self.create() - self.checkParams(widget, 'state', 'active', 'disabled', 'normal') - - def test_configure_width(self): - widget = self.create() - self.checkParams(widget, 'width', 402, -402, 0) - - -@add_standard_options(StandardTtkOptionsTests) -class LabelTest(AbstractLabelTest, unittest.TestCase): - OPTIONS = ( - 'anchor', 'background', 'borderwidth', - 'class', 'compound', 'cursor', 'font', 'foreground', - 'image', 'justify', 'padding', 'relief', 'state', 'style', - 'takefocus', 'text', 'textvariable', - 'underline', 'width', 'wraplength', - ) - _conv_pixels = False - - def create(self, **kwargs): - return ttk.Label(self.root, **kwargs) - - def test_configure_font(self): - widget = self.create() - self.checkParam(widget, 'font', - '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') - - -@add_standard_options(StandardTtkOptionsTests) -class ButtonTest(AbstractLabelTest, unittest.TestCase): - OPTIONS = ( - 'class', 'command', 'compound', 'cursor', 'default', - 'image', 'padding', 'state', 'style', - 'takefocus', 'text', 'textvariable', - 'underline', 'width', - ) - - def create(self, **kwargs): - return ttk.Button(self.root, **kwargs) - - def test_configure_default(self): - widget = self.create() - self.checkEnumParam(widget, 'default', 'normal', 'active', 'disabled') - - def test_invoke(self): - success = [] - btn = ttk.Button(self.root, command=lambda: success.append(1)) - btn.invoke() - self.assertTrue(success) - - -@add_standard_options(StandardTtkOptionsTests) -class CheckbuttonTest(AbstractLabelTest, unittest.TestCase): - OPTIONS = ( - 'class', 'command', 'compound', 'cursor', - 'image', - 'offvalue', 'onvalue', - 'padding', 'state', 'style', - 'takefocus', 'text', 'textvariable', - 'underline', 'variable', 'width', - ) - - def create(self, **kwargs): - return ttk.Checkbutton(self.root, **kwargs) - - def test_configure_offvalue(self): - widget = self.create() - self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string') - - def test_configure_onvalue(self): - widget = self.create() - self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string') - - def test_invoke(self): - success = [] - def cb_test(): - success.append(1) - return "cb test called" - - cbtn = ttk.Checkbutton(self.root, command=cb_test) - # the variable automatically created by ttk.Checkbutton is actually - # undefined till we invoke the Checkbutton - self.assertEqual(cbtn.state(), ('alternate', )) - self.assertRaises(tkinter.TclError, cbtn.tk.globalgetvar, - cbtn['variable']) - - res = cbtn.invoke() - self.assertEqual(res, "cb test called") - self.assertEqual(cbtn['onvalue'], - cbtn.tk.globalgetvar(cbtn['variable'])) - self.assertTrue(success) - - cbtn['command'] = '' - res = cbtn.invoke() - self.assertFalse(str(res)) - self.assertLessEqual(len(success), 1) - self.assertEqual(cbtn['offvalue'], - cbtn.tk.globalgetvar(cbtn['variable'])) - - -@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) -class EntryTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'background', 'class', 'cursor', - 'exportselection', 'font', 'foreground', - 'invalidcommand', 'justify', - 'show', 'state', 'style', 'takefocus', 'textvariable', - 'validate', 'validatecommand', 'width', 'xscrollcommand', - ) - IDENTIFY_AS = 'Entry.field' if sys.platform == 'darwin' else 'textarea' - - def setUp(self): - super().setUp() - self.entry = self.create() - - def create(self, **kwargs): - return ttk.Entry(self.root, **kwargs) - - def test_configure_invalidcommand(self): - widget = self.create() - self.checkCommandParam(widget, 'invalidcommand') - - def test_configure_show(self): - widget = self.create() - self.checkParam(widget, 'show', '*') - self.checkParam(widget, 'show', '') - self.checkParam(widget, 'show', ' ') - - def test_configure_state(self): - widget = self.create() - self.checkParams(widget, 'state', - 'disabled', 'normal', 'readonly') - - def test_configure_validate(self): - widget = self.create() - self.checkEnumParam(widget, 'validate', - 'all', 'key', 'focus', 'focusin', 'focusout', 'none') - - def test_configure_validatecommand(self): - widget = self.create() - self.checkCommandParam(widget, 'validatecommand') - - def test_bbox(self): - self.assertIsBoundingBox(self.entry.bbox(0)) - self.assertRaises(tkinter.TclError, self.entry.bbox, 'noindex') - self.assertRaises(tkinter.TclError, self.entry.bbox, None) - - def test_identify(self): - self.entry.pack() - self.entry.update() - - # bpo-27313: macOS Cocoa widget differs from X, allow either - self.assertEqual(self.entry.identify(5, 5), self.IDENTIFY_AS) - self.assertEqual(self.entry.identify(-1, -1), "") - - self.assertRaises(tkinter.TclError, self.entry.identify, None, 5) - self.assertRaises(tkinter.TclError, self.entry.identify, 5, None) - self.assertRaises(tkinter.TclError, self.entry.identify, 5, '') - - def test_validation_options(self): - success = [] - test_invalid = lambda: success.append(True) - - self.entry['validate'] = 'none' - self.entry['validatecommand'] = lambda: False - - self.entry['invalidcommand'] = test_invalid - self.entry.validate() - self.assertTrue(success) - - self.entry['invalidcommand'] = '' - self.entry.validate() - self.assertEqual(len(success), 1) - - self.entry['invalidcommand'] = test_invalid - self.entry['validatecommand'] = lambda: True - self.entry.validate() - self.assertEqual(len(success), 1) - - self.entry['validatecommand'] = '' - self.entry.validate() - self.assertEqual(len(success), 1) - - self.entry['validatecommand'] = True - self.assertRaises(tkinter.TclError, self.entry.validate) - - def test_validation(self): - validation = [] - def validate(to_insert): - if not 'a' <= to_insert.lower() <= 'z': - validation.append(False) - return False - validation.append(True) - return True - - self.entry['validate'] = 'key' - self.entry['validatecommand'] = self.entry.register(validate), '%S' - - self.entry.insert('end', 1) - self.entry.insert('end', 'a') - self.assertEqual(validation, [False, True]) - self.assertEqual(self.entry.get(), 'a') - - def test_revalidation(self): - def validate(content): - for letter in content: - if not 'a' <= letter.lower() <= 'z': - return False - return True - - self.entry['validatecommand'] = self.entry.register(validate), '%P' - - self.entry.insert('end', 'avocado') - self.assertEqual(self.entry.validate(), True) - self.assertEqual(self.entry.state(), ()) - - self.entry.delete(0, 'end') - self.assertEqual(self.entry.get(), '') - - self.entry.insert('end', 'a1b') - self.assertEqual(self.entry.validate(), False) - self.assertEqual(self.entry.state(), ('invalid', )) - - self.entry.delete(1) - self.assertEqual(self.entry.validate(), True) - self.assertEqual(self.entry.state(), ()) - - -@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) -class ComboboxTest(EntryTest, unittest.TestCase): - OPTIONS = ( - 'background', 'class', 'cursor', 'exportselection', - 'font', 'foreground', 'height', 'invalidcommand', - 'justify', 'postcommand', 'show', 'state', 'style', - 'takefocus', 'textvariable', - 'validate', 'validatecommand', 'values', - 'width', 'xscrollcommand', - ) - IDENTIFY_AS = 'Combobox.button' if sys.platform == 'darwin' else 'textarea' - - def setUp(self): - super().setUp() - self.combo = self.create() - - def create(self, **kwargs): - return ttk.Combobox(self.root, **kwargs) - - def test_configure_height(self): - widget = self.create() - self.checkParams(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i') - - def _show_drop_down_listbox(self): - width = self.combo.winfo_width() - x, y = width - 5, 5 - if sys.platform != 'darwin': # there's no down arrow on macOS - self.assertRegex(self.combo.identify(x, y), r'.*downarrow\Z') - self.combo.event_generate('', x=x, y=y) - self.combo.event_generate('', x=x, y=y) - self.combo.update_idletasks() - - def test_virtual_event(self): - success = [] - - self.combo['values'] = [1] - self.combo.bind('<>', - lambda evt: success.append(True)) - self.combo.pack() - self.combo.update() - - height = self.combo.winfo_height() - self._show_drop_down_listbox() - self.combo.update() - self.combo.event_generate('') - self.combo.update() - - self.assertTrue(success) - - def test_configure_postcommand(self): - success = [] - - self.combo['postcommand'] = lambda: success.append(True) - self.combo.pack() - self.combo.update() - - self._show_drop_down_listbox() - self.assertTrue(success) - - # testing postcommand removal - self.combo['postcommand'] = '' - self._show_drop_down_listbox() - self.assertEqual(len(success), 1) - - def test_configure_values(self): - def check_get_current(getval, currval): - self.assertEqual(self.combo.get(), getval) - self.assertEqual(self.combo.current(), currval) - - self.assertEqual(self.combo['values'], '') - check_get_current('', -1) - - self.checkParam(self.combo, 'values', 'mon tue wed thur', - expected=('mon', 'tue', 'wed', 'thur')) - self.checkParam(self.combo, 'values', ('mon', 'tue', 'wed', 'thur')) - self.checkParam(self.combo, 'values', (42, 3.14, '', 'any string')) - self.checkParam(self.combo, 'values', '') - - self.combo['values'] = ['a', 1, 'c'] - - self.combo.set('c') - check_get_current('c', 2) - - self.combo.current(0) - check_get_current('a', 0) - - self.combo.set('d') - check_get_current('d', -1) - - # testing values with empty string - self.combo.set('') - self.combo['values'] = (1, 2, '', 3) - check_get_current('', 2) - - # testing values with empty string set through configure - self.combo.configure(values=[1, '', 2]) - self.assertEqual(self.combo['values'], - ('1', '', '2') if self.wantobjects else - '1 {} 2') - - # testing values with spaces - self.combo['values'] = ['a b', 'a\tb', 'a\nb'] - self.assertEqual(self.combo['values'], - ('a b', 'a\tb', 'a\nb') if self.wantobjects else - '{a b} {a\tb} {a\nb}') - - # testing values with special characters - self.combo['values'] = [r'a\tb', '"a"', '} {'] - self.assertEqual(self.combo['values'], - (r'a\tb', '"a"', '} {') if self.wantobjects else - r'a\\tb {"a"} \}\ \{') - - # out of range - self.assertRaises(tkinter.TclError, self.combo.current, - len(self.combo['values'])) - # it expects an integer (or something that can be converted to int) - self.assertRaises(tkinter.TclError, self.combo.current, '') - - # testing creating combobox with empty string in values - combo2 = ttk.Combobox(self.root, values=[1, 2, '']) - self.assertEqual(combo2['values'], - ('1', '2', '') if self.wantobjects else '1 2 {}') - combo2.destroy() - - -@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) -class PanedWindowTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'class', 'cursor', 'height', - 'orient', 'style', 'takefocus', 'width', - ) - - def setUp(self): - super().setUp() - self.paned = self.create() - - def create(self, **kwargs): - return ttk.PanedWindow(self.root, **kwargs) - - def test_configure_orient(self): - widget = self.create() - self.assertEqual(str(widget['orient']), 'vertical') - errmsg='attempt to change read-only option' - if get_tk_patchlevel() < (8, 6, 0, 'beta', 3): - errmsg='Attempt to change read-only option' - self.checkInvalidParam(widget, 'orient', 'horizontal', - errmsg=errmsg) - widget2 = self.create(orient='horizontal') - self.assertEqual(str(widget2['orient']), 'horizontal') - - def test_add(self): - # attempt to add a child that is not a direct child of the paned window - label = ttk.Label(self.paned) - child = ttk.Label(label) - self.assertRaises(tkinter.TclError, self.paned.add, child) - label.destroy() - child.destroy() - # another attempt - label = ttk.Label(self.root) - child = ttk.Label(label) - self.assertRaises(tkinter.TclError, self.paned.add, child) - child.destroy() - label.destroy() - - good_child = ttk.Label(self.root) - self.paned.add(good_child) - # re-adding a child is not accepted - self.assertRaises(tkinter.TclError, self.paned.add, good_child) - - other_child = ttk.Label(self.paned) - self.paned.add(other_child) - self.assertEqual(self.paned.pane(0), self.paned.pane(1)) - self.assertRaises(tkinter.TclError, self.paned.pane, 2) - good_child.destroy() - other_child.destroy() - self.assertRaises(tkinter.TclError, self.paned.pane, 0) - - def test_forget(self): - self.assertRaises(tkinter.TclError, self.paned.forget, None) - self.assertRaises(tkinter.TclError, self.paned.forget, 0) - - self.paned.add(ttk.Label(self.root)) - self.paned.forget(0) - self.assertRaises(tkinter.TclError, self.paned.forget, 0) - - def test_insert(self): - self.assertRaises(tkinter.TclError, self.paned.insert, None, 0) - self.assertRaises(tkinter.TclError, self.paned.insert, 0, None) - self.assertRaises(tkinter.TclError, self.paned.insert, 0, 0) - - child = ttk.Label(self.root) - child2 = ttk.Label(self.root) - child3 = ttk.Label(self.root) - - self.assertRaises(tkinter.TclError, self.paned.insert, 0, child) - - self.paned.insert('end', child2) - self.paned.insert(0, child) - self.assertEqual(self.paned.panes(), (str(child), str(child2))) - - self.paned.insert(0, child2) - self.assertEqual(self.paned.panes(), (str(child2), str(child))) - - self.paned.insert('end', child3) - self.assertEqual(self.paned.panes(), - (str(child2), str(child), str(child3))) - - # reinserting a child should move it to its current position - panes = self.paned.panes() - self.paned.insert('end', child3) - self.assertEqual(panes, self.paned.panes()) - - # moving child3 to child2 position should result in child2 ending up - # in previous child position and child ending up in previous child3 - # position - self.paned.insert(child2, child3) - self.assertEqual(self.paned.panes(), - (str(child3), str(child2), str(child))) - - def test_pane(self): - self.assertRaises(tkinter.TclError, self.paned.pane, 0) - - child = ttk.Label(self.root) - self.paned.add(child) - self.assertIsInstance(self.paned.pane(0), dict) - self.assertEqual(self.paned.pane(0, weight=None), - 0 if self.wantobjects else '0') - # newer form for querying a single option - self.assertEqual(self.paned.pane(0, 'weight'), - 0 if self.wantobjects else '0') - self.assertEqual(self.paned.pane(0), self.paned.pane(str(child))) - - self.assertRaises(tkinter.TclError, self.paned.pane, 0, - badoption='somevalue') - - def test_sashpos(self): - self.assertRaises(tkinter.TclError, self.paned.sashpos, None) - self.assertRaises(tkinter.TclError, self.paned.sashpos, '') - self.assertRaises(tkinter.TclError, self.paned.sashpos, 0) - - child = ttk.Label(self.paned, text='a') - self.paned.add(child, weight=1) - self.assertRaises(tkinter.TclError, self.paned.sashpos, 0) - child2 = ttk.Label(self.paned, text='b') - self.paned.add(child2) - self.assertRaises(tkinter.TclError, self.paned.sashpos, 1) - - self.paned.pack(expand=True, fill='both') - - curr_pos = self.paned.sashpos(0) - self.paned.sashpos(0, 1000) - self.assertNotEqual(curr_pos, self.paned.sashpos(0)) - self.assertIsInstance(self.paned.sashpos(0), int) - - -@add_standard_options(StandardTtkOptionsTests) -class RadiobuttonTest(AbstractLabelTest, unittest.TestCase): - OPTIONS = ( - 'class', 'command', 'compound', 'cursor', - 'image', - 'padding', 'state', 'style', - 'takefocus', 'text', 'textvariable', - 'underline', 'value', 'variable', 'width', - ) - - def create(self, **kwargs): - return ttk.Radiobutton(self.root, **kwargs) - - def test_configure_value(self): - widget = self.create() - self.checkParams(widget, 'value', 1, 2.3, '', 'any string') - - def test_configure_invoke(self): - success = [] - def cb_test(): - success.append(1) - return "cb test called" - - myvar = tkinter.IntVar(self.root) - cbtn = ttk.Radiobutton(self.root, command=cb_test, - variable=myvar, value=0) - cbtn2 = ttk.Radiobutton(self.root, command=cb_test, - variable=myvar, value=1) - - if self.wantobjects: - conv = lambda x: x - else: - conv = int - - res = cbtn.invoke() - self.assertEqual(res, "cb test called") - self.assertEqual(conv(cbtn['value']), myvar.get()) - self.assertEqual(myvar.get(), - conv(cbtn.tk.globalgetvar(cbtn['variable']))) - self.assertTrue(success) - - cbtn2['command'] = '' - res = cbtn2.invoke() - self.assertEqual(str(res), '') - self.assertLessEqual(len(success), 1) - self.assertEqual(conv(cbtn2['value']), myvar.get()) - self.assertEqual(myvar.get(), - conv(cbtn.tk.globalgetvar(cbtn['variable']))) - - self.assertEqual(str(cbtn['variable']), str(cbtn2['variable'])) - - -class MenubuttonTest(AbstractLabelTest, unittest.TestCase): - OPTIONS = ( - 'class', 'compound', 'cursor', 'direction', - 'image', 'menu', 'padding', 'state', 'style', - 'takefocus', 'text', 'textvariable', - 'underline', 'width', - ) - - def create(self, **kwargs): - return ttk.Menubutton(self.root, **kwargs) - - def test_direction(self): - widget = self.create() - self.checkEnumParam(widget, 'direction', - 'above', 'below', 'left', 'right', 'flush') - - def test_configure_menu(self): - widget = self.create() - menu = tkinter.Menu(widget, name='menu') - self.checkParam(widget, 'menu', menu, conv=str) - menu.destroy() - - -@add_standard_options(StandardTtkOptionsTests) -class ScaleTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'class', 'command', 'cursor', 'from', 'length', - 'orient', 'style', 'takefocus', 'to', 'value', 'variable', - ) - _conv_pixels = False - default_orient = 'horizontal' - - def setUp(self): - super().setUp() - self.scale = self.create() - self.scale.pack() - self.scale.update() - - def create(self, **kwargs): - return ttk.Scale(self.root, **kwargs) - - def test_configure_from(self): - widget = self.create() - self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=False) - - def test_configure_length(self): - widget = self.create() - self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i') - - def test_configure_to(self): - widget = self.create() - self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=False) - - def test_configure_value(self): - widget = self.create() - self.checkFloatParam(widget, 'value', 300, 14.9, 15.1, -10, conv=False) - - def test_custom_event(self): - failure = [1, 1, 1] # will need to be empty - - funcid = self.scale.bind('<>', lambda evt: failure.pop()) - - self.scale['from'] = 10 - self.scale['from_'] = 10 - self.scale['to'] = 3 - - self.assertFalse(failure) - - failure = [1, 1, 1] - self.scale.configure(from_=2, to=5) - self.scale.configure(from_=0, to=-2) - self.scale.configure(to=10) - - self.assertFalse(failure) - - def test_get(self): - if self.wantobjects: - conv = lambda x: x - else: - conv = float - - scale_width = self.scale.winfo_width() - self.assertEqual(self.scale.get(scale_width, 0), self.scale['to']) - - self.assertEqual(conv(self.scale.get(0, 0)), conv(self.scale['from'])) - self.assertEqual(self.scale.get(), self.scale['value']) - self.scale['value'] = 30 - self.assertEqual(self.scale.get(), self.scale['value']) - - self.assertRaises(tkinter.TclError, self.scale.get, '', 0) - self.assertRaises(tkinter.TclError, self.scale.get, 0, '') - - def test_set(self): - if self.wantobjects: - conv = lambda x: x - else: - conv = float - - # set restricts the max/min values according to the current range - max = conv(self.scale['to']) - new_max = max + 10 - self.scale.set(new_max) - self.assertEqual(conv(self.scale.get()), max) - min = conv(self.scale['from']) - self.scale.set(min - 1) - self.assertEqual(conv(self.scale.get()), min) - - # changing directly the variable doesn't impose this limitation tho - var = tkinter.DoubleVar(self.root) - self.scale['variable'] = var - var.set(max + 5) - self.assertEqual(conv(self.scale.get()), var.get()) - self.assertEqual(conv(self.scale.get()), max + 5) - del var - gc_collect() # For PyPy or other GCs. - - # the same happens with the value option - self.scale['value'] = max + 10 - self.assertEqual(conv(self.scale.get()), max + 10) - self.assertEqual(conv(self.scale.get()), conv(self.scale['value'])) - - # nevertheless, note that the max/min values we can get specifying - # x, y coords are the ones according to the current range - self.assertEqual(conv(self.scale.get(0, 0)), min) - self.assertEqual(conv(self.scale.get(self.scale.winfo_width(), 0)), max) - - self.assertRaises(tkinter.TclError, self.scale.set, None) - - -@add_standard_options(StandardTtkOptionsTests) -class ProgressbarTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'class', 'cursor', 'orient', 'length', - 'mode', 'maximum', 'phase', - 'style', 'takefocus', 'value', 'variable', - ) - _conv_pixels = False - default_orient = 'horizontal' - - def create(self, **kwargs): - return ttk.Progressbar(self.root, **kwargs) - - def test_configure_length(self): - widget = self.create() - self.checkPixelsParam(widget, 'length', 100.1, 56.7, '2i') - - def test_configure_maximum(self): - widget = self.create() - self.checkFloatParam(widget, 'maximum', 150.2, 77.7, 0, -10, conv=False) - - def test_configure_mode(self): - widget = self.create() - self.checkEnumParam(widget, 'mode', 'determinate', 'indeterminate') - - def test_configure_phase(self): - # XXX - pass - - def test_configure_value(self): - widget = self.create() - self.checkFloatParam(widget, 'value', 150.2, 77.7, 0, -10, - conv=False) - - -@unittest.skipIf(sys.platform == 'darwin', - 'ttk.Scrollbar is special on MacOSX') -@add_standard_options(StandardTtkOptionsTests) -class ScrollbarTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'class', 'command', 'cursor', 'orient', 'style', 'takefocus', - ) - default_orient = 'vertical' - - def create(self, **kwargs): - return ttk.Scrollbar(self.root, **kwargs) - - -@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) -class NotebookTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'class', 'cursor', 'height', 'padding', 'style', 'takefocus', 'width', - ) - - def setUp(self): - super().setUp() - self.nb = self.create(padding=0) - self.child1 = ttk.Label(self.root) - self.child2 = ttk.Label(self.root) - self.nb.add(self.child1, text='a') - self.nb.add(self.child2, text='b') - - def create(self, **kwargs): - return ttk.Notebook(self.root, **kwargs) - - def test_tab_identifiers(self): - self.nb.forget(0) - self.nb.hide(self.child2) - self.assertRaises(tkinter.TclError, self.nb.tab, self.child1) - self.assertEqual(self.nb.index('end'), 1) - self.nb.add(self.child2) - self.assertEqual(self.nb.index('end'), 1) - self.nb.select(self.child2) - - self.assertTrue(self.nb.tab('current')) - self.nb.add(self.child1, text='a') - - self.nb.pack() - self.nb.update() - if sys.platform == 'darwin': - tb_idx = "@20,5" - else: - tb_idx = "@5,5" - self.assertEqual(self.nb.tab(tb_idx), self.nb.tab('current')) - - for i in range(5, 100, 5): - try: - if self.nb.tab('@%d, 5' % i, text=None) == 'a': - break - except tkinter.TclError: - pass - - else: - self.fail("Tab with text 'a' not found") - - def test_add_and_hidden(self): - self.assertRaises(tkinter.TclError, self.nb.hide, -1) - self.assertRaises(tkinter.TclError, self.nb.hide, 'hi') - self.assertRaises(tkinter.TclError, self.nb.hide, None) - self.assertRaises(tkinter.TclError, self.nb.add, None) - self.assertRaises(tkinter.TclError, self.nb.add, ttk.Label(self.root), - unknown='option') - - tabs = self.nb.tabs() - self.nb.hide(self.child1) - self.nb.add(self.child1) - self.assertEqual(self.nb.tabs(), tabs) - - child = ttk.Label(self.root) - self.nb.add(child, text='c') - tabs = self.nb.tabs() - - curr = self.nb.index('current') - # verify that the tab gets re-added at its previous position - child2_index = self.nb.index(self.child2) - self.nb.hide(self.child2) - self.nb.add(self.child2) - self.assertEqual(self.nb.tabs(), tabs) - self.assertEqual(self.nb.index(self.child2), child2_index) - self.assertEqual(str(self.child2), self.nb.tabs()[child2_index]) - # but the tab next to it (not hidden) is the one selected now - self.assertEqual(self.nb.index('current'), curr + 1) - - def test_forget(self): - self.assertRaises(tkinter.TclError, self.nb.forget, -1) - self.assertRaises(tkinter.TclError, self.nb.forget, 'hi') - self.assertRaises(tkinter.TclError, self.nb.forget, None) - - tabs = self.nb.tabs() - child1_index = self.nb.index(self.child1) - self.nb.forget(self.child1) - self.assertNotIn(str(self.child1), self.nb.tabs()) - self.assertEqual(len(tabs) - 1, len(self.nb.tabs())) - - self.nb.add(self.child1) - self.assertEqual(self.nb.index(self.child1), 1) - self.assertNotEqual(child1_index, self.nb.index(self.child1)) - - def test_index(self): - self.assertRaises(tkinter.TclError, self.nb.index, -1) - self.assertRaises(tkinter.TclError, self.nb.index, None) - - self.assertIsInstance(self.nb.index('end'), int) - self.assertEqual(self.nb.index(self.child1), 0) - self.assertEqual(self.nb.index(self.child2), 1) - self.assertEqual(self.nb.index('end'), 2) - - def test_insert(self): - # moving tabs - tabs = self.nb.tabs() - self.nb.insert(1, tabs[0]) - self.assertEqual(self.nb.tabs(), (tabs[1], tabs[0])) - self.nb.insert(self.child1, self.child2) - self.assertEqual(self.nb.tabs(), tabs) - self.nb.insert('end', self.child1) - self.assertEqual(self.nb.tabs(), (tabs[1], tabs[0])) - self.nb.insert('end', 0) - self.assertEqual(self.nb.tabs(), tabs) - # bad moves - self.assertRaises(tkinter.TclError, self.nb.insert, 2, tabs[0]) - self.assertRaises(tkinter.TclError, self.nb.insert, -1, tabs[0]) - - # new tab - child3 = ttk.Label(self.root) - self.nb.insert(1, child3) - self.assertEqual(self.nb.tabs(), (tabs[0], str(child3), tabs[1])) - self.nb.forget(child3) - self.assertEqual(self.nb.tabs(), tabs) - self.nb.insert(self.child1, child3) - self.assertEqual(self.nb.tabs(), (str(child3), ) + tabs) - self.nb.forget(child3) - self.assertRaises(tkinter.TclError, self.nb.insert, 2, child3) - self.assertRaises(tkinter.TclError, self.nb.insert, -1, child3) - - # bad inserts - self.assertRaises(tkinter.TclError, self.nb.insert, 'end', None) - self.assertRaises(tkinter.TclError, self.nb.insert, None, 0) - self.assertRaises(tkinter.TclError, self.nb.insert, None, None) - - def test_select(self): - self.nb.pack() - self.nb.update() - - success = [] - tab_changed = [] - - self.child1.bind('', lambda evt: success.append(True)) - self.nb.bind('<>', - lambda evt: tab_changed.append(True)) - - self.assertEqual(self.nb.select(), str(self.child1)) - self.nb.select(self.child2) - self.assertTrue(success) - self.assertEqual(self.nb.select(), str(self.child2)) - - self.nb.update() - self.assertTrue(tab_changed) - - def test_tab(self): - self.assertRaises(tkinter.TclError, self.nb.tab, -1) - self.assertRaises(tkinter.TclError, self.nb.tab, 'notab') - self.assertRaises(tkinter.TclError, self.nb.tab, None) - - self.assertIsInstance(self.nb.tab(self.child1), dict) - self.assertEqual(self.nb.tab(self.child1, text=None), 'a') - # newer form for querying a single option - self.assertEqual(self.nb.tab(self.child1, 'text'), 'a') - self.nb.tab(self.child1, text='abc') - self.assertEqual(self.nb.tab(self.child1, text=None), 'abc') - self.assertEqual(self.nb.tab(self.child1, 'text'), 'abc') - - def test_configure_tabs(self): - self.assertEqual(len(self.nb.tabs()), 2) - - self.nb.forget(self.child1) - self.nb.forget(self.child2) - - self.assertEqual(self.nb.tabs(), ()) - - def test_traversal(self): - self.nb.pack() - self.nb.update() - - self.nb.select(0) - - focus_identify_as = 'focus' if sys.platform != 'darwin' else '' - self.assertEqual(self.nb.identify(5, 5), focus_identify_as) - simulate_mouse_click(self.nb, 5, 5) - self.nb.focus_force() - self.nb.event_generate('') - self.assertEqual(self.nb.select(), str(self.child2)) - self.nb.focus_force() - self.nb.event_generate('') - self.assertEqual(self.nb.select(), str(self.child1)) - self.nb.focus_force() - self.nb.event_generate('') - self.assertEqual(self.nb.select(), str(self.child2)) - - self.nb.tab(self.child1, text='a', underline=0) - self.nb.tab(self.child2, text='e', underline=0) - self.nb.enable_traversal() - self.nb.focus_force() - self.assertEqual(self.nb.identify(5, 5), focus_identify_as) - simulate_mouse_click(self.nb, 5, 5) - # on macOS Emacs-style keyboard shortcuts are region-dependent; - # let's use the regular arrow keys instead - if sys.platform == 'darwin': - begin = '' - end = '' - else: - begin = '' - end = '' - self.nb.event_generate(begin) - self.assertEqual(self.nb.select(), str(self.child1)) - self.nb.event_generate(end) - self.assertEqual(self.nb.select(), str(self.child2)) - - -@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) -class SpinboxTest(EntryTest, unittest.TestCase): - OPTIONS = ( - 'background', 'class', 'command', 'cursor', 'exportselection', - 'font', 'foreground', 'format', 'from', 'increment', - 'invalidcommand', 'justify', 'show', 'state', 'style', - 'takefocus', 'textvariable', 'to', 'validate', 'validatecommand', - 'values', 'width', 'wrap', 'xscrollcommand', - ) - IDENTIFY_AS = 'Spinbox.field' if sys.platform == 'darwin' else 'textarea' - - def setUp(self): - super().setUp() - self.spin = self.create() - self.spin.pack() - - def create(self, **kwargs): - return ttk.Spinbox(self.root, **kwargs) - - def _click_increment_arrow(self): - width = self.spin.winfo_width() - height = self.spin.winfo_height() - x = width - 5 - y = height//2 - 5 - self.assertRegex(self.spin.identify(x, y), r'.*uparrow\Z') - self.spin.event_generate('', x=x, y=y) - self.spin.event_generate('', x=x, y=y) - self.spin.update_idletasks() - - def _click_decrement_arrow(self): - width = self.spin.winfo_width() - height = self.spin.winfo_height() - x = width - 5 - y = height//2 + 4 - self.assertRegex(self.spin.identify(x, y), r'.*downarrow\Z') - self.spin.event_generate('', x=x, y=y) - self.spin.event_generate('', x=x, y=y) - self.spin.update_idletasks() - - def test_configure_command(self): - success = [] - - self.spin['command'] = lambda: success.append(True) - self.spin.update() - self._click_increment_arrow() - self.spin.update() - self.assertTrue(success) - - self._click_decrement_arrow() - self.assertEqual(len(success), 2) - - # testing postcommand removal - self.spin['command'] = '' - self.spin.update_idletasks() - self._click_increment_arrow() - self._click_decrement_arrow() - self.spin.update() - self.assertEqual(len(success), 2) - - def test_configure_to(self): - self.spin['from'] = 0 - self.spin['to'] = 5 - self.spin.set(4) - self.spin.update() - self._click_increment_arrow() # 5 - - self.assertEqual(self.spin.get(), '5') - - self._click_increment_arrow() # 5 - self.assertEqual(self.spin.get(), '5') - - def test_configure_from(self): - self.spin['from'] = 1 - self.spin['to'] = 10 - self.spin.set(2) - self.spin.update() - self._click_decrement_arrow() # 1 - self.assertEqual(self.spin.get(), '1') - self._click_decrement_arrow() # 1 - self.assertEqual(self.spin.get(), '1') - - def test_configure_increment(self): - self.spin['from'] = 0 - self.spin['to'] = 10 - self.spin['increment'] = 4 - self.spin.set(1) - self.spin.update() - - self._click_increment_arrow() # 5 - self.assertEqual(self.spin.get(), '5') - self.spin['increment'] = 2 - self.spin.update() - self._click_decrement_arrow() # 3 - self.assertEqual(self.spin.get(), '3') - - def test_configure_format(self): - self.spin.set(1) - self.spin['format'] = '%10.3f' - self.spin.update() - self._click_increment_arrow() - value = self.spin.get() - - self.assertEqual(len(value), 10) - self.assertEqual(value.index('.'), 6) - - self.spin['format'] = '' - self.spin.update() - self._click_increment_arrow() - value = self.spin.get() - self.assertTrue('.' not in value) - self.assertEqual(len(value), 1) - - def test_configure_wrap(self): - self.spin['to'] = 10 - self.spin['from'] = 1 - self.spin.set(1) - self.spin['wrap'] = True - self.spin.update() - - self._click_decrement_arrow() - self.assertEqual(self.spin.get(), '10') - - self._click_increment_arrow() - self.assertEqual(self.spin.get(), '1') - - self.spin['wrap'] = False - self.spin.update() - - self._click_decrement_arrow() - self.assertEqual(self.spin.get(), '1') - - def test_configure_values(self): - self.assertEqual(self.spin['values'], '') - self.checkParam(self.spin, 'values', 'mon tue wed thur', - expected=('mon', 'tue', 'wed', 'thur')) - self.checkParam(self.spin, 'values', ('mon', 'tue', 'wed', 'thur')) - self.checkParam(self.spin, 'values', (42, 3.14, '', 'any string')) - self.checkParam(self.spin, 'values', '') - - self.spin['values'] = ['a', 1, 'c'] - - # test incrementing / decrementing values - self.spin.set('a') - self.spin.update() - self._click_increment_arrow() - self.assertEqual(self.spin.get(), '1') - - self._click_decrement_arrow() - self.assertEqual(self.spin.get(), 'a') - - # testing values with empty string set through configure - self.spin.configure(values=[1, '', 2]) - self.assertEqual(self.spin['values'], - ('1', '', '2') if self.wantobjects else - '1 {} 2') - - # testing values with spaces - self.spin['values'] = ['a b', 'a\tb', 'a\nb'] - self.assertEqual(self.spin['values'], - ('a b', 'a\tb', 'a\nb') if self.wantobjects else - '{a b} {a\tb} {a\nb}') - - # testing values with special characters - self.spin['values'] = [r'a\tb', '"a"', '} {'] - self.assertEqual(self.spin['values'], - (r'a\tb', '"a"', '} {') if self.wantobjects else - r'a\\tb {"a"} \}\ \{') - - # testing creating spinbox with empty string in values - spin2 = ttk.Spinbox(self.root, values=[1, 2, '']) - self.assertEqual(spin2['values'], - ('1', '2', '') if self.wantobjects else '1 2 {}') - spin2.destroy() - - -@add_standard_options(StandardTtkOptionsTests) -class TreeviewTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'class', 'columns', 'cursor', 'displaycolumns', - 'height', 'padding', 'selectmode', 'show', - 'style', 'takefocus', 'xscrollcommand', 'yscrollcommand', - ) - - def setUp(self): - super().setUp() - self.tv = self.create(padding=0) - - def create(self, **kwargs): - return ttk.Treeview(self.root, **kwargs) - - def test_configure_columns(self): - widget = self.create() - self.checkParam(widget, 'columns', 'a b c', - expected=('a', 'b', 'c')) - self.checkParam(widget, 'columns', ('a', 'b', 'c')) - self.checkParam(widget, 'columns', '') - - def test_configure_displaycolumns(self): - widget = self.create() - widget['columns'] = ('a', 'b', 'c') - self.checkParam(widget, 'displaycolumns', 'b a c', - expected=('b', 'a', 'c')) - self.checkParam(widget, 'displaycolumns', ('b', 'a', 'c')) - self.checkParam(widget, 'displaycolumns', '#all', - expected=('#all',)) - self.checkParam(widget, 'displaycolumns', (2, 1, 0)) - self.checkInvalidParam(widget, 'displaycolumns', ('a', 'b', 'd'), - errmsg='Invalid column index d') - self.checkInvalidParam(widget, 'displaycolumns', (1, 2, 3), - errmsg='Column index 3 out of bounds') - self.checkInvalidParam(widget, 'displaycolumns', (1, -2), - errmsg='Column index -2 out of bounds') - - def test_configure_height(self): - widget = self.create() - self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c', conv=False) - self.checkPixelsParam(widget, 'height', 101.2, 102.6, conv=False) - - def test_configure_selectmode(self): - widget = self.create() - self.checkEnumParam(widget, 'selectmode', - 'none', 'browse', 'extended') - - def test_configure_show(self): - widget = self.create() - self.checkParam(widget, 'show', 'tree headings', - expected=('tree', 'headings')) - self.checkParam(widget, 'show', ('tree', 'headings')) - self.checkParam(widget, 'show', ('headings', 'tree')) - self.checkParam(widget, 'show', 'tree', expected=('tree',)) - self.checkParam(widget, 'show', 'headings', expected=('headings',)) - - def test_bbox(self): - self.tv.pack() - self.assertEqual(self.tv.bbox(''), '') - self.tv.update() - - item_id = self.tv.insert('', 'end') - children = self.tv.get_children() - self.assertTrue(children) - - bbox = self.tv.bbox(children[0]) - self.assertIsBoundingBox(bbox) - - # compare width in bboxes - self.tv['columns'] = ['test'] - self.tv.column('test', width=50) - bbox_column0 = self.tv.bbox(children[0], 0) - root_width = self.tv.column('#0', width=None) - if not self.wantobjects: - root_width = int(root_width) - self.assertEqual(bbox_column0[0], bbox[0] + root_width) - - # verify that bbox of a closed item is the empty string - child1 = self.tv.insert(item_id, 'end') - self.assertEqual(self.tv.bbox(child1), '') - - def test_children(self): - # no children yet, should get an empty tuple - self.assertEqual(self.tv.get_children(), ()) - - item_id = self.tv.insert('', 'end') - self.assertIsInstance(self.tv.get_children(), tuple) - self.assertEqual(self.tv.get_children()[0], item_id) - - # add item_id and child3 as children of child2 - child2 = self.tv.insert('', 'end') - child3 = self.tv.insert('', 'end') - self.tv.set_children(child2, item_id, child3) - self.assertEqual(self.tv.get_children(child2), (item_id, child3)) - - # child3 has child2 as parent, thus trying to set child2 as a children - # of child3 should result in an error - self.assertRaises(tkinter.TclError, - self.tv.set_children, child3, child2) - - # remove child2 children - self.tv.set_children(child2) - self.assertEqual(self.tv.get_children(child2), ()) - - # remove root's children - self.tv.set_children('') - self.assertEqual(self.tv.get_children(), ()) - - def test_column(self): - # return a dict with all options/values - self.assertIsInstance(self.tv.column('#0'), dict) - # return a single value of the given option - if self.wantobjects: - self.assertIsInstance(self.tv.column('#0', width=None), int) - # set a new value for an option - self.tv.column('#0', width=10) - # testing new way to get option value - self.assertEqual(self.tv.column('#0', 'width'), - 10 if self.wantobjects else '10') - self.assertEqual(self.tv.column('#0', width=None), - 10 if self.wantobjects else '10') - # check read-only option - self.assertRaises(tkinter.TclError, self.tv.column, '#0', id='X') - - self.assertRaises(tkinter.TclError, self.tv.column, 'invalid') - invalid_kws = [ - {'unknown_option': 'some value'}, {'stretch': 'wrong'}, - {'anchor': 'wrong'}, {'width': 'wrong'}, {'minwidth': 'wrong'} - ] - for kw in invalid_kws: - self.assertRaises(tkinter.TclError, self.tv.column, '#0', - **kw) - - def test_delete(self): - self.assertRaises(tkinter.TclError, self.tv.delete, '#0') - - item_id = self.tv.insert('', 'end') - item2 = self.tv.insert(item_id, 'end') - self.assertEqual(self.tv.get_children(), (item_id, )) - self.assertEqual(self.tv.get_children(item_id), (item2, )) - - self.tv.delete(item_id) - self.assertFalse(self.tv.get_children()) - - # reattach should fail - self.assertRaises(tkinter.TclError, - self.tv.reattach, item_id, '', 'end') - - # test multiple item delete - item1 = self.tv.insert('', 'end') - item2 = self.tv.insert('', 'end') - self.assertEqual(self.tv.get_children(), (item1, item2)) - - self.tv.delete(item1, item2) - self.assertFalse(self.tv.get_children()) - - def test_detach_reattach(self): - item_id = self.tv.insert('', 'end') - item2 = self.tv.insert(item_id, 'end') - - # calling detach without items is valid, although it does nothing - prev = self.tv.get_children() - self.tv.detach() # this should do nothing - self.assertEqual(prev, self.tv.get_children()) - - self.assertEqual(self.tv.get_children(), (item_id, )) - self.assertEqual(self.tv.get_children(item_id), (item2, )) - - # detach item with children - self.tv.detach(item_id) - self.assertFalse(self.tv.get_children()) - - # reattach item with children - self.tv.reattach(item_id, '', 'end') - self.assertEqual(self.tv.get_children(), (item_id, )) - self.assertEqual(self.tv.get_children(item_id), (item2, )) - - # move a children to the root - self.tv.move(item2, '', 'end') - self.assertEqual(self.tv.get_children(), (item_id, item2)) - self.assertEqual(self.tv.get_children(item_id), ()) - - # bad values - self.assertRaises(tkinter.TclError, - self.tv.reattach, 'nonexistent', '', 'end') - self.assertRaises(tkinter.TclError, - self.tv.detach, 'nonexistent') - self.assertRaises(tkinter.TclError, - self.tv.reattach, item2, 'otherparent', 'end') - self.assertRaises(tkinter.TclError, - self.tv.reattach, item2, '', 'invalid') - - # multiple detach - self.tv.detach(item_id, item2) - self.assertEqual(self.tv.get_children(), ()) - self.assertEqual(self.tv.get_children(item_id), ()) - - def test_exists(self): - self.assertEqual(self.tv.exists('something'), False) - self.assertEqual(self.tv.exists(''), True) - self.assertEqual(self.tv.exists({}), False) - - # the following will make a tk.call equivalent to - # tk.call(treeview, "exists") which should result in an error - # in the tcl interpreter since tk requires an item. - self.assertRaises(tkinter.TclError, self.tv.exists, None) - - def test_focus(self): - # nothing is focused right now - self.assertEqual(self.tv.focus(), '') - - item1 = self.tv.insert('', 'end') - self.tv.focus(item1) - self.assertEqual(self.tv.focus(), item1) - - self.tv.delete(item1) - self.assertEqual(self.tv.focus(), '') - - # try focusing inexistent item - self.assertRaises(tkinter.TclError, self.tv.focus, 'hi') - - def test_heading(self): - # check a dict is returned - self.assertIsInstance(self.tv.heading('#0'), dict) - - # check a value is returned - self.tv.heading('#0', text='hi') - self.assertEqual(self.tv.heading('#0', 'text'), 'hi') - self.assertEqual(self.tv.heading('#0', text=None), 'hi') - - # invalid option - self.assertRaises(tkinter.TclError, self.tv.heading, '#0', - background=None) - # invalid value - self.assertRaises(tkinter.TclError, self.tv.heading, '#0', - anchor=1) - - def test_heading_callback(self): - def simulate_heading_click(x, y): - if tcl_version >= (8, 6): - self.assertEqual(self.tv.identify_column(x), '#0') - self.assertEqual(self.tv.identify_region(x, y), 'heading') - simulate_mouse_click(self.tv, x, y) - self.tv.update() - - success = [] # no success for now - - self.tv.pack() - self.tv.heading('#0', command=lambda: success.append(True)) - self.tv.column('#0', width=100) - self.tv.update() - - # assuming that the coords (5, 5) fall into heading #0 - simulate_heading_click(5, 5) - if not success: - self.fail("The command associated to the treeview heading wasn't " - "invoked.") - - success = [] - commands = self.tv.master._tclCommands - self.tv.heading('#0', command=str(self.tv.heading('#0', command=None))) - self.assertEqual(commands, self.tv.master._tclCommands) - simulate_heading_click(5, 5) - if not success: - self.fail("The command associated to the treeview heading wasn't " - "invoked.") - - # XXX The following raises an error in a tcl interpreter, but not in - # Python - #self.tv.heading('#0', command='I dont exist') - #simulate_heading_click(5, 5) - - def test_index(self): - # item 'what' doesn't exist - self.assertRaises(tkinter.TclError, self.tv.index, 'what') - - self.assertEqual(self.tv.index(''), 0) - - item1 = self.tv.insert('', 'end') - item2 = self.tv.insert('', 'end') - c1 = self.tv.insert(item1, 'end') - c2 = self.tv.insert(item1, 'end') - self.assertEqual(self.tv.index(item1), 0) - self.assertEqual(self.tv.index(c1), 0) - self.assertEqual(self.tv.index(c2), 1) - self.assertEqual(self.tv.index(item2), 1) - - self.tv.move(item2, '', 0) - self.assertEqual(self.tv.index(item2), 0) - self.assertEqual(self.tv.index(item1), 1) - - # check that index still works even after its parent and siblings - # have been detached - self.tv.detach(item1) - self.assertEqual(self.tv.index(c2), 1) - self.tv.detach(c1) - self.assertEqual(self.tv.index(c2), 0) - - # but it fails after item has been deleted - self.tv.delete(item1) - self.assertRaises(tkinter.TclError, self.tv.index, c2) - - def test_insert_item(self): - # parent 'none' doesn't exist - self.assertRaises(tkinter.TclError, self.tv.insert, 'none', 'end') - - # open values - self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', - open='') - self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', - open='please') - self.assertFalse(self.tv.delete(self.tv.insert('', 'end', open=True))) - self.assertFalse(self.tv.delete(self.tv.insert('', 'end', open=False))) - - # invalid index - self.assertRaises(tkinter.TclError, self.tv.insert, '', 'middle') - - # trying to duplicate item id is invalid - itemid = self.tv.insert('', 'end', 'first-item') - self.assertEqual(itemid, 'first-item') - self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', - 'first-item') - self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', - MockTclObj('first-item')) - - # unicode values - value = '\xe1ba' - item = self.tv.insert('', 'end', values=(value, )) - self.assertEqual(self.tv.item(item, 'values'), - (value,) if self.wantobjects else value) - self.assertEqual(self.tv.item(item, values=None), - (value,) if self.wantobjects else value) - - self.tv.item(item, values=self.root.splitlist(self.tv.item(item, values=None))) - self.assertEqual(self.tv.item(item, values=None), - (value,) if self.wantobjects else value) - - self.assertIsInstance(self.tv.item(item), dict) - - # erase item values - self.tv.item(item, values='') - self.assertFalse(self.tv.item(item, values=None)) - - # item tags - item = self.tv.insert('', 'end', tags=[1, 2, value]) - self.assertEqual(self.tv.item(item, tags=None), - ('1', '2', value) if self.wantobjects else - '1 2 %s' % value) - self.tv.item(item, tags=[]) - self.assertFalse(self.tv.item(item, tags=None)) - self.tv.item(item, tags=(1, 2)) - self.assertEqual(self.tv.item(item, tags=None), - ('1', '2') if self.wantobjects else '1 2') - - # values with spaces - item = self.tv.insert('', 'end', values=('a b c', - '%s %s' % (value, value))) - self.assertEqual(self.tv.item(item, values=None), - ('a b c', '%s %s' % (value, value)) if self.wantobjects else - '{a b c} {%s %s}' % (value, value)) - - # text - self.assertEqual(self.tv.item( - self.tv.insert('', 'end', text="Label here"), text=None), - "Label here") - self.assertEqual(self.tv.item( - self.tv.insert('', 'end', text=value), text=None), - value) - - # test for values which are not None - itemid = self.tv.insert('', 'end', 0) - self.assertEqual(itemid, '0') - itemid = self.tv.insert('', 'end', 0.0) - self.assertEqual(itemid, '0.0') - # this is because False resolves to 0 and element with 0 iid is already present - self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', False) - self.assertRaises(tkinter.TclError, self.tv.insert, '', 'end', '') - - def test_selection(self): - self.assertRaises(TypeError, self.tv.selection, 'spam') - # item 'none' doesn't exist - self.assertRaises(tkinter.TclError, self.tv.selection_set, 'none') - self.assertRaises(tkinter.TclError, self.tv.selection_add, 'none') - self.assertRaises(tkinter.TclError, self.tv.selection_remove, 'none') - self.assertRaises(tkinter.TclError, self.tv.selection_toggle, 'none') - - item1 = self.tv.insert('', 'end') - item2 = self.tv.insert('', 'end') - c1 = self.tv.insert(item1, 'end') - c2 = self.tv.insert(item1, 'end') - c3 = self.tv.insert(item1, 'end') - self.assertEqual(self.tv.selection(), ()) - - self.tv.selection_set(c1, item2) - self.assertEqual(self.tv.selection(), (c1, item2)) - self.tv.selection_set(c2) - self.assertEqual(self.tv.selection(), (c2,)) - - self.tv.selection_add(c1, item2) - self.assertEqual(self.tv.selection(), (c1, c2, item2)) - self.tv.selection_add(item1) - self.assertEqual(self.tv.selection(), (item1, c1, c2, item2)) - self.tv.selection_add() - self.assertEqual(self.tv.selection(), (item1, c1, c2, item2)) - - self.tv.selection_remove(item1, c3) - self.assertEqual(self.tv.selection(), (c1, c2, item2)) - self.tv.selection_remove(c2) - self.assertEqual(self.tv.selection(), (c1, item2)) - self.tv.selection_remove() - self.assertEqual(self.tv.selection(), (c1, item2)) - - self.tv.selection_toggle(c1, c3) - self.assertEqual(self.tv.selection(), (c3, item2)) - self.tv.selection_toggle(item2) - self.assertEqual(self.tv.selection(), (c3,)) - self.tv.selection_toggle() - self.assertEqual(self.tv.selection(), (c3,)) - - self.tv.insert('', 'end', id='with spaces') - self.tv.selection_set('with spaces') - self.assertEqual(self.tv.selection(), ('with spaces',)) - - self.tv.insert('', 'end', id='{brace') - self.tv.selection_set('{brace') - self.assertEqual(self.tv.selection(), ('{brace',)) - - self.tv.insert('', 'end', id='unicode\u20ac') - self.tv.selection_set('unicode\u20ac') - self.assertEqual(self.tv.selection(), ('unicode\u20ac',)) - - self.tv.insert('', 'end', id=b'bytes\xe2\x82\xac') - self.tv.selection_set(b'bytes\xe2\x82\xac') - self.assertEqual(self.tv.selection(), ('bytes\xe2\x82\xac',)) - - self.tv.selection_set() - self.assertEqual(self.tv.selection(), ()) - - # Old interface - self.tv.selection_set((c1, item2)) - self.assertEqual(self.tv.selection(), (c1, item2)) - self.tv.selection_add((c1, item1)) - self.assertEqual(self.tv.selection(), (item1, c1, item2)) - self.tv.selection_remove((item1, c3)) - self.assertEqual(self.tv.selection(), (c1, item2)) - self.tv.selection_toggle((c1, c3)) - self.assertEqual(self.tv.selection(), (c3, item2)) - - def test_set(self): - self.tv['columns'] = ['A', 'B'] - item = self.tv.insert('', 'end', values=['a', 'b']) - self.assertEqual(self.tv.set(item), {'A': 'a', 'B': 'b'}) - - self.tv.set(item, 'B', 'a') - self.assertEqual(self.tv.item(item, values=None), - ('a', 'a') if self.wantobjects else 'a a') - - self.tv['columns'] = ['B'] - self.assertEqual(self.tv.set(item), {'B': 'a'}) - - self.tv.set(item, 'B', 'b') - self.assertEqual(self.tv.set(item, column='B'), 'b') - self.assertEqual(self.tv.item(item, values=None), - ('b', 'a') if self.wantobjects else 'b a') - - self.tv.set(item, 'B', 123) - self.assertEqual(self.tv.set(item, 'B'), - 123 if self.wantobjects else '123') - self.assertEqual(self.tv.item(item, values=None), - (123, 'a') if self.wantobjects else '123 a') - self.assertEqual(self.tv.set(item), - {'B': 123} if self.wantobjects else {'B': '123'}) - - # inexistent column - self.assertRaises(tkinter.TclError, self.tv.set, item, 'A') - self.assertRaises(tkinter.TclError, self.tv.set, item, 'A', 'b') - - # inexistent item - self.assertRaises(tkinter.TclError, self.tv.set, 'notme') - - def test_tag_bind(self): - events = [] - item1 = self.tv.insert('', 'end', tags=['call']) - item2 = self.tv.insert('', 'end', tags=['call']) - self.tv.tag_bind('call', '', - lambda evt: events.append(1)) - self.tv.tag_bind('call', '', - lambda evt: events.append(2)) - - self.tv.pack() - self.tv.update() - - pos_y = set() - found = set() - for i in range(0, 100, 10): - if len(found) == 2: # item1 and item2 already found - break - item_id = self.tv.identify_row(i) - if item_id and item_id not in found: - pos_y.add(i) - found.add(item_id) - - self.assertEqual(len(pos_y), 2) # item1 and item2 y pos - for y in pos_y: - simulate_mouse_click(self.tv, 0, y) - - # by now there should be 4 things in the events list, since each - # item had a bind for two events that were simulated above - self.assertEqual(len(events), 4) - for evt in zip(events[::2], events[1::2]): - self.assertEqual(evt, (1, 2)) - - def test_tag_configure(self): - # Just testing parameter passing for now - self.assertRaises(TypeError, self.tv.tag_configure) - self.assertRaises(tkinter.TclError, self.tv.tag_configure, - 'test', sky='blue') - self.tv.tag_configure('test', foreground='blue') - self.assertEqual(str(self.tv.tag_configure('test', 'foreground')), - 'blue') - self.assertEqual(str(self.tv.tag_configure('test', foreground=None)), - 'blue') - self.assertIsInstance(self.tv.tag_configure('test'), dict) - - def test_tag_has(self): - item1 = self.tv.insert('', 'end', text='Item 1', tags=['tag1']) - item2 = self.tv.insert('', 'end', text='Item 2', tags=['tag2']) - self.assertRaises(TypeError, self.tv.tag_has) - self.assertRaises(TclError, self.tv.tag_has, 'tag1', 'non-existing') - self.assertTrue(self.tv.tag_has('tag1', item1)) - self.assertFalse(self.tv.tag_has('tag1', item2)) - self.assertFalse(self.tv.tag_has('tag2', item1)) - self.assertTrue(self.tv.tag_has('tag2', item2)) - self.assertFalse(self.tv.tag_has('tag3', item1)) - self.assertFalse(self.tv.tag_has('tag3', item2)) - self.assertEqual(self.tv.tag_has('tag1'), (item1,)) - self.assertEqual(self.tv.tag_has('tag2'), (item2,)) - self.assertEqual(self.tv.tag_has('tag3'), ()) - - -@add_standard_options(StandardTtkOptionsTests) -class SeparatorTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'class', 'cursor', 'orient', 'style', 'takefocus', - # 'state'? - ) - default_orient = 'horizontal' - - def create(self, **kwargs): - return ttk.Separator(self.root, **kwargs) - - -@add_standard_options(StandardTtkOptionsTests) -class SizegripTest(AbstractWidgetTest, unittest.TestCase): - OPTIONS = ( - 'class', 'cursor', 'style', 'takefocus', - # 'state'? - ) - - 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, DefaultRootTest, - ) - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/tkinter/test/widget_tests.py b/Lib/tkinter/test/widget_tests.py deleted file mode 100644 index 8418154..0000000 --- a/Lib/tkinter/test/widget_tests.py +++ /dev/null @@ -1,519 +0,0 @@ -# Common tests for test_tkinter/test_widgets.py and test_ttk/test_widgets.py - -import tkinter -from tkinter.test.support import (AbstractTkTest, tcl_version, - pixels_conv, tcl_obj_eq) -import test.support - - -_sentinel = object() - -class AbstractWidgetTest(AbstractTkTest): - _conv_pixels = round - _conv_pad_pixels = None - _stringify = False - - @property - def scaling(self): - try: - return self._scaling - except AttributeError: - self._scaling = float(self.root.call('tk', 'scaling')) - return self._scaling - - def _str(self, value): - if not self._stringify and self.wantobjects and tcl_version >= (8, 6): - return value - if isinstance(value, tuple): - return ' '.join(map(self._str, value)) - return str(value) - - def assertEqual2(self, actual, expected, msg=None, eq=object.__eq__): - if eq(actual, expected): - return - self.assertEqual(actual, expected, msg) - - def checkParam(self, widget, name, value, *, expected=_sentinel, - conv=False, eq=None): - widget[name] = value - if expected is _sentinel: - expected = value - if conv: - expected = conv(expected) - if self._stringify or not self.wantobjects: - if isinstance(expected, tuple): - expected = tkinter._join(expected) - else: - expected = str(expected) - if eq is None: - eq = tcl_obj_eq - self.assertEqual2(widget[name], expected, eq=eq) - self.assertEqual2(widget.cget(name), expected, eq=eq) - t = widget.configure(name) - self.assertEqual(len(t), 5) - self.assertEqual2(t[4], expected, eq=eq) - - def checkInvalidParam(self, widget, name, value, errmsg=None): - orig = widget[name] - if errmsg is not None: - errmsg = errmsg.format(value) - with self.assertRaises(tkinter.TclError) as cm: - widget[name] = value - if errmsg is not None: - self.assertEqual(str(cm.exception), errmsg) - self.assertEqual(widget[name], orig) - with self.assertRaises(tkinter.TclError) as cm: - widget.configure({name: value}) - if errmsg is not None: - self.assertEqual(str(cm.exception), errmsg) - self.assertEqual(widget[name], orig) - - def checkParams(self, widget, name, *values, **kwargs): - for value in values: - self.checkParam(widget, name, value, **kwargs) - - def checkIntegerParam(self, widget, name, *values, **kwargs): - self.checkParams(widget, name, *values, **kwargs) - self.checkInvalidParam(widget, name, '', - errmsg='expected integer but got ""') - self.checkInvalidParam(widget, name, '10p', - errmsg='expected integer but got "10p"') - self.checkInvalidParam(widget, name, 3.2, - errmsg='expected integer but got "3.2"') - - def checkFloatParam(self, widget, name, *values, conv=float, **kwargs): - for value in values: - self.checkParam(widget, name, value, conv=conv, **kwargs) - self.checkInvalidParam(widget, name, '', - errmsg='expected floating-point number but got ""') - self.checkInvalidParam(widget, name, 'spam', - errmsg='expected floating-point number but got "spam"') - - def checkBooleanParam(self, widget, name): - for value in (False, 0, 'false', 'no', 'off'): - self.checkParam(widget, name, value, expected=0) - for value in (True, 1, 'true', 'yes', 'on'): - self.checkParam(widget, name, value, expected=1) - self.checkInvalidParam(widget, name, '', - errmsg='expected boolean value but got ""') - self.checkInvalidParam(widget, name, 'spam', - errmsg='expected boolean value but got "spam"') - - def checkColorParam(self, widget, name, *, allow_empty=None, **kwargs): - self.checkParams(widget, name, - '#ff0000', '#00ff00', '#0000ff', '#123456', - 'red', 'green', 'blue', 'white', 'black', 'grey', - **kwargs) - self.checkInvalidParam(widget, name, 'spam', - errmsg='unknown color name "spam"') - - def checkCursorParam(self, widget, name, **kwargs): - self.checkParams(widget, name, 'arrow', 'watch', 'cross', '',**kwargs) - self.checkParam(widget, name, 'none') - self.checkInvalidParam(widget, name, 'spam', - errmsg='bad cursor spec "spam"') - - def checkCommandParam(self, widget, name): - def command(*args): - pass - widget[name] = command - self.assertTrue(widget[name]) - self.checkParams(widget, name, '') - - def checkEnumParam(self, widget, name, *values, errmsg=None, **kwargs): - self.checkParams(widget, name, *values, **kwargs) - if errmsg is None: - errmsg2 = ' %s "{}": must be %s%s or %s' % ( - name, - ', '.join(values[:-1]), - ',' if len(values) > 2 else '', - values[-1]) - self.checkInvalidParam(widget, name, '', - errmsg='ambiguous' + errmsg2) - errmsg = 'bad' + errmsg2 - self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) - - def checkPixelsParam(self, widget, name, *values, - conv=None, **kwargs): - if conv is None: - conv = self._conv_pixels - for value in values: - expected = _sentinel - conv1 = conv - if isinstance(value, str): - if conv1 and conv1 is not str: - expected = pixels_conv(value) * self.scaling - conv1 = round - self.checkParam(widget, name, value, expected=expected, - conv=conv1, **kwargs) - self.checkInvalidParam(widget, name, '6x', - errmsg='bad screen distance "6x"') - self.checkInvalidParam(widget, name, 'spam', - errmsg='bad screen distance "spam"') - - def checkReliefParam(self, widget, name): - self.checkParams(widget, name, - 'flat', 'groove', 'raised', 'ridge', 'solid', 'sunken') - errmsg='bad relief "spam": must be '\ - 'flat, groove, raised, ridge, solid, or sunken' - if tcl_version < (8, 6): - errmsg = None - self.checkInvalidParam(widget, name, 'spam', - errmsg=errmsg) - - def checkImageParam(self, widget, name): - image = tkinter.PhotoImage(master=self.root, name='image1') - self.checkParam(widget, name, image, conv=str) - self.checkInvalidParam(widget, name, 'spam', - errmsg='image "spam" doesn\'t exist') - widget[name] = '' - - def checkVariableParam(self, widget, name, var): - self.checkParam(widget, name, var, conv=str) - - def assertIsBoundingBox(self, bbox): - self.assertIsNotNone(bbox) - self.assertIsInstance(bbox, tuple) - if len(bbox) != 4: - self.fail('Invalid bounding box: %r' % (bbox,)) - for item in bbox: - if not isinstance(item, int): - self.fail('Invalid bounding box: %r' % (bbox,)) - break - - - def test_keys(self): - widget = self.create() - keys = widget.keys() - self.assertEqual(sorted(keys), sorted(widget.configure())) - for k in keys: - widget[k] - # Test if OPTIONS contains all keys - if test.support.verbose: - aliases = { - 'bd': 'borderwidth', - 'bg': 'background', - 'fg': 'foreground', - 'invcmd': 'invalidcommand', - 'vcmd': 'validatecommand', - } - keys = set(keys) - expected = set(self.OPTIONS) - for k in sorted(keys - expected): - if not (k in aliases and - aliases[k] in keys and - aliases[k] in expected): - print('%s.OPTIONS doesn\'t contain "%s"' % - (self.__class__.__name__, k)) - - -class StandardOptionsTests: - STANDARD_OPTIONS = ( - 'activebackground', 'activeborderwidth', 'activeforeground', 'anchor', - 'background', 'bitmap', 'borderwidth', 'compound', 'cursor', - 'disabledforeground', 'exportselection', 'font', 'foreground', - 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'image', 'insertbackground', 'insertborderwidth', - 'insertofftime', 'insertontime', 'insertwidth', - 'jump', 'justify', 'orient', 'padx', 'pady', 'relief', - 'repeatdelay', 'repeatinterval', - 'selectbackground', 'selectborderwidth', 'selectforeground', - 'setgrid', 'takefocus', 'text', 'textvariable', 'troughcolor', - 'underline', 'wraplength', 'xscrollcommand', 'yscrollcommand', - ) - - def test_configure_activebackground(self): - widget = self.create() - self.checkColorParam(widget, 'activebackground') - - def test_configure_activeborderwidth(self): - widget = self.create() - self.checkPixelsParam(widget, 'activeborderwidth', - 0, 1.3, 2.9, 6, -2, '10p') - - def test_configure_activeforeground(self): - widget = self.create() - self.checkColorParam(widget, 'activeforeground') - - def test_configure_anchor(self): - widget = self.create() - self.checkEnumParam(widget, 'anchor', - 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center') - - def test_configure_background(self): - widget = self.create() - self.checkColorParam(widget, 'background') - if 'bg' in self.OPTIONS: - self.checkColorParam(widget, 'bg') - - def test_configure_bitmap(self): - widget = self.create() - self.checkParam(widget, 'bitmap', 'questhead') - self.checkParam(widget, 'bitmap', 'gray50') - filename = test.support.findfile('python.xbm', subdir='imghdrdata') - self.checkParam(widget, 'bitmap', '@' + filename) - # Cocoa Tk widgets don't detect invalid -bitmap values - # See https://core.tcl.tk/tk/info/31cd33dbf0 - if not ('aqua' in self.root.tk.call('tk', 'windowingsystem') and - 'AppKit' in self.root.winfo_server()): - self.checkInvalidParam(widget, 'bitmap', 'spam', - errmsg='bitmap "spam" not defined') - - def test_configure_borderwidth(self): - widget = self.create() - self.checkPixelsParam(widget, 'borderwidth', - 0, 1.3, 2.6, 6, -2, '10p') - if 'bd' in self.OPTIONS: - self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, -2, '10p') - - def test_configure_compound(self): - widget = self.create() - self.checkEnumParam(widget, 'compound', - 'bottom', 'center', 'left', 'none', 'right', 'top') - - def test_configure_cursor(self): - widget = self.create() - self.checkCursorParam(widget, 'cursor') - - def test_configure_disabledforeground(self): - widget = self.create() - self.checkColorParam(widget, 'disabledforeground') - - def test_configure_exportselection(self): - widget = self.create() - self.checkBooleanParam(widget, 'exportselection') - - def test_configure_font(self): - widget = self.create() - self.checkParam(widget, 'font', - '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') - self.checkInvalidParam(widget, 'font', '', - errmsg='font "" doesn\'t exist') - - def test_configure_foreground(self): - widget = self.create() - self.checkColorParam(widget, 'foreground') - if 'fg' in self.OPTIONS: - self.checkColorParam(widget, 'fg') - - def test_configure_highlightbackground(self): - widget = self.create() - self.checkColorParam(widget, 'highlightbackground') - - def test_configure_highlightcolor(self): - widget = self.create() - self.checkColorParam(widget, 'highlightcolor') - - def test_configure_highlightthickness(self): - widget = self.create() - self.checkPixelsParam(widget, 'highlightthickness', - 0, 1.3, 2.6, 6, '10p') - self.checkParam(widget, 'highlightthickness', -2, expected=0, - conv=self._conv_pixels) - - def test_configure_image(self): - widget = self.create() - self.checkImageParam(widget, 'image') - - def test_configure_insertbackground(self): - widget = self.create() - self.checkColorParam(widget, 'insertbackground') - - def test_configure_insertborderwidth(self): - widget = self.create() - self.checkPixelsParam(widget, 'insertborderwidth', - 0, 1.3, 2.6, 6, -2, '10p') - - def test_configure_insertofftime(self): - widget = self.create() - self.checkIntegerParam(widget, 'insertofftime', 100) - - def test_configure_insertontime(self): - widget = self.create() - self.checkIntegerParam(widget, 'insertontime', 100) - - def test_configure_insertwidth(self): - widget = self.create() - self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p') - - def test_configure_jump(self): - widget = self.create() - self.checkBooleanParam(widget, 'jump') - - def test_configure_justify(self): - widget = self.create() - self.checkEnumParam(widget, 'justify', 'left', 'right', 'center', - errmsg='bad justification "{}": must be ' - 'left, right, or center') - self.checkInvalidParam(widget, 'justify', '', - errmsg='ambiguous justification "": must be ' - 'left, right, or center') - - def test_configure_orient(self): - widget = self.create() - self.assertEqual(str(widget['orient']), self.default_orient) - self.checkEnumParam(widget, 'orient', 'horizontal', 'vertical') - - def test_configure_padx(self): - widget = self.create() - self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, -2, '12m', - conv=self._conv_pad_pixels) - - def test_configure_pady(self): - widget = self.create() - self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, -2, '12m', - conv=self._conv_pad_pixels) - - def test_configure_relief(self): - widget = self.create() - self.checkReliefParam(widget, 'relief') - - def test_configure_repeatdelay(self): - widget = self.create() - self.checkIntegerParam(widget, 'repeatdelay', -500, 500) - - def test_configure_repeatinterval(self): - widget = self.create() - self.checkIntegerParam(widget, 'repeatinterval', -500, 500) - - def test_configure_selectbackground(self): - widget = self.create() - self.checkColorParam(widget, 'selectbackground') - - def test_configure_selectborderwidth(self): - widget = self.create() - self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p') - - def test_configure_selectforeground(self): - widget = self.create() - self.checkColorParam(widget, 'selectforeground') - - def test_configure_setgrid(self): - widget = self.create() - self.checkBooleanParam(widget, 'setgrid') - - def test_configure_state(self): - widget = self.create() - self.checkEnumParam(widget, 'state', 'active', 'disabled', 'normal') - - def test_configure_takefocus(self): - widget = self.create() - self.checkParams(widget, 'takefocus', '0', '1', '') - - def test_configure_text(self): - widget = self.create() - self.checkParams(widget, 'text', '', 'any string') - - def test_configure_textvariable(self): - widget = self.create() - var = tkinter.StringVar(self.root) - self.checkVariableParam(widget, 'textvariable', var) - - def test_configure_troughcolor(self): - widget = self.create() - self.checkColorParam(widget, 'troughcolor') - - def test_configure_underline(self): - widget = self.create() - self.checkIntegerParam(widget, 'underline', 0, 1, 10) - - def test_configure_wraplength(self): - widget = self.create() - self.checkPixelsParam(widget, 'wraplength', 100) - - def test_configure_xscrollcommand(self): - widget = self.create() - self.checkCommandParam(widget, 'xscrollcommand') - - def test_configure_yscrollcommand(self): - widget = self.create() - self.checkCommandParam(widget, 'yscrollcommand') - - # non-standard but common options - - def test_configure_command(self): - widget = self.create() - self.checkCommandParam(widget, 'command') - - def test_configure_indicatoron(self): - widget = self.create() - self.checkBooleanParam(widget, 'indicatoron') - - def test_configure_offrelief(self): - widget = self.create() - self.checkReliefParam(widget, 'offrelief') - - def test_configure_overrelief(self): - widget = self.create() - self.checkReliefParam(widget, 'overrelief') - - def test_configure_selectcolor(self): - widget = self.create() - self.checkColorParam(widget, 'selectcolor') - - def test_configure_selectimage(self): - widget = self.create() - self.checkImageParam(widget, 'selectimage') - - def test_configure_tristateimage(self): - widget = self.create() - self.checkImageParam(widget, 'tristateimage') - - def test_configure_tristatevalue(self): - widget = self.create() - self.checkParam(widget, 'tristatevalue', 'unknowable') - - def test_configure_variable(self): - widget = self.create() - var = tkinter.DoubleVar(self.root) - self.checkVariableParam(widget, 'variable', var) - - -class IntegerSizeTests: - def test_configure_height(self): - widget = self.create() - self.checkIntegerParam(widget, 'height', 100, -100, 0) - - def test_configure_width(self): - widget = self.create() - self.checkIntegerParam(widget, 'width', 402, -402, 0) - - -class PixelSizeTests: - def test_configure_height(self): - widget = self.create() - self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '3c') - - def test_configure_width(self): - widget = self.create() - self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i') - - -def add_standard_options(*source_classes): - # This decorator adds test_configure_xxx methods from source classes for - # every xxx option in the OPTIONS class attribute if they are not defined - # explicitly. - def decorator(cls): - for option in cls.OPTIONS: - methodname = 'test_configure_' + option - if not hasattr(cls, methodname): - for source_class in source_classes: - if hasattr(source_class, methodname): - setattr(cls, methodname, - getattr(source_class, methodname)) - break - else: - def test(self, option=option): - widget = self.create() - widget[option] - raise AssertionError('Option "%s" is not tested in %s' % - (option, cls.__name__)) - test.__name__ = methodname - setattr(cls, methodname, test) - return cls - return decorator - -def setUpModule(): - if test.support.verbose: - tcl = tkinter.Tcl() - print('patchlevel =', tcl.call('info', 'patchlevel'), flush=True) diff --git a/Makefile.pre.in b/Makefile.pre.in index 6448785..5d0ae6b 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1987,15 +1987,15 @@ TESTSUBDIRS= distutils/tests \ test/test_lib2to3/data/fixers \ test/test_lib2to3/data/fixers/myfixes \ test/test_peg_generator \ + test/test_tkinter \ test/test_tools \ + test/test_ttk \ test/test_warnings test/test_warnings/data \ test/test_zoneinfo test/test_zoneinfo/data \ test/test_unittest test/test_unittest/testmock \ test/tracedmodules \ test/xmltestdata test/xmltestdata/c14n-20 \ - test/ziptestdata \ - tkinter/test tkinter/test/test_tkinter \ - tkinter/test/test_ttk + test/ziptestdata TEST_MODULES=@TEST_MODULES@ libinstall: all $(srcdir)/Modules/xxmodule.c diff --git a/Misc/NEWS.d/next/Tests/2022-06-21-17-37-46.gh-issue-54781.BjVAVg.rst b/Misc/NEWS.d/next/Tests/2022-06-21-17-37-46.gh-issue-54781.BjVAVg.rst new file mode 100644 index 0000000..f7ae7b9 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-06-21-17-37-46.gh-issue-54781.BjVAVg.rst @@ -0,0 +1,2 @@ +Rename test_tk to test_tkinter, and rename test_ttk_guionly to test_ttk. +Patch by Victor Stinner. diff --git a/PCbuild/lib.pyproj b/PCbuild/lib.pyproj index 2355eb5..0556efe 100644 --- a/PCbuild/lib.pyproj +++ b/PCbuild/lib.pyproj @@ -1323,7 +1323,17 @@ - + + + + + + + + + + + @@ -1339,8 +1349,11 @@ - + + + + @@ -1353,7 +1366,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1432,22 +1471,6 @@ - - - - - - - - - - - - - - - - @@ -1490,33 +1513,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1802,16 +1798,15 @@ + + - - - diff --git a/Tools/wasm/wasm_assets.py b/Tools/wasm/wasm_assets.py index 67afde6..a59db9d 100755 --- a/Tools/wasm/wasm_assets.py +++ b/Tools/wasm/wasm_assets.py @@ -109,11 +109,6 @@ OMIT_MODULE_FILES = { "_zoneinfo": ["zoneinfo/"], } -# regression test sub directories -OMIT_SUBDIRS = ( - "tkinter/test/", -) - def get_builddir(args: argparse.Namespace) -> pathlib.Path: """Get builddir path from pybuilddir.txt """ @@ -136,9 +131,6 @@ def create_stdlib_zip( *, optimize: int = 0, ) -> None: - def filterfunc(name: str) -> bool: - return not name.startswith(args.omit_subdirs_absolute) - with zipfile.PyZipFile( args.wasm_stdlib_zip, mode="w", compression=args.compression, optimize=optimize ) as pzf: @@ -152,7 +144,7 @@ def create_stdlib_zip( continue if entry.name.endswith(".py") or entry.is_dir(): # writepy() writes .pyc files (bytecode). - pzf.writepy(entry, filterfunc=filterfunc) + pzf.writepy(entry) def detect_extension_modules(args: argparse.Namespace): @@ -234,9 +226,6 @@ def main(): omit_files.extend(modfiles) args.omit_files_absolute = {args.srcdir_lib / name for name in omit_files} - args.omit_subdirs_absolute = tuple( - str(args.srcdir_lib / name) for name in OMIT_SUBDIRS - ) # Empty, unused directory for dynamic libs, but required for site initialization. args.wasm_dynload.mkdir(parents=True, exist_ok=True) -- cgit v0.12