diff -r e5f78085499e Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py Mon Aug 18 17:48:15 2014 +0300 +++ b/Lib/test/test_tcl.py Tue Aug 19 08:52:46 2014 +0300 @@ -7,7 +7,7 @@ _tkinter = support.import_module('_tkinter') # Make sure tkinter._fix runs to set up the environment -support.import_fresh_module('tkinter') +tkinter = support.import_fresh_module('tkinter') from tkinter import Tcl from _tkinter import TclError diff -r e5f78085499e Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py Mon Aug 18 17:48:15 2014 +0300 +++ b/Lib/tkinter/__init__.py Tue Aug 19 08:52:46 2014 +0300 @@ -112,6 +112,27 @@ try: _cnfmerge = _tkinter._cnfmerge except AttributeError: pass +def _splitdict(tk, v, cut_minus=True, conv=None): + """Break Tcl list in pairs, format it properly, then build the return + dict. If cut_minus is True, the supposed '-' prefixing options will + be removed. If conv is specified, it is used to convert values. + + Tcl list is expected to contain an even number of elements.""" + t = tk.splitlist(v) + if len(t) % 1: + raise RuntimeError('Tcl list is expected to contain an even number ' + 'of elements') + it = iter(tk.splitlist(v)) + dict = {} + for key, value in zip(it, it): + key = str(key) + if cut_minus and key[0] == '-': + key = key[1:] + if conv: + value = conv(value) + dict[key] = value + return dict + class Event: """Container for the properties of an event. @@ -1392,15 +1413,9 @@ else: options = self._options(cnf, kw) if not options: - res = self.tk.call('grid', - command, self._w, index) - words = self.tk.splitlist(res) - dict = {} - for i in range(0, len(words), 2): - key = words[i][1:] - value = words[i+1] - dict[key] = self._gridconvvalue(value) - return dict + return _splitdict(self.tk, + self.tk.call('grid', command, self._w, index), + conv=self._gridconvvalue) res = self.tk.call( ('grid', command, self._w, index) + options) @@ -1960,16 +1975,10 @@ def pack_info(self): """Return information about the packing options for this widget.""" - words = self.tk.splitlist( - self.tk.call('pack', 'info', self._w)) - dict = {} - for i in range(0, len(words), 2): - key = words[i][1:] - value = words[i+1] - if str(value)[:1] == '.': - value = self._nametowidget(value) - dict[key] = value - return dict + d = _splitdict(self.tk, self.tk.call('pack', 'info', self._w)) + if 'in' in d: + d['in'] = self.nametowidget(d['in']) + return d info = pack_info propagate = pack_propagate = Misc.pack_propagate slaves = pack_slaves = Misc.pack_slaves @@ -2011,16 +2020,10 @@ def place_info(self): """Return information about the placing options for this widget.""" - words = self.tk.splitlist( - self.tk.call('place', 'info', self._w)) - dict = {} - for i in range(0, len(words), 2): - key = words[i][1:] - value = words[i+1] - if str(value)[:1] == '.': - value = self._nametowidget(value) - dict[key] = value - return dict + d = _splitdict(self.tk, self.tk.call('place', 'info', self._w)) + if 'in' in d: + d['in'] = self.nametowidget(d['in']) + return d info = place_info slaves = place_slaves = Misc.place_slaves @@ -2060,16 +2063,10 @@ def grid_info(self): """Return information about the options for positioning this widget in a grid.""" - words = self.tk.splitlist( - self.tk.call('grid', 'info', self._w)) - dict = {} - for i in range(0, len(words), 2): - key = words[i][1:] - value = words[i+1] - if str(value)[:1] == '.': - value = self._nametowidget(value) - dict[key] = value - return dict + d = _splitdict(self.tk, self.tk.call('grid', 'info', self._w)) + if 'in' in d: + d['in'] = self.nametowidget(d['in']) + return d info = grid_info location = grid_location = Misc.grid_location propagate = grid_propagate = Misc.grid_propagate diff -r e5f78085499e Lib/tkinter/test/test_ttk/test_functions.py --- a/Lib/tkinter/test/test_ttk/test_functions.py Mon Aug 18 17:48:15 2014 +0300 +++ b/Lib/tkinter/test/test_ttk/test_functions.py Tue Aug 19 08:52:46 2014 +0300 @@ -324,28 +324,6 @@ "-opt {3 2m}") - def test_dict_from_tcltuple(self): - fakettuple = ('-a', '{1 2 3}', '-something', 'foo') - - self.assertEqual(ttk._dict_from_tcltuple(fakettuple, False), - {'-a': '{1 2 3}', '-something': 'foo'}) - - self.assertEqual(ttk._dict_from_tcltuple(fakettuple), - {'a': '{1 2 3}', 'something': 'foo'}) - - # passing a tuple with a single item should return an empty dict, - # since it tries to break the tuple by pairs. - self.assertFalse(ttk._dict_from_tcltuple(('single', ))) - - sspec = MockStateSpec('a', 'b') - self.assertEqual(ttk._dict_from_tcltuple(('-a', (sspec, 'val'))), - {'a': [('a', 'b', 'val')]}) - - self.assertEqual(ttk._dict_from_tcltuple((MockTclObj('-padding'), - [MockTclObj('1'), 2, MockTclObj('3m')])), - {'padding': [1, 2, '3m']}) - - def test_list_from_statespec(self): def test_it(sspec, value, res_value, states): self.assertEqual(ttk._list_from_statespec( diff -r e5f78085499e Lib/tkinter/ttk.py --- a/Lib/tkinter/ttk.py Mon Aug 18 17:48:15 2014 +0300 +++ b/Lib/tkinter/ttk.py Tue Aug 19 08:52:46 2014 +0300 @@ -26,7 +26,7 @@ "tclobjs_to_py", "setup_master"] import tkinter -from tkinter import _flatten, _join, _stringify +from tkinter import _flatten, _join, _stringify, _splitdict # Verify if Tk is new enough to not need the Tile package _REQUIRE_TILE = True if tkinter.TkVersion < 8.5 else False @@ -240,21 +240,6 @@ return '\n'.join(script) -def _dict_from_tcltuple(ttuple, cut_minus=True): - """Break tuple in pairs, format it properly, then build the return - dict. If cut_minus is True, the supposed '-' prefixing options will - be removed. - - ttuple is expected to contain an even number of elements.""" - opt_start = 1 if cut_minus else 0 - - retdict = {} - it = iter(ttuple) - for opt, val in zip(it, it): - retdict[str(opt)[opt_start:]] = val - - return tclobjs_to_py(retdict) - def _list_from_statespec(stuple): """Construct a list from the given statespec tuple according to the accepted statespec accepted by _format_mapdict.""" @@ -314,7 +299,7 @@ if len(options) % 2: # option specified without a value, return its value return res - return _dict_from_tcltuple(tk.splitlist(res)) + return _splitdict(tk, res, conv=_tclobj_to_py) def _convert_stringval(value): """Converts a value to, hopefully, a more appropriate Python object.""" @@ -334,20 +319,24 @@ x = int(x) return x +def _tclobj_to_py(val): + """Returns value converted from Tcl object to Python object.""" + if val and hasattr(val, '__len__') and not isinstance(val, str): + if getattr(val[0], 'typename', None) == 'StateSpec': + val = _list_from_statespec(val) + else: + val = list(map(_convert_stringval, val)) + + elif hasattr(val, 'typename'): # some other (single) Tcl object + val = _convert_stringval(val) + + return val + def tclobjs_to_py(adict): """Returns adict with its values converted from Tcl objects to Python objects.""" for opt, val in adict.items(): - if val and hasattr(val, '__len__') and not isinstance(val, str): - if getattr(val[0], 'typename', None) == 'StateSpec': - val = _list_from_statespec(val) - else: - val = list(map(_convert_stringval, val)) - - elif hasattr(val, 'typename'): # some other (single) Tcl object - val = _convert_stringval(val) - - adict[opt] = val + adict[opt] = _tclobj_to_py(val) return adict @@ -407,8 +396,9 @@ return _list_from_statespec(self.tk.splitlist( self.tk.call(self._name, "map", style, '-%s' % query_opt))) - return _dict_from_tcltuple(self.tk.splitlist( - self.tk.call(self._name, "map", style, *(_format_mapdict(kw))))) + return _splitdict(self.tk, + self.tk.call(self._name, "map", style, *_format_mapdict(kw)), + conv=_tclobj_to_py) def lookup(self, style, option, state=None, default=None): @@ -1431,7 +1421,8 @@ value of given column in given item to the specified value.""" res = self.tk.call(self._w, "set", item, column, value) if column is None and value is None: - return _dict_from_tcltuple(self.tk.splitlist(res), False) + return _splitdict(self.tk, res, + cut_minus=False, conv=_tclobj_to_py) else: return res