Commit a21acb5d authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #20072: Fixed multiple errors in tkinter with wantobjects is False.

* Misc.image_names(), Misc.image_types(), Wm.wm_colormapwindows(), and
  LabelFrame.panes() now always return a tuple.
* Fixed error of comparing str and int in tt.LabeledScale._adjust().
* ttk.Notebook.index() now always returns int.
* ttk.Notebook.tabs() now always returns a tuple.
* ttk.Entry.bbox() now always returns a tuple of ints.
* ttk.Entry.validate() now always correctly works.
* ttk.Combobox.current() now always returns int.
* ttk.Panedwindow.sashpos() now always returns int.
* ttk.Treeview.bbox() now always returns a tuple of ints.
* ttk.Treeview.get_children() now always returns a tuple.
* ttk.Treeview.exists() now always correctly works.
* ttk.Treeview.index() now always returns int.
* ttk.Treeview.tag_has() now always returns 0 or 1.
* And numerous other errors in methods which returns a tuple, list or dict.
* Fixed ttk tests for wantobjects is False.
parent 0455c3fd
...@@ -1459,11 +1459,11 @@ class Misc: ...@@ -1459,11 +1459,11 @@ class Misc:
def image_names(self): def image_names(self):
"""Return a list of all existing image names.""" """Return a list of all existing image names."""
return self.tk.call('image', 'names') return self.tk.splitlist(self.tk.call('image', 'names'))
def image_types(self): def image_types(self):
"""Return a list of all available image types (e.g. phote bitmap).""" """Return a list of all available image types (e.g. phote bitmap)."""
return self.tk.call('image', 'types') return self.tk.splitlist(self.tk.call('image', 'types'))
class CallWrapper: class CallWrapper:
...@@ -1577,7 +1577,11 @@ class Wm: ...@@ -1577,7 +1577,11 @@ class Wm:
if len(wlist) > 1: if len(wlist) > 1:
wlist = (wlist,) # Tk needs a list of windows here wlist = (wlist,) # Tk needs a list of windows here
args = ('wm', 'colormapwindows', self._w) + wlist args = ('wm', 'colormapwindows', self._w) + wlist
return [self._nametowidget(x) for x in self.tk.call(args)] if wlist:
self.tk.call(args)
else:
return [self._nametowidget(x)
for x in self.tk.splitlist(self.tk.call(args))]
colormapwindows = wm_colormapwindows colormapwindows = wm_colormapwindows
def wm_command(self, value=None): def wm_command(self, value=None):
"""Store VALUE in WM_COMMAND property. It is the command """Store VALUE in WM_COMMAND property. It is the command
...@@ -3472,8 +3476,11 @@ class BitmapImage(Image): ...@@ -3472,8 +3476,11 @@ class BitmapImage(Image):
Valid resource names: background, data, file, foreground, maskdata, maskfile.""" Valid resource names: background, data, file, foreground, maskdata, maskfile."""
Image.__init__(self, 'bitmap', name, cnf, master, **kw) Image.__init__(self, 'bitmap', name, cnf, master, **kw)
def image_names(): return _default_root.tk.call('image', 'names') def image_names():
def image_types(): return _default_root.tk.call('image', 'types') return _default_root.tk.splitlist(_default_root.tk.call('image', 'names'))
def image_types():
return _default_root.tk.splitlist(_default_root.tk.call('image', 'types'))
class Spinbox(Widget, XView): class Spinbox(Widget, XView):
...@@ -3842,7 +3849,7 @@ class PanedWindow(Widget): ...@@ -3842,7 +3849,7 @@ class PanedWindow(Widget):
def panes(self): def panes(self):
"""Returns an ordered list of the child panes.""" """Returns an ordered list of the child panes."""
return self.tk.call(self._w, 'panes') return self.tk.splitlist(self.tk.call(self._w, 'panes'))
###################################################################### ######################################################################
# Extensions: # Extensions:
......
...@@ -29,7 +29,10 @@ class LabeledScaleTest(unittest.TestCase): ...@@ -29,7 +29,10 @@ class LabeledScaleTest(unittest.TestCase):
name = myvar._name name = myvar._name
x = ttk.LabeledScale(variable=myvar) x = ttk.LabeledScale(variable=myvar)
x.destroy() x.destroy()
self.assertEqual(x.tk.globalgetvar(name), myvar.get()) if x.tk.wantobjects():
self.assertEqual(x.tk.globalgetvar(name), myvar.get())
else:
self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get())
del myvar del myvar
self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name) self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name)
...@@ -59,8 +62,10 @@ class LabeledScaleTest(unittest.TestCase): ...@@ -59,8 +62,10 @@ class LabeledScaleTest(unittest.TestCase):
x.destroy() x.destroy()
# variable initialization/passing # variable initialization/passing
passed_expected = ((2.5, 2), ('0', 0), (0, 0), (10, 10), passed_expected = (('0', 0), (0, 0), (10, 10),
(-1, -1), (sys.maxsize + 1, sys.maxsize + 1)) (-1, -1), (sys.maxsize + 1, sys.maxsize + 1))
if x.tk.wantobjects():
passed_expected += ((2.5, 2),)
for pair in passed_expected: for pair in passed_expected:
x = ttk.LabeledScale(from_=pair[0]) x = ttk.LabeledScale(from_=pair[0])
self.assertEqual(x.value, pair[1]) self.assertEqual(x.value, pair[1])
...@@ -123,7 +128,7 @@ class LabeledScaleTest(unittest.TestCase): ...@@ -123,7 +128,7 @@ class LabeledScaleTest(unittest.TestCase):
self.assertNotEqual(prev_xcoord, curr_xcoord) self.assertNotEqual(prev_xcoord, curr_xcoord)
# the label widget should have been repositioned too # the label widget should have been repositioned too
linfo_2 = lscale.label.place_info() linfo_2 = lscale.label.place_info()
self.assertEqual(lscale.label['text'], 0) self.assertEqual(lscale.label['text'], 0 if lscale.tk.wantobjects() else '0')
self.assertEqual(curr_xcoord, int(linfo_2['x'])) self.assertEqual(curr_xcoord, int(linfo_2['x']))
# change the range back # change the range back
lscale.scale.configure(from_=0, to=10) lscale.scale.configure(from_=0, to=10)
...@@ -145,15 +150,20 @@ class LabeledScaleTest(unittest.TestCase): ...@@ -145,15 +150,20 @@ class LabeledScaleTest(unittest.TestCase):
# The following update is needed since the test doesn't use mainloop, # The following update is needed since the test doesn't use mainloop,
# at the same time this shouldn't affect test outcome # at the same time this shouldn't affect test outcome
x.update() x.update()
self.assertEqual(x.label['text'], newval) self.assertEqual(x.label['text'],
newval if x.tk.wantobjects() else str(newval))
self.assertGreater(x.scale.coords()[0], curr_xcoord) self.assertGreater(x.scale.coords()[0], curr_xcoord)
self.assertEqual(x.scale.coords()[0], self.assertEqual(x.scale.coords()[0],
int(x.label.place_info()['x'])) int(x.label.place_info()['x']))
# value outside range # value outside range
x.value = x.scale['to'] + 1 # no changes shouldn't happen if x.tk.wantobjects():
conv = lambda x: x
else:
conv = int
x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen
x.update() x.update()
self.assertEqual(x.label['text'], newval) self.assertEqual(conv(x.label['text']), newval)
self.assertEqual(x.scale.coords()[0], self.assertEqual(x.scale.coords()[0],
int(x.label.place_info()['x'])) int(x.label.place_info()['x']))
......
...@@ -393,8 +393,10 @@ class InternalFunctionsTest(unittest.TestCase): ...@@ -393,8 +393,10 @@ class InternalFunctionsTest(unittest.TestCase):
('name', 'no_minus', 'value')) ('name', 'no_minus', 'value'))
self.assertRaises(ValueError, ttk._list_from_layouttuple, self.assertRaises(ValueError, ttk._list_from_layouttuple,
('something', '-children')) # no children ('something', '-children')) # no children
self.assertRaises(ValueError, ttk._list_from_layouttuple, import tkinter
('something', '-children', 'value')) # invalid children if not tkinter._default_root or tkinter._default_root.wantobjects():
self.assertRaises(ValueError, ttk._list_from_layouttuple,
('something', '-children', 'value')) # invalid children
def test_val_or_dict(self): def test_val_or_dict(self):
......
...@@ -25,7 +25,8 @@ class StyleTest(unittest.TestCase): ...@@ -25,7 +25,8 @@ class StyleTest(unittest.TestCase):
style = self.style style = self.style
style.map('TButton', background=[('active', 'background', 'blue')]) style.map('TButton', background=[('active', 'background', 'blue')])
self.assertEqual(style.map('TButton', 'background'), self.assertEqual(style.map('TButton', 'background'),
[('active', 'background', 'blue')]) [('active', 'background', 'blue')] if style.tk.wantobjects() else
[('active background', 'blue')])
self.assertIsInstance(style.map('TButton'), dict) self.assertIsInstance(style.map('TButton'), dict)
......
This diff is collapsed.
...@@ -293,6 +293,9 @@ def _list_from_layouttuple(ltuple): ...@@ -293,6 +293,9 @@ def _list_from_layouttuple(ltuple):
indx += 2 indx += 2
if opt == 'children': if opt == 'children':
if (tkinter._default_root and
not tkinter._default_root.wantobjects()):
val = tkinter._default_root.splitlist(val)
val = _list_from_layouttuple(val) val = _list_from_layouttuple(val)
opts[opt] = val opts[opt] = val
...@@ -313,6 +316,8 @@ def _val_or_dict(options, func, *args): ...@@ -313,6 +316,8 @@ def _val_or_dict(options, func, *args):
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:
res = tkinter._default_root.splitlist(res)
return _dict_from_tcltuple(res) return _dict_from_tcltuple(res)
def _convert_stringval(value): def _convert_stringval(value):
...@@ -325,6 +330,14 @@ def _convert_stringval(value): ...@@ -325,6 +330,14 @@ def _convert_stringval(value):
return value return value
def _to_number(x):
if isinstance(x, str):
if '.' in x:
x = float(x)
else:
x = int(x)
return x
def tclobjs_to_py(adict): def tclobjs_to_py(adict):
"""Returns adict with its values converted from Tcl objects to Python """Returns adict with its values converted from Tcl objects to Python
objects.""" objects."""
...@@ -395,8 +408,8 @@ class Style(object): ...@@ -395,8 +408,8 @@ class Style(object):
or something else of your preference. A statespec is compound of or something else of your preference. A statespec is compound of
one or more states and then a value.""" one or more states and then a value."""
if query_opt is not None: if query_opt is not None:
return _list_from_statespec( return _list_from_statespec(self.tk.splitlist(
self.tk.call(self._name, "map", style, '-%s' % query_opt)) self.tk.call(self._name, "map", style, '-%s' % query_opt)))
return _dict_from_tcltuple( return _dict_from_tcltuple(
self.tk.call(self._name, "map", style, *(_format_mapdict(kw)))) self.tk.call(self._name, "map", style, *(_format_mapdict(kw))))
...@@ -453,8 +466,8 @@ class Style(object): ...@@ -453,8 +466,8 @@ 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( return _list_from_layouttuple(self.tk.splitlist(
self.tk.call(self._name, "layout", style, lspec)) self.tk.call(self._name, "layout", style, lspec)))
def element_create(self, elementname, etype, *args, **kw): def element_create(self, elementname, etype, *args, **kw):
...@@ -466,12 +479,12 @@ class Style(object): ...@@ -466,12 +479,12 @@ class Style(object):
def element_names(self): def element_names(self):
"""Returns the list of elements defined in the current theme.""" """Returns the list of elements defined in the current theme."""
return self.tk.call(self._name, "element", "names") return self.tk.splitlist(self.tk.call(self._name, "element", "names"))
def element_options(self, elementname): def element_options(self, elementname):
"""Return the list of elementname's options.""" """Return the list of elementname's options."""
return self.tk.call(self._name, "element", "options", elementname) return self.tk.splitlist(self.tk.call(self._name, "element", "options", elementname))
def theme_create(self, themename, parent=None, settings=None): def theme_create(self, themename, parent=None, settings=None):
...@@ -505,7 +518,7 @@ class Style(object): ...@@ -505,7 +518,7 @@ class Style(object):
def theme_names(self): def theme_names(self):
"""Returns a list of all known themes.""" """Returns a list of all known themes."""
return self.tk.call(self._name, "theme", "names") return self.tk.splitlist(self.tk.call(self._name, "theme", "names"))
def theme_use(self, themename=None): def theme_use(self, themename=None):
...@@ -568,7 +581,8 @@ class Widget(tkinter.Widget): ...@@ -568,7 +581,8 @@ class Widget(tkinter.Widget):
matches statespec and False otherwise. If callback is specified, matches statespec and False otherwise. If callback is specified,
then it will be invoked with *args, **kw if the widget state then it will be invoked with *args, **kw if the widget state
matches statespec. statespec is expected to be a sequence.""" matches statespec. statespec is expected to be a sequence."""
ret = self.tk.call(self._w, "instate", ' '.join(statespec)) ret = self.tk.getboolean(
self.tk.call(self._w, "instate", ' '.join(statespec)))
if ret and callback: if ret and callback:
return callback(*args, **kw) return callback(*args, **kw)
...@@ -667,7 +681,7 @@ class Entry(Widget, tkinter.Entry): ...@@ -667,7 +681,7 @@ class Entry(Widget, tkinter.Entry):
def bbox(self, index): def bbox(self, index):
"""Return a tuple of (x, y, width, height) which describes the """Return a tuple of (x, y, width, height) which describes the
bounding box of the character given by index.""" bounding box of the character given by index."""
return self.tk.call(self._w, "bbox", index) return self._getints(self.tk.call(self._w, "bbox", index))
def identify(self, x, y): def identify(self, x, y):
...@@ -680,7 +694,7 @@ class Entry(Widget, tkinter.Entry): ...@@ -680,7 +694,7 @@ class Entry(Widget, tkinter.Entry):
"""Force revalidation, independent of the conditions specified """Force revalidation, independent of the conditions specified
by the validate option. Returns False if validation fails, True by the validate option. Returns False if validation fails, True
if it succeeds. Sets or clears the invalid state accordingly.""" if it succeeds. Sets or clears the invalid state accordingly."""
return bool(self.tk.call(self._w, "validate")) return bool(self.tk.getboolean(self.tk.call(self._w, "validate")))
class Combobox(Entry): class Combobox(Entry):
...@@ -707,6 +721,8 @@ class Combobox(Entry): ...@@ -707,6 +721,8 @@ class Combobox(Entry):
element at position newindex in the list of values. Otherwise, element at position newindex in the list of values. Otherwise,
returns the index of the current value in the list of values returns the index of the current value in the list of values
or -1 if the current value does not appear in the list.""" or -1 if the current value does not appear in the list."""
if newindex is None:
return self.tk.getint(self.tk.call(self._w, "current"))
return self.tk.call(self._w, "current", newindex) return self.tk.call(self._w, "current", newindex)
...@@ -861,7 +877,7 @@ class Notebook(Widget): ...@@ -861,7 +877,7 @@ class Notebook(Widget):
def index(self, tab_id): def index(self, tab_id):
"""Returns the numeric index of the tab specified by tab_id, or """Returns the numeric index of the tab specified by tab_id, or
the total number of tabs if tab_id is the string "end".""" the total number of tabs if tab_id is the string "end"."""
return self.tk.call(self._w, "index", tab_id) return self.tk.getint(self.tk.call(self._w, "index", tab_id))
def insert(self, pos, child, **kw): def insert(self, pos, child, **kw):
...@@ -896,7 +912,7 @@ class Notebook(Widget): ...@@ -896,7 +912,7 @@ class Notebook(Widget):
def tabs(self): def tabs(self):
"""Returns a list of windows managed by the notebook.""" """Returns a list of windows managed by the notebook."""
return self.tk.call(self._w, "tabs") or () return self.tk.splitlist(self.tk.call(self._w, "tabs") or ())
def enable_traversal(self): def enable_traversal(self):
...@@ -979,7 +995,7 @@ class Panedwindow(Widget, tkinter.PanedWindow): ...@@ -979,7 +995,7 @@ class Panedwindow(Widget, tkinter.PanedWindow):
constrained to be between 0 and the total size of the widget. constrained to be between 0 and the total size of the widget.
Returns the new position of sash number index.""" Returns the new position of sash number index."""
return self.tk.call(self._w, "sashpos", index, newpos) return self.tk.getint(self.tk.call(self._w, "sashpos", index, newpos))
PanedWindow = Panedwindow # tkinter name compatibility PanedWindow = Panedwindow # tkinter name compatibility
...@@ -1179,14 +1195,15 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): ...@@ -1179,14 +1195,15 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
If column is specified, returns the bounding box of that cell. If column is specified, returns the bounding box of that cell.
If the item is not visible (i.e., if it is a descendant of a If the item is not visible (i.e., if it is a descendant of a
closed item or is scrolled offscreen), returns an empty string.""" closed item or is scrolled offscreen), returns an empty string."""
return self.tk.call(self._w, "bbox", item, column) return self._getints(self.tk.call(self._w, "bbox", item, column)) or ''
def get_children(self, item=None): def get_children(self, item=None):
"""Returns a tuple of children belonging to item. """Returns a tuple of children belonging to item.
If item is not specified, returns root children.""" If item is not specified, returns root children."""
return self.tk.call(self._w, "children", item or '') or () return self.tk.splitlist(
self.tk.call(self._w, "children", item or '') or ())
def set_children(self, item, *newchildren): def set_children(self, item, *newchildren):
...@@ -1227,7 +1244,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): ...@@ -1227,7 +1244,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
def exists(self, item): def exists(self, item):
"""Returns True if the specified item is present in the tree, """Returns True if the specified item is present in the tree,
False otherwise.""" False otherwise."""
return bool(self.tk.call(self._w, "exists", item)) return bool(self.tk.getboolean(self.tk.call(self._w, "exists", item)))
def focus(self, item=None): def focus(self, item=None):
...@@ -1309,7 +1326,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): ...@@ -1309,7 +1326,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
def index(self, item): def index(self, item):
"""Returns the integer index of item within its parent's list """Returns the integer index of item within its parent's list
of children.""" of children."""
return self.tk.call(self._w, "index", item) return self.tk.getint(self.tk.call(self._w, "index", item))
def insert(self, parent, index, iid=None, **kw): def insert(self, parent, index, iid=None, **kw):
...@@ -1418,7 +1435,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): ...@@ -1418,7 +1435,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
value of given column in given item to the specified value.""" value of given column in given item to the specified value."""
res = self.tk.call(self._w, "set", item, column, value) res = self.tk.call(self._w, "set", item, column, value)
if column is None and value is None: if column is None and value is None:
return _dict_from_tcltuple(res, False) return _dict_from_tcltuple(self.tk.splitlist(res), False)
else: else:
return res return res
...@@ -1449,7 +1466,8 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): ...@@ -1449,7 +1466,8 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
all items which have the specified tag. all items which have the specified tag.
* Availability: Tk 8.6""" * Availability: Tk 8.6"""
return self.tk.call(self._w, "tag", "has", tagname, item) return self.tk.getboolean(
self.tk.call(self._w, "tag", "has", tagname, item))
# Extensions # Extensions
...@@ -1521,7 +1539,8 @@ class LabeledScale(Frame): ...@@ -1521,7 +1539,8 @@ class LabeledScale(Frame):
self.label.place_configure(x=x, y=y) self.label.place_configure(x=x, y=y)
from_, to = self.scale['from'], self.scale['to'] from_ = _to_number(self.scale['from'])
to = _to_number(self.scale['to'])
if to < from_: if to < from_:
from_, to = to, from_ from_, to = to, from_
newval = self._variable.get() newval = self._variable.get()
......
...@@ -31,6 +31,8 @@ Core and Builtins ...@@ -31,6 +31,8 @@ Core and Builtins
Library Library
------- -------
- Issue #20072: Fixed multiple errors in tkinter with wantobjects is False.
- Issue #20108: Avoid parameter name clash in inspect.getcallargs(). - Issue #20108: Avoid parameter name clash in inspect.getcallargs().
- Issue #12692: Backport the fix for ResourceWarning in test_urllib2net. This - Issue #12692: Backport the fix for ResourceWarning in test_urllib2net. This
......
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