[Python-checkins] cpython (2.7): Issue #22226: Added private function _splitdict() in the Tkinter module.

serhiy.storchaka python-checkins at python.org
Sat Sep 6 21:52:09 CEST 2014


http://hg.python.org/cpython/rev/7b0fdc1e917a
changeset: 92372:7b0fdc1e917a
branch: 2.7
parent: 92369:d8c6b15a2ae3
user: Serhiy Storchaka <storchaka at gmail.com>
date: Sat Sep 06 22:47:02 2014 +0300
summary:
 Issue #22226: Added private function _splitdict() in the Tkinter module.
First letter no longer is stripped from the "status" key in
the result of Treeview.heading().
files:
 Lib/lib-tk/Tkinter.py | 78 +++++-----
 Lib/lib-tk/test/test_ttk/test_functions.py | 27 +--
 Lib/lib-tk/ttk.py | 62 +++----
 Lib/test/test_tcl.py | 39 +++++
 Misc/NEWS | 3 +
 5 files changed, 116 insertions(+), 93 deletions(-)
diff --git a/Lib/lib-tk/Tkinter.py b/Lib/lib-tk/Tkinter.py
--- a/Lib/lib-tk/Tkinter.py
+++ b/Lib/lib-tk/Tkinter.py
@@ -123,6 +123,29 @@
 try: _cnfmerge = _tkinter._cnfmerge
 except AttributeError: pass
 
+def _splitdict(tk, v, cut_minus=True, conv=None):
+ """Return a properly formatted dict built from Tcl list pairs.
+
+ If cut_minus is True, the supposed '-' prefix will be removed from
+ keys. 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) % 2:
+ raise RuntimeError('Tcl list representing a dict is expected '
+ 'to contain an even number of elements')
+ it = iter(t)
+ 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.
 
@@ -1390,15 +1413,10 @@
 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)
@@ -1921,16 +1939,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
@@ -1972,16 +1984,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
 
@@ -2021,16 +2027,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 --git a/Lib/lib-tk/test/test_ttk/test_functions.py b/Lib/lib-tk/test/test_ttk/test_functions.py
--- a/Lib/lib-tk/test/test_ttk/test_functions.py
+++ b/Lib/lib-tk/test/test_ttk/test_functions.py
@@ -324,26 +324,13 @@
 "-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_tclobj_to_py(self):
+ self.assertEqual(
+ ttk._tclobj_to_py((MockStateSpec('a', 'b'), 'val')),
+ [('a', 'b', 'val')])
+ self.assertEqual(
+ ttk._tclobj_to_py([MockTclObj('1'), 2, MockTclObj('3m')]),
+ [1, 2, '3m'])
 
 
 def test_list_from_statespec(self):
diff --git a/Lib/lib-tk/ttk.py b/Lib/lib-tk/ttk.py
--- a/Lib/lib-tk/ttk.py
+++ b/Lib/lib-tk/ttk.py
@@ -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
@@ -242,21 +242,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."""
@@ -316,7 +301,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."""
@@ -336,20 +321,24 @@
 x = int(x)
 return x
 
+def _tclobj_to_py(val):
+ """Return value converted from Tcl object to Python object."""
+ if val and hasattr(val, '__len__') and not isinstance(val, basestring):
+ if getattr(val[0], 'typename', None) == 'StateSpec':
+ val = _list_from_statespec(val)
+ else:
+ val = 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.iteritems():
- if val and hasattr(val, '__len__') and not isinstance(val, basestring):
- if getattr(val[0], 'typename', None) == 'StateSpec':
- val = _list_from_statespec(val)
- else:
- val = map(_convert_stringval, val)
-
- elif hasattr(val, 'typename'): # some other (single) Tcl object
- val = _convert_stringval(val)
-
- adict[opt] = val
+ for opt, val in adict.items():
+ adict[opt] = _tclobj_to_py(val)
 
 return adict
 
@@ -409,8 +398,10 @@
 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):
@@ -1427,13 +1418,16 @@
 
 
 def set(self, item, column=None, value=None):
- """With one argument, returns a dictionary of column/value pairs
- for the specified item. With two arguments, returns the current
- value of the specified column. With three arguments, sets the
+ """Query or set the value of given item.
+
+ With one argument, return a dictionary of column/value pairs
+ for the specified item. With two arguments, return the current
+ value of the specified column. With three arguments, set the
 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
 
diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py
--- a/Lib/test/test_tcl.py
+++ b/Lib/test/test_tcl.py
@@ -7,6 +7,9 @@
 # Skip this test if the _tkinter module wasn't built.
 _tkinter = test_support.import_module('_tkinter')
 
+# Make sure tkinter._fix runs to set up the environment
+tkinter = test_support.import_fresh_module('Tkinter')
+
 from Tkinter import Tcl
 from _tkinter import TclError
 
@@ -565,6 +568,42 @@
 for arg, res in testcases:
 self.assertEqual(split(arg), res)
 
+ def test_splitdict(self):
+ splitdict = tkinter._splitdict
+ tcl = self.interp.tk
+
+ arg = '-a {1 2 3} -something foo status {}'
+ self.assertEqual(splitdict(tcl, arg, False),
+ {'-a': '1 2 3', '-something': 'foo', 'status': ''})
+ self.assertEqual(splitdict(tcl, arg),
+ {'a': '1 2 3', 'something': 'foo', 'status': ''})
+
+ arg = ('-a', (1, 2, 3), '-something', 'foo', 'status', '{}')
+ self.assertEqual(splitdict(tcl, arg, False),
+ {'-a': (1, 2, 3), '-something': 'foo', 'status': '{}'})
+ self.assertEqual(splitdict(tcl, arg),
+ {'a': (1, 2, 3), 'something': 'foo', 'status': '{}'})
+
+ self.assertRaises(RuntimeError, splitdict, tcl, '-a b -c ')
+ self.assertRaises(RuntimeError, splitdict, tcl, ('-a', 'b', '-c'))
+
+ arg = tcl.call('list',
+ '-a', (1, 2, 3), '-something', 'foo', 'status', ())
+ self.assertEqual(splitdict(tcl, arg),
+ {'a': (1, 2, 3) if self.wantobjects else '1 2 3',
+ 'something': 'foo', 'status': ''})
+
+ if tcl_version >= (8, 5):
+ arg = tcl.call('dict', 'create',
+ '-a', (1, 2, 3), '-something', 'foo', 'status', ())
+ if not self.wantobjects or get_tk_patchlevel() < (8, 5, 5):
+ # Before 8.5.5 dicts were converted to lists through string
+ expected = {'a': '1 2 3', 'something': 'foo', 'status': ''}
+ else:
+ expected = {'a': (1, 2, 3), 'something': 'foo', 'status': ''}
+ self.assertEqual(splitdict(tcl, arg), expected)
+
+
 character_size = 4 if sys.maxunicode > 0xFFFF else 2
 
 class BigmemTclTest(unittest.TestCase):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -22,6 +22,9 @@
 Library
 -------
 
+- Issue #22226: First letter no longer is stripped from the "status" key in
+ the result of Treeview.heading().
+
 - Issue #22051: turtledemo no longer reloads examples to re-run them.
 Initialization of variables and gui setup should be done in main(),
 which is called each time a demo is run, but not on import.
-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /