From 66cc04855100c3865bd01adfe92a3a02dbc3a914 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 20 Jun 2026 01:45:47 +0300 Subject: [PATCH] gh-151678: Add tests for tkinter font, image, variable, Misc and Wm methods (GH-151751) * font: copy(), the config alias, the displayof argument of measure and metrics, and the errors raised for invalid options and a wrong number of arguments; * image: the cget method and the config alias, and the errors raised by transparency_get and transparency_set; * variable: that initialize is an alias of set and the deprecated trace is an alias of trace_variable; * Misc: tk_focusNext, tk_focusPrev, tk_strictMotif, tk_bisque and option_readfile; * Wm: wm_iconphoto. Co-authored-by: Claude Opus 4.8 (1M context) --- Lib/test/test_tkinter/test_font.py | 33 +++++++++++++++ Lib/test/test_tkinter/test_images.py | 13 ++++++ Lib/test/test_tkinter/test_misc.py | 53 +++++++++++++++++++++++++ Lib/test/test_tkinter/test_variables.py | 3 ++ 4 files changed, 102 insertions(+) diff --git a/Lib/test/test_tkinter/test_font.py b/Lib/test/test_tkinter/test_font.py index ee147710fbfc..8adc9e1151db 100644 --- a/Lib/test/test_tkinter/test_font.py +++ b/Lib/test/test_tkinter/test_font.py @@ -21,6 +21,7 @@ class FontTest(AbstractTkTest, unittest.TestCase): cls.font = font.Font(root=cls.root, name=fontname, exists=False) def test_configure(self): + self.assertEqual(self.font.config, self.font.configure) options = self.font.configure() self.assertGreaterEqual(set(options), {'family', 'size', 'weight', 'slant', 'underline', 'overstrike'}) @@ -36,6 +37,26 @@ class FontTest(AbstractTkTest, unittest.TestCase): self.assertIsInstance(options[key], sizetype) self.assertIsInstance(self.font.cget(key), sizetype) self.assertIsInstance(self.font[key], sizetype) + self.assertRaisesRegex(tkinter.TclError, 'bad option "-spam"', + self.font.cget, 'spam') + self.assertRaisesRegex(tkinter.TclError, 'bad option "-spam"', + self.font.configure, spam='x') + self.assertRaises(TypeError, self.font.cget) + self.assertRaises(TypeError, self.font.cget, 'size', 'weight') + + def test_copy(self): + f = font.Font(root=self.root, family='Times', size=10, weight='bold') + copied = f.copy() + self.assertIsInstance(copied, font.Font) + self.assertIsNot(copied, f) + self.assertNotEqual(copied.name, f.name) + self.assertEqual(copied.actual(), f.actual()) + # The copy is independent of the original. + sizetype = int if self.wantobjects else str + copied.configure(size=20) + self.assertEqual(f.cget('size'), sizetype(10)) + self.assertEqual(copied.cget('size'), sizetype(20)) + self.assertRaises(TypeError, f.copy, 'x') def test_unicode_family(self): family = 'MS \u30b4\u30b7\u30c3\u30af' @@ -60,6 +81,9 @@ class FontTest(AbstractTkTest, unittest.TestCase): for key in 'size', 'underline', 'overstrike': self.assertIsInstance(options[key], sizetype) self.assertIsInstance(self.font.actual(key), sizetype) + self.assertRaisesRegex(tkinter.TclError, 'bad option "-spam"', + self.font.actual, 'spam') + self.assertRaises(TypeError, self.font.actual, 'size', 'weight', 'slant') def test_name(self): self.assertEqual(self.font.name, fontname) @@ -83,6 +107,11 @@ class FontTest(AbstractTkTest, unittest.TestCase): def test_measure(self): self.assertIsInstance(self.font.measure('abc'), int) + self.assertEqual(self.font.measure(''), 0) + self.assertIsInstance( + self.font.measure('abc', displayof=self.root), int) + self.assertRaises(TypeError, self.font.measure) + self.assertRaises(TypeError, self.font.measure, 'a', 'b', 'c') def test_metrics(self): metrics = self.font.metrics() @@ -90,8 +119,12 @@ class FontTest(AbstractTkTest, unittest.TestCase): {'ascent', 'descent', 'linespace', 'fixed'}) for key in metrics: self.assertEqual(self.font.metrics(key), metrics[key]) + self.assertEqual(self.font.metrics(key, displayof=self.root), + metrics[key]) self.assertIsInstance(metrics[key], int) self.assertIsInstance(self.font.metrics(key), int) + self.assertRaisesRegex(tkinter.TclError, 'bad metric "-spam"', + self.font.metrics, 'spam') def test_families(self): families = font.families(self.root) diff --git a/Lib/test/test_tkinter/test_images.py b/Lib/test/test_tkinter/test_images.py index 3aca9515a33b..f9b314da9e8a 100644 --- a/Lib/test/test_tkinter/test_images.py +++ b/Lib/test/test_tkinter/test_images.py @@ -288,6 +288,11 @@ class PhotoImageTest(BaseImageTest, AbstractTkTest, unittest.TestCase): image.configure(height=10) self.assertEqual(image['width'], '20') self.assertEqual(image['height'], '10') + self.assertEqual(image.cget('width'), image['width']) + self.assertEqual(image.cget('height'), image['height']) + self.assertRaises(TypeError, image.cget) + self.assertRaises(TypeError, image.cget, 'width', 'height') + self.assertEqual(image.config, image.configure) self.assertEqual(image.width(), 20) self.assertEqual(image.height(), 10) @@ -656,6 +661,14 @@ class PhotoImageTest(BaseImageTest, AbstractTkTest, unittest.TestCase): self.assertEqual(image.transparency_get(4, 6), True) image.transparency_set(4, 6, False) self.assertEqual(image.transparency_get(4, 6), False) + self.assertRaises(tkinter.TclError, image.transparency_get, -1, 0) + self.assertRaises(tkinter.TclError, image.transparency_get, 16, 0) + self.assertRaises(tkinter.TclError, image.transparency_set, -1, 0, True) + self.assertRaises(tkinter.TclError, image.transparency_set, 16, 0, True) + self.assertRaises(TypeError, image.transparency_get, 0) + self.assertRaises(TypeError, image.transparency_get, 0, 0, 0) + self.assertRaises(TypeError, image.transparency_set, 0, 0) + self.assertRaises(TypeError, image.transparency_set, 0, 0, True, 0) if __name__ == "__main__": diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 1b32689bb596..0819b77e6643 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -7,6 +7,7 @@ import tkinter from tkinter import TclError import enum from test import support +from test.support import os_helper from test.test_tkinter.support import setUpModule # noqa: F401 from test.test_tkinter.support import (AbstractTkTest, AbstractDefaultRootTest, requires_tk, get_tk_patchlevel) @@ -357,6 +358,19 @@ class MiscTest(AbstractTkTest, unittest.TestCase): self.root.option_clear() self.assertEqual(b.option_get('background', 'Background'), '') + def test_option_readfile(self): + self.addCleanup(self.root.option_clear) + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + with open(os_helper.TESTFN, 'w') as f: + f.write('*Button.background: red\n') + self.root.option_readfile(os_helper.TESTFN) + b = tkinter.Button(self.root) + self.assertEqual(b.option_get('background', 'Background'), 'red') + self.assertRaises(TclError, self.root.option_readfile, + os_helper.TESTFN + '.nonexistent') + self.assertRaises(TypeError, self.root.option_readfile) + self.assertRaises(TypeError, self.root.option_readfile, 'a', 'b', 'c') + def test_nametowidget(self): b = tkinter.Button(self.root, name='btn') self.assertIs(self.root.nametowidget('btn'), b) @@ -417,6 +431,38 @@ class MiscTest(AbstractTkTest, unittest.TestCase): self.root.bell() # No exception. self.root.bell(displayof=self.root) + def test_tk_focusNext_focusPrev(self): + f = tkinter.Frame(self.root) + f.pack() + entries = [tkinter.Entry(f) for _ in range(3)] + for entry in entries: + entry.pack() + # tk_focusNext skips widgets that are not viewable. + entries[-1].wait_visibility() + self.assertIs(entries[0].tk_focusNext(), entries[1]) + self.assertIs(entries[1].tk_focusNext(), entries[2]) + self.assertIs(entries[2].tk_focusPrev(), entries[1]) + self.assertIs(entries[1].tk_focusPrev(), entries[0]) + self.assertRaises(TypeError, entries[0].tk_focusNext, 'x') + self.assertRaises(TypeError, entries[0].tk_focusPrev, 'x') + + def test_tk_strictMotif(self): + self.addCleanup(self.root.tk_strictMotif, False) + self.assertIs(self.root.tk_strictMotif(), False) + self.assertIs(self.root.tk_strictMotif(True), True) + self.assertIs(self.root.tk_strictMotif(), True) + self.assertIs(self.root.tk_strictMotif(False), False) + self.assertRaises(TypeError, self.root.tk_strictMotif, 1, 2) + + def test_tk_bisque(self): + # tk_bisque resets the color palette; use a separate root so that + # the shared one is not affected. + root = tkinter.Tk() + self.addCleanup(root.destroy) + root.tk_bisque() + self.assertEqual(root['background'], '#ffe4c4') + self.assertRaises(TypeError, root.tk_bisque, 'x') + def test_event_repr_defaults(self): e = tkinter.Event() e.serial = 12345 @@ -819,6 +865,13 @@ class WmTest(AbstractTkTest, unittest.TestCase): t.destroy() + def test_wm_iconphoto(self): + t = tkinter.Toplevel(self.root) + img = tkinter.PhotoImage(master=t, width=16, height=16) + t.wm_iconphoto(False, img) # No exception. + t.wm_iconphoto(True, img) + self.assertRaises(tkinter.TclError, t.wm_iconphoto, False, 'spam') + def test_wm_title(self): t = tkinter.Toplevel(self.root) t.title('Hello') diff --git a/Lib/test/test_tkinter/test_variables.py b/Lib/test/test_tkinter/test_variables.py index 8733095ffb65..5ee4e9467dd0 100644 --- a/Lib/test/test_tkinter/test_variables.py +++ b/Lib/test/test_tkinter/test_variables.py @@ -111,6 +111,7 @@ class TestVariable(TestBase): self.assertFalse(v.side_effect) v.set("value") self.assertTrue(v.side_effect) + self.assertEqual(Variable.initialize, Variable.set) def test_trace_old(self): if tcl_version >= (9, 0): @@ -118,6 +119,7 @@ class TestVariable(TestBase): # Old interface v = Variable(self.root) vname = str(v) + self.assertEqual(v.trace, v.trace_variable) trace = [] def read_tracer(*args): trace.append(('read',) + args) @@ -328,6 +330,7 @@ class TestBooleanVar(TestBase): self.assertEqual(self.root.globalgetvar("name"), false) v.set("on") self.assertEqual(self.root.globalgetvar("name"), true) + self.assertEqual(BooleanVar.initialize, BooleanVar.set) def test_invalid_value_domain(self): false = 0 if self.root.wantobjects() else "0" -- 2.47.3