Commit edb6428e authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #21402: tkinter.ttk now works when default root window is not set.

parent 49b2086a
...@@ -3,6 +3,17 @@ import sys ...@@ -3,6 +3,17 @@ import sys
import unittest import unittest
import ttk import ttk
class MockTkApp:
def splitlist(self, arg):
if isinstance(arg, tuple):
return arg
return arg.split(':')
def wantobjects(self):
return True
class MockTclObj(object): class MockTclObj(object):
typename = 'test' typename = 'test'
...@@ -353,20 +364,22 @@ class InternalFunctionsTest(unittest.TestCase): ...@@ -353,20 +364,22 @@ class InternalFunctionsTest(unittest.TestCase):
def test_list_from_layouttuple(self): def test_list_from_layouttuple(self):
tk = MockTkApp()
# empty layout tuple # empty layout tuple
self.assertFalse(ttk._list_from_layouttuple(())) self.assertFalse(ttk._list_from_layouttuple(tk, ()))
# shortest layout tuple # shortest layout tuple
self.assertEqual(ttk._list_from_layouttuple(('name', )), self.assertEqual(ttk._list_from_layouttuple(tk, ('name', )),
[('name', {})]) [('name', {})])
# not so interesting ltuple # not so interesting ltuple
sample_ltuple = ('name', '-option', 'value') sample_ltuple = ('name', '-option', 'value')
self.assertEqual(ttk._list_from_layouttuple(sample_ltuple), self.assertEqual(ttk._list_from_layouttuple(tk, sample_ltuple),
[('name', {'option': 'value'})]) [('name', {'option': 'value'})])
# empty children # empty children
self.assertEqual(ttk._list_from_layouttuple( self.assertEqual(ttk._list_from_layouttuple(tk,
('something', '-children', ())), ('something', '-children', ())),
[('something', {'children': []})] [('something', {'children': []})]
) )
...@@ -379,7 +392,7 @@ class InternalFunctionsTest(unittest.TestCase): ...@@ -379,7 +392,7 @@ class InternalFunctionsTest(unittest.TestCase):
) )
) )
) )
self.assertEqual(ttk._list_from_layouttuple(ltuple), self.assertEqual(ttk._list_from_layouttuple(tk, ltuple),
[('name', {'option': 'niceone', 'children': [('name', {'option': 'niceone', 'children':
[('otherone', {'otheropt': 'othervalue', 'children': [('otherone', {'otheropt': 'othervalue', 'children':
[('child', {})] [('child', {})]
...@@ -388,29 +401,37 @@ class InternalFunctionsTest(unittest.TestCase): ...@@ -388,29 +401,37 @@ class InternalFunctionsTest(unittest.TestCase):
) )
# bad tuples # bad tuples
self.assertRaises(ValueError, ttk._list_from_layouttuple, self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
('name', 'no_minus')) ('name', 'no_minus'))
self.assertRaises(ValueError, ttk._list_from_layouttuple, self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
('name', 'no_minus', 'value')) ('name', 'no_minus', 'value'))
self.assertRaises(ValueError, ttk._list_from_layouttuple, self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
('something', '-children')) # no children ('something', '-children')) # no children
import Tkinter self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
if not Tkinter._default_root or Tkinter._default_root.wantobjects(): ('something', '-children', 'value')) # invalid children
self.assertRaises(ValueError, ttk._list_from_layouttuple,
('something', '-children', 'value')) # invalid children
def test_val_or_dict(self): def test_val_or_dict(self):
def func(opt, val=None): def func(res, opt=None, val=None):
if opt is None:
return res
if val is None: if val is None:
return "test val" return "test val"
return (opt, val) return (opt, val)
options = {'test': None} tk = MockTkApp()
self.assertEqual(ttk._val_or_dict(options, func), "test val") tk.call = func
self.assertEqual(ttk._val_or_dict(tk, {}, '-test:3'),
{'test': '3'})
self.assertEqual(ttk._val_or_dict(tk, {}, ('-test', 3)),
{'test': 3})
self.assertEqual(ttk._val_or_dict(tk, {'test': None}, 'x:y'),
'test val')
options = {'test': 3} self.assertEqual(ttk._val_or_dict(tk, {'test': 3}, 'x:y'),
self.assertEqual(ttk._val_or_dict(options, func), options) {'test': 3})
def test_convert_stringval(self): def test_convert_stringval(self):
......
...@@ -274,7 +274,7 @@ def _list_from_statespec(stuple): ...@@ -274,7 +274,7 @@ def _list_from_statespec(stuple):
it = iter(nval) it = iter(nval)
return [_flatten(spec) for spec in zip(it, it)] return [_flatten(spec) for spec in zip(it, it)]
def _list_from_layouttuple(ltuple): def _list_from_layouttuple(tk, ltuple):
"""Construct a list from the tuple returned by ttk::layout, this is """Construct a list from the tuple returned by ttk::layout, this is
somewhat the reverse of _format_layoutlist.""" somewhat the reverse of _format_layoutlist."""
res = [] res = []
...@@ -295,17 +295,16 @@ def _list_from_layouttuple(ltuple): ...@@ -295,17 +295,16 @@ def _list_from_layouttuple(ltuple):
indx += 2 indx += 2
if opt == 'children': if opt == 'children':
if (Tkinter._default_root and if not tk.wantobjects():
not Tkinter._default_root.wantobjects()): val = tk.splitlist(val)
val = Tkinter._default_root.splitlist(val) val = _list_from_layouttuple(tk, val)
val = _list_from_layouttuple(val)
opts[opt] = val opts[opt] = val
return res return res
def _val_or_dict(options, func, *args): def _val_or_dict(tk, options, *args):
"""Format options then call func with args and options and return """Format options then call Tk command with args and options and return
the appropriate result. the appropriate result.
If no option is specified, a dict is returned. If a option is If no option is specified, a dict is returned. If a option is
...@@ -313,14 +312,12 @@ def _val_or_dict(options, func, *args): ...@@ -313,14 +312,12 @@ def _val_or_dict(options, func, *args):
Otherwise, the function just sets the passed options and the caller Otherwise, the function just sets the passed options and the caller
shouldn't be expecting a return value anyway.""" shouldn't be expecting a return value anyway."""
options = _format_optdict(options) options = _format_optdict(options)
res = func(*(args + options)) res = tk.call(*(args + options))
if len(options) % 2: # option specified without a value, return its value if len(options) % 2: # option specified without a value, return its value
return res return res
if Tkinter._default_root: return _dict_from_tcltuple(tk.splitlist(res))
res = Tkinter._default_root.splitlist(res)
return _dict_from_tcltuple(res)
def _convert_stringval(value): def _convert_stringval(value):
"""Converts a value to, hopefully, a more appropriate Python object.""" """Converts a value to, hopefully, a more appropriate Python object."""
...@@ -398,7 +395,7 @@ class Style(object): ...@@ -398,7 +395,7 @@ class Style(object):
a sequence identifying the value for that option.""" a sequence identifying the value for that option."""
if query_opt is not None: if query_opt is not None:
kw[query_opt] = None kw[query_opt] = None
return _val_or_dict(kw, self.tk.call, self._name, "configure", style) return _val_or_dict(self.tk, kw, self._name, "configure", style)
def map(self, style, query_opt=None, **kw): def map(self, style, query_opt=None, **kw):
...@@ -468,7 +465,7 @@ class Style(object): ...@@ -468,7 +465,7 @@ class Style(object):
lspec = "null" # could be any other word, but this may make sense lspec = "null" # could be any other word, but this may make sense
# when calling layout(style) later # when calling layout(style) later
return _list_from_layouttuple(self.tk.splitlist( return _list_from_layouttuple(self.tk, self.tk.splitlist(
self.tk.call(self._name, "layout", style, lspec))) self.tk.call(self._name, "layout", style, lspec)))
...@@ -909,7 +906,7 @@ class Notebook(Widget): ...@@ -909,7 +906,7 @@ class Notebook(Widget):
options to the corresponding values.""" options to the corresponding values."""
if option is not None: if option is not None:
kw[option] = None kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, "tab", tab_id) return _val_or_dict(self.tk, kw, self._w, "tab", tab_id)
def tabs(self): def tabs(self):
...@@ -986,7 +983,7 @@ class Panedwindow(Widget, Tkinter.PanedWindow): ...@@ -986,7 +983,7 @@ class Panedwindow(Widget, Tkinter.PanedWindow):
Otherwise, sets the options to the corresponding values.""" Otherwise, sets the options to the corresponding values."""
if option is not None: if option is not None:
kw[option] = None kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, "pane", pane) return _val_or_dict(self.tk, kw, self._w, "pane", pane)
def sashpos(self, index, newpos=None): def sashpos(self, index, newpos=None):
...@@ -1225,7 +1222,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView): ...@@ -1225,7 +1222,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView):
Otherwise, sets the options to the corresponding values.""" Otherwise, sets the options to the corresponding values."""
if option is not None: if option is not None:
kw[option] = None kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, "column", column) return _val_or_dict(self.tk, kw, self._w, "column", column)
def delete(self, *items): def delete(self, *items):
...@@ -1284,7 +1281,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView): ...@@ -1284,7 +1281,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView):
if option is not None: if option is not None:
kw[option] = None kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, 'heading', column) return _val_or_dict(self.tk, kw, self._w, 'heading', column)
def identify(self, component, x, y): def identify(self, component, x, y):
...@@ -1363,7 +1360,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView): ...@@ -1363,7 +1360,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView):
values as given by kw.""" values as given by kw."""
if option is not None: if option is not None:
kw[option] = None kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, "item", item) return _val_or_dict(self.tk, kw, self._w, "item", item)
def move(self, item, parent, index): def move(self, item, parent, index):
...@@ -1458,7 +1455,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView): ...@@ -1458,7 +1455,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView):
values for the given tagname.""" values for the given tagname."""
if option is not None: if option is not None:
kw[option] = None kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, "tag", "configure", return _val_or_dict(self.tk, kw, self._w, "tag", "configure",
tagname) tagname)
......
...@@ -18,6 +18,8 @@ Core and Builtins ...@@ -18,6 +18,8 @@ Core and Builtins
Library Library
------- -------
- Issue #21402: Tkinter.ttk now works when default root window is not set.
- Issue #10203: sqlite3.Row now truly supports sequence protocol. In particulr - Issue #10203: sqlite3.Row now truly supports sequence protocol. In particulr
it supports reverse() and negative indices. Original patch by Claudiu Popa. it supports reverse() and negative indices. Original patch by Claudiu Popa.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment