Skip to content

Commit 2faae25

Browse files
serhiy-storchakaclaude
authored andcommitted
gh-151678: Add tests for tkinter.ttk methods (GH-151736)
Cover previously-untested ttk methods: * Progressbar.step, start and stop; * Treeview.parent, next, prev, see and identify_element; * Style.theme_settings; * OptionMenu.set_menu. (cherry picked from commit 7d4a0aa) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent cc7043d commit 2faae25

3 files changed

Lines changed: 99 additions & 0 deletions

File tree

Lib/test/test_ttk/test_extensions.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,24 @@ def cb_test(item):
281281

282282
optmenu.destroy()
283283

284+
def test_set_menu(self):
285+
optmenu = ttk.OptionMenu(self.root, self.textvar, 'a', 'a', 'b', 'c')
286+
menu = optmenu['menu']
287+
self.assertEqual(menu.index('end'), 2)
288+
289+
# set_menu rebuilds the menu with new values and an optional default.
290+
optmenu.set_menu('y', 'x', 'y', 'z')
291+
self.assertEqual(self.textvar.get(), 'y')
292+
self.assertEqual([menu.entrycget(i, 'label') for i in range(3)],
293+
['x', 'y', 'z'])
294+
295+
# Without a default the variable is left unchanged.
296+
optmenu.set_menu(None, 'p', 'q')
297+
self.assertEqual(self.textvar.get(), 'y')
298+
self.assertEqual([menu.entrycget(i, 'label') for i in range(2)],
299+
['p', 'q'])
300+
optmenu.destroy()
301+
284302
def test_unique_radiobuttons(self):
285303
# check that radiobuttons are unique across instances (bpo25684)
286304
items = ('a', 'b', 'c')

Lib/test/test_ttk/test_style.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,22 @@ def test_theme_use(self):
124124

125125
self.style.theme_use(curr_theme)
126126

127+
def test_theme_settings(self):
128+
style = self.style
129+
theme = style.theme_use()
130+
style.theme_settings(theme, {
131+
'Test.TLabel': {
132+
'configure': {'foreground': 'red', 'background': 'blue'},
133+
'map': {'foreground': [('active', 'green')]},
134+
},
135+
})
136+
self.assertEqual(style.lookup('Test.TLabel', 'foreground'), 'red')
137+
self.assertEqual(style.lookup('Test.TLabel', 'background'), 'blue')
138+
self.assertEqual(style.map('Test.TLabel', 'foreground'),
139+
[('active', 'green')])
140+
self.assertRaises(tkinter.TclError, style.theme_settings,
141+
'nonexistingname', {})
142+
127143
def test_configure_custom_copy(self):
128144
style = self.style
129145

Lib/test/test_ttk/test_widgets.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,27 @@ def test_configure_value(self):
950950

951951
test_configure_wraplength = requires_tk(8, 7)(StandardOptionsTests.test_configure_wraplength)
952952

953+
def test_step(self):
954+
widget = self.create(maximum=100, mode='determinate')
955+
self.assertEqual(float(widget['value']), 0.0)
956+
widget.step() # The default increment is 1.0.
957+
self.assertEqual(float(widget['value']), 1.0)
958+
widget.step(5)
959+
self.assertEqual(float(widget['value']), 6.0)
960+
widget.step(-2)
961+
self.assertEqual(float(widget['value']), 4.0)
962+
963+
def test_start_stop(self):
964+
widget = self.create(maximum=100, mode='determinate')
965+
widget.pack()
966+
widget.start() # Schedule autoincrement; no exception.
967+
widget.update()
968+
widget.stop() # Cancel it.
969+
# After stopping, the value no longer changes.
970+
value = float(widget['value'])
971+
widget.update()
972+
self.assertEqual(float(widget['value']), value)
973+
953974

954975
@unittest.skipIf(sys.platform == 'darwin',
955976
'ttk.Scrollbar is special on MacOSX')
@@ -1604,6 +1625,50 @@ def test_exists(self):
16041625
# in the tcl interpreter since tk requires an item.
16051626
self.assertRaises(tkinter.TclError, self.tv.exists, None)
16061627

1628+
def test_parent(self):
1629+
a = self.tv.insert('', 'end')
1630+
b = self.tv.insert(a, 'end')
1631+
self.assertEqual(self.tv.parent(b), a)
1632+
self.assertEqual(self.tv.parent(a), '')
1633+
self.assertRaises(tkinter.TclError, self.tv.parent, 'nonexistent')
1634+
1635+
def test_next_prev(self):
1636+
a = self.tv.insert('', 'end')
1637+
b = self.tv.insert('', 'end')
1638+
c = self.tv.insert('', 'end')
1639+
self.assertEqual(self.tv.next(a), b)
1640+
self.assertEqual(self.tv.next(b), c)
1641+
self.assertEqual(self.tv.next(c), '')
1642+
self.assertEqual(self.tv.prev(c), b)
1643+
self.assertEqual(self.tv.prev(b), a)
1644+
self.assertEqual(self.tv.prev(a), '')
1645+
self.assertRaises(tkinter.TclError, self.tv.next, 'nonexistent')
1646+
self.assertRaises(tkinter.TclError, self.tv.prev, 'nonexistent')
1647+
1648+
def test_see(self):
1649+
a = self.tv.insert('', 'end')
1650+
b = self.tv.insert(a, 'end')
1651+
# see() opens all of the item's ancestors.
1652+
self.assertFalse(self.tv.tk.getboolean(self.tv.item(a, 'open')))
1653+
self.tv.see(b)
1654+
self.assertTrue(self.tv.tk.getboolean(self.tv.item(a, 'open')))
1655+
self.assertRaises(tkinter.TclError, self.tv.see, 'nonexistent')
1656+
1657+
def test_identify_element(self):
1658+
self.tv.pack()
1659+
self.tv.wait_visibility()
1660+
parent = self.tv.insert('', 'end', text='parent')
1661+
self.tv.insert(parent, 'end', text='child')
1662+
self.tv.update()
1663+
x, y, w, h = self.tv.bbox(parent)
1664+
# The Treeitem.indicator element is packed at the left of the row in
1665+
# the Item layout on every platform and theme.
1666+
element = self.tv.identify_element(x + 8, y + h // 2)
1667+
self.assertRegex(element, r'.*indicator\z')
1668+
# The empty string is returned outside the widget.
1669+
self.assertEqual(self.tv.identify_element(-1, -1), '')
1670+
self.assertRaises(tkinter.TclError, self.tv.identify_element, None, 5)
1671+
16071672
def test_focus(self):
16081673
# nothing is focused right now
16091674
self.assertEqual(self.tv.focus(), '')

0 commit comments

Comments
 (0)