]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-151678: Add tests for tkinter.ttk methods (GH-151736)
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 19 Jun 2026 15:45:39 +0000 (18:45 +0300)
committerGitHub <noreply@github.com>
Fri, 19 Jun 2026 15:45:39 +0000 (18:45 +0300)
Cover previously-untested ttk methods:

* Progressbar.step, start and stop;
* Treeview.parent, next, prev, see and identify_element;
* Style.theme_settings;
* OptionMenu.set_menu.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lib/test/test_ttk/test_extensions.py
Lib/test/test_ttk/test_style.py
Lib/test/test_ttk/test_widgets.py

index 669a3e184eb771d7c66ea59b64d16b7925140b56..2765b226e271f9e14660d4730f95f3683c49864f 100644 (file)
@@ -281,6 +281,24 @@ class OptionMenuTest(AbstractTkTest, unittest.TestCase):
 
         optmenu.destroy()
 
+    def test_set_menu(self):
+        optmenu = ttk.OptionMenu(self.root, self.textvar, 'a', 'a', 'b', 'c')
+        menu = optmenu['menu']
+        self.assertEqual(menu.index('end'), 2)
+
+        # set_menu rebuilds the menu with new values and an optional default.
+        optmenu.set_menu('y', 'x', 'y', 'z')
+        self.assertEqual(self.textvar.get(), 'y')
+        self.assertEqual([menu.entrycget(i, 'label') for i in range(3)],
+                         ['x', 'y', 'z'])
+
+        # Without a default the variable is left unchanged.
+        optmenu.set_menu(None, 'p', 'q')
+        self.assertEqual(self.textvar.get(), 'y')
+        self.assertEqual([menu.entrycget(i, 'label') for i in range(2)],
+                         ['p', 'q'])
+        optmenu.destroy()
+
     def test_unique_radiobuttons(self):
         # check that radiobuttons are unique across instances (bpo25684)
         items = ('a', 'b', 'c')
index fdbaae1b644e4d2d260feb07c34635f5c80c9216..f85f76eb499278337b3456765bf644960ccd29d0 100644 (file)
@@ -124,6 +124,22 @@ class StyleTest(AbstractTkTest, unittest.TestCase):
 
         self.style.theme_use(curr_theme)
 
+    def test_theme_settings(self):
+        style = self.style
+        theme = style.theme_use()
+        style.theme_settings(theme, {
+            'Test.TLabel': {
+                'configure': {'foreground': 'red', 'background': 'blue'},
+                'map': {'foreground': [('active', 'green')]},
+            },
+        })
+        self.assertEqual(style.lookup('Test.TLabel', 'foreground'), 'red')
+        self.assertEqual(style.lookup('Test.TLabel', 'background'), 'blue')
+        self.assertEqual(style.map('Test.TLabel', 'foreground'),
+                         [('active', 'green')])
+        self.assertRaises(tkinter.TclError, style.theme_settings,
+                          'nonexistingname', {})
+
     def test_configure_custom_copy(self):
         style = self.style
 
index 8cce9aed9d514f4af5e7d12ca15b5395b6695ada..adcd736cd40b194b1f9be7e69e02eac90f0bd4d7 100644 (file)
@@ -973,6 +973,27 @@ class ProgressbarTest(AbstractWidgetTest, unittest.TestCase):
 
     test_configure_wraplength = requires_tk(8, 7)(StandardOptionsTests.test_configure_wraplength)
 
+    def test_step(self):
+        widget = self.create(maximum=100, mode='determinate')
+        self.assertEqual(float(widget['value']), 0.0)
+        widget.step()  # The default increment is 1.0.
+        self.assertEqual(float(widget['value']), 1.0)
+        widget.step(5)
+        self.assertEqual(float(widget['value']), 6.0)
+        widget.step(-2)
+        self.assertEqual(float(widget['value']), 4.0)
+
+    def test_start_stop(self):
+        widget = self.create(maximum=100, mode='determinate')
+        widget.pack()
+        widget.start()  # Schedule autoincrement; no exception.
+        widget.update()
+        widget.stop()   # Cancel it.
+        # After stopping, the value no longer changes.
+        value = float(widget['value'])
+        widget.update()
+        self.assertEqual(float(widget['value']), value)
+
 
 @unittest.skipIf(sys.platform == 'darwin',
                  'ttk.Scrollbar is special on MacOSX')
@@ -1639,6 +1660,50 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
         # in the tcl interpreter since tk requires an item.
         self.assertRaises(tkinter.TclError, self.tv.exists, None)
 
+    def test_parent(self):
+        a = self.tv.insert('', 'end')
+        b = self.tv.insert(a, 'end')
+        self.assertEqual(self.tv.parent(b), a)
+        self.assertEqual(self.tv.parent(a), '')
+        self.assertRaises(tkinter.TclError, self.tv.parent, 'nonexistent')
+
+    def test_next_prev(self):
+        a = self.tv.insert('', 'end')
+        b = self.tv.insert('', 'end')
+        c = self.tv.insert('', 'end')
+        self.assertEqual(self.tv.next(a), b)
+        self.assertEqual(self.tv.next(b), c)
+        self.assertEqual(self.tv.next(c), '')
+        self.assertEqual(self.tv.prev(c), b)
+        self.assertEqual(self.tv.prev(b), a)
+        self.assertEqual(self.tv.prev(a), '')
+        self.assertRaises(tkinter.TclError, self.tv.next, 'nonexistent')
+        self.assertRaises(tkinter.TclError, self.tv.prev, 'nonexistent')
+
+    def test_see(self):
+        a = self.tv.insert('', 'end')
+        b = self.tv.insert(a, 'end')
+        # see() opens all of the item's ancestors.
+        self.assertFalse(self.tv.tk.getboolean(self.tv.item(a, 'open')))
+        self.tv.see(b)
+        self.assertTrue(self.tv.tk.getboolean(self.tv.item(a, 'open')))
+        self.assertRaises(tkinter.TclError, self.tv.see, 'nonexistent')
+
+    def test_identify_element(self):
+        self.tv.pack()
+        self.tv.wait_visibility()
+        parent = self.tv.insert('', 'end', text='parent')
+        self.tv.insert(parent, 'end', text='child')
+        self.tv.update()
+        x, y, w, h = self.tv.bbox(parent)
+        # The Treeitem.indicator element is packed at the left of the row in
+        # the Item layout on every platform and theme.
+        element = self.tv.identify_element(x + 8, y + h // 2)
+        self.assertRegex(element, r'.*indicator\z')
+        # The empty string is returned outside the widget.
+        self.assertEqual(self.tv.identify_element(-1, -1), '')
+        self.assertRaises(tkinter.TclError, self.tv.identify_element, None, 5)
+
     def test_focus(self):
         # nothing is focused right now
         self.assertEqual(self.tv.focus(), '')