From b49eff25b7af3398b44f1b5e8b29748948c22b69 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 28 May 2014 18:38:27 +0300 Subject: [PATCH] Issue #21402: tkinter.ttk now works when default root window is not set. --- Lib/tkinter/test/test_ttk/test_functions.py | 56 ++++++++++++++------- Lib/tkinter/ttk.py | 35 ++++++------- Misc/NEWS | 2 + 3 files changed, 57 insertions(+), 36 deletions(-) diff --git a/Lib/tkinter/test/test_ttk/test_functions.py b/Lib/tkinter/test/test_ttk/test_functions.py index 1986e660264..8dd87533ff5 100644 --- a/Lib/tkinter/test/test_ttk/test_functions.py +++ b/Lib/tkinter/test/test_ttk/test_functions.py @@ -1,7 +1,19 @@ # -*- encoding: utf-8 -*- import unittest +import tkinter from tkinter 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): typename = 'test' @@ -352,20 +364,22 @@ class InternalFunctionsTest(unittest.TestCase): def test_list_from_layouttuple(self): + tk = MockTkApp() + # empty layout tuple - self.assertFalse(ttk._list_from_layouttuple(())) + self.assertFalse(ttk._list_from_layouttuple(tk, ())) # shortest layout tuple - self.assertEqual(ttk._list_from_layouttuple(('name', )), + self.assertEqual(ttk._list_from_layouttuple(tk, ('name', )), [('name', {})]) # not so interesting ltuple 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'})]) # empty children - self.assertEqual(ttk._list_from_layouttuple( + self.assertEqual(ttk._list_from_layouttuple(tk, ('something', '-children', ())), [('something', {'children': []})] ) @@ -378,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': [('otherone', {'otheropt': 'othervalue', 'children': [('child', {})] @@ -387,29 +401,37 @@ class InternalFunctionsTest(unittest.TestCase): ) # bad tuples - self.assertRaises(ValueError, ttk._list_from_layouttuple, + self.assertRaises(ValueError, ttk._list_from_layouttuple, tk, ('name', 'no_minus')) - self.assertRaises(ValueError, ttk._list_from_layouttuple, + self.assertRaises(ValueError, ttk._list_from_layouttuple, tk, ('name', 'no_minus', 'value')) - self.assertRaises(ValueError, ttk._list_from_layouttuple, + self.assertRaises(ValueError, ttk._list_from_layouttuple, tk, ('something', '-children')) # no children - import tkinter - if not tkinter._default_root or tkinter._default_root.wantobjects(): - self.assertRaises(ValueError, ttk._list_from_layouttuple, - ('something', '-children', 'value')) # invalid children + self.assertRaises(ValueError, ttk._list_from_layouttuple, tk, + ('something', '-children', 'value')) # invalid children 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: return "test val" return (opt, val) - options = {'test': None} - self.assertEqual(ttk._val_or_dict(options, func), "test val") + tk = MockTkApp() + tk.call = func - options = {'test': 3} - self.assertEqual(ttk._val_or_dict(options, func), options) + 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') + + self.assertEqual(ttk._val_or_dict(tk, {'test': 3}, 'x:y'), + {'test': 3}) def test_convert_stringval(self): diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index ca9027374d5..81f909c9845 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -272,7 +272,7 @@ def _list_from_statespec(stuple): it = iter(nval) 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 somewhat the reverse of _format_layoutlist.""" res = [] @@ -293,17 +293,16 @@ def _list_from_layouttuple(ltuple): indx += 2 if opt == 'children': - if (tkinter._default_root and - not tkinter._default_root.wantobjects()): - val = tkinter._default_root.splitlist(val) - val = _list_from_layouttuple(val) + if not tk.wantobjects(): + val = tk.splitlist(val) + val = _list_from_layouttuple(tk, val) opts[opt] = val return res -def _val_or_dict(options, func, *args): - """Format options then call func with args and options and return +def _val_or_dict(tk, options, *args): + """Format options then call Tk command with args and options and return the appropriate result. If no option is specified, a dict is returned. If a option is @@ -311,14 +310,12 @@ def _val_or_dict(options, func, *args): Otherwise, the function just sets the passed options and the caller shouldn't be expecting a return value anyway.""" 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 return res - if tkinter._default_root: - res = tkinter._default_root.splitlist(res) - return _dict_from_tcltuple(res) + return _dict_from_tcltuple(tk.splitlist(res)) def _convert_stringval(value): """Converts a value to, hopefully, a more appropriate Python object.""" @@ -396,7 +393,7 @@ class Style(object): a sequence identifying the value for that option.""" if query_opt is not 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): @@ -466,7 +463,7 @@ class Style(object): lspec = "null" # could be any other word, but this may make sense # 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))) @@ -907,7 +904,7 @@ class Notebook(Widget): options to the corresponding values.""" if option is not 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): @@ -984,7 +981,7 @@ class Panedwindow(Widget, tkinter.PanedWindow): Otherwise, sets the options to the corresponding values.""" if option is not 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): @@ -1223,7 +1220,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): Otherwise, sets the options to the corresponding values.""" if option is not 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): @@ -1282,7 +1279,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): if option is not 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): @@ -1361,7 +1358,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): values as given by kw.""" if option is not 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): @@ -1456,7 +1453,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): values for the given tagname.""" if option is not 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) diff --git a/Misc/NEWS b/Misc/NEWS index f82d3c565c5..51210308ac3 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,8 @@ Core and Builtins 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 it supports reverse() and negative indices. Original patch by Claudiu Popa.