summaryrefslogtreecommitdiffstats
path: root/Lib/tkinter
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/tkinter')
-rw-r--r--Lib/tkinter/__init__.py216
-rw-r--r--Lib/tkinter/_fix.py4
-rw-r--r--Lib/tkinter/colorchooser.py4
-rw-r--r--Lib/tkinter/filedialog.py4
-rw-r--r--Lib/tkinter/font.py18
-rw-r--r--Lib/tkinter/test/runtktests.py1
-rw-r--r--Lib/tkinter/test/support.py124
-rw-r--r--Lib/tkinter/test/test_tkinter/test_font.py18
-rw-r--r--Lib/tkinter/test/test_tkinter/test_geometry_managers.py900
-rw-r--r--Lib/tkinter/test/test_tkinter/test_images.py327
-rw-r--r--Lib/tkinter/test/test_tkinter/test_misc.py7
-rw-r--r--Lib/tkinter/test/test_tkinter/test_text.py9
-rw-r--r--Lib/tkinter/test/test_tkinter/test_variables.py40
-rw-r--r--Lib/tkinter/test/test_tkinter/test_widgets.py310
-rw-r--r--Lib/tkinter/test/test_ttk/test_extensions.py105
-rw-r--r--Lib/tkinter/test/test_ttk/test_functions.py81
-rw-r--r--Lib/tkinter/test/test_ttk/test_style.py10
-rw-r--r--Lib/tkinter/test/test_ttk/test_widgets.py177
-rw-r--r--Lib/tkinter/test/widget_tests.py54
-rw-r--r--Lib/tkinter/tix.py2
-rw-r--r--Lib/tkinter/ttk.py106
21 files changed, 1977 insertions, 540 deletions
diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py
index b9e5d2e..21a560b 100644
--- a/Lib/tkinter/__init__.py
+++ b/Lib/tkinter/__init__.py
@@ -35,8 +35,6 @@ if sys.platform == "win32":
# Attempt to configure Tcl/Tk without requiring PATH
from tkinter import _fix
-import warnings
-
import _tkinter # If this fails your Python may not be configured for Tk
TclError = _tkinter.TclError
from tkinter.constants import *
@@ -114,6 +112,29 @@ def _cnfmerge(cnfs):
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.
@@ -193,6 +214,7 @@ class Variable:
that constrain the type of the value returned from get()."""
_default = ""
_tk = None
+ _tclCommands = None
def __init__(self, master=None, value=None, name=None):
"""Construct a variable
@@ -211,7 +233,7 @@ class Variable:
global _varnum
if not master:
master = _default_root
- self._master = master
+ self._root = master._root()
self._tk = master.tk
if name:
self._name = name
@@ -224,9 +246,15 @@ class Variable:
self.initialize(self._default)
def __del__(self):
"""Unset the variable in Tcl."""
- if (self._tk is not None and
- self._tk.getboolean(self._tk.call("info", "exists", self._name))):
+ if self._tk is None:
+ return
+ if self._tk.getboolean(self._tk.call("info", "exists", self._name)):
self._tk.globalunsetvar(self._name)
+ if self._tclCommands is not None:
+ for name in self._tclCommands:
+ #print '- Tkinter: deleted command', name
+ self._tk.deletecommand(name)
+ self._tclCommands = None
def __str__(self):
"""Return the name of the variable in Tcl."""
return self._name
@@ -246,7 +274,20 @@ class Variable:
Return the name of the callback.
"""
- cbname = self._master._register(callback)
+ f = CallWrapper(callback, None, self).__call__
+ cbname = repr(id(f))
+ try:
+ callback = callback.__func__
+ except AttributeError:
+ pass
+ try:
+ cbname = cbname + callback.__name__
+ except AttributeError:
+ pass
+ self._tk.createcommand(cbname, f)
+ if self._tclCommands is None:
+ self._tclCommands = []
+ self._tclCommands.append(cbname)
self._tk.call("trace", "variable", self._name, mode, cbname)
return cbname
trace = trace_variable
@@ -257,7 +298,11 @@ class Variable:
CBNAME is the name of the callback returned from trace_variable or trace.
"""
self._tk.call("trace", "vdelete", self._name, mode, cbname)
- self._master.deletecommand(cbname)
+ self._tk.deletecommand(cbname)
+ try:
+ self._tclCommands.remove(cbname)
+ except ValueError:
+ pass
def trace_vinfo(self):
"""Return all trace callback information."""
return [self._tk.split(x) for x in self._tk.splitlist(
@@ -346,6 +391,11 @@ class BooleanVar(Variable):
"""
Variable.__init__(self, master, value, name)
+ def set(self, value):
+ """Set the variable to VALUE."""
+ return self._tk.globalsetvar(self._name, self._tk.getboolean(value))
+ initialize = set
+
def get(self):
"""Return the value of the variable as a bool."""
try:
@@ -423,7 +473,10 @@ class Misc:
+ _flatten(args) + _flatten(list(kw.items())))
def tk_menuBar(self, *args):
"""Do not use. Needed in Tk 3.6 and earlier."""
- pass # obsolete since Tk 4.0
+ # obsolete since Tk 4.0
+ import warnings
+ warnings.warn('tk_menuBar() does nothing and will be removed in 3.6',
+ DeprecationWarning, stacklevel=2)
def wait_variable(self, name='PY_VAR'):
"""Wait until the variable is modified.
@@ -537,6 +590,7 @@ class Misc:
self.deletecommand(name)
except TclError:
pass
+ callit.__name__ = func.__name__
name = self._register(callit)
return self.tk.call('after', ms, name)
def after_idle(self, func, *args):
@@ -1365,15 +1419,10 @@ class Misc:
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)
@@ -1685,7 +1734,7 @@ class Wm:
On X, the images are arranged into the _NET_WM_ICON X property,
which most modern window managers support. An icon specified by
- wm_iconbitmap may exist simuultaneously.
+ wm_iconbitmap may exist simultaneously.
On Macintosh, this currently does nothing."""
if default:
@@ -1873,9 +1922,12 @@ class Tk(Misc, Wm):
if os.path.isfile(base_py):
exec(open(base_py).read(), dir)
def report_callback_exception(self, exc, val, tb):
- """Internal function. It reports exception on sys.stderr."""
+ """Report callback exception on sys.stderr.
+
+ Applications may want to override this internal function, and
+ should when sys.stderr is None."""
import traceback
- sys.stderr.write("Exception in Tkinter callback\n")
+ print("Exception in Tkinter callback", file=sys.stderr)
sys.last_type = exc
sys.last_value = val
sys.last_traceback = tb
@@ -1933,16 +1985,10 @@ class Pack:
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
@@ -1984,16 +2030,10 @@ class Place:
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
@@ -2033,16 +2073,10 @@ class Grid:
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
@@ -2199,45 +2233,6 @@ class Button(Widget):
"""
return self.tk.call(self._w, 'invoke')
-
-# Indices:
-# XXX I don't like these -- take them away
-def AtEnd():
- warnings.warn("tkinter.AtEnd will be removed in 3.4",
- DeprecationWarning, stacklevel=2)
- return 'end'
-
-
-def AtInsert(*args):
- warnings.warn("tkinter.AtInsert will be removed in 3.4",
- DeprecationWarning, stacklevel=2)
- s = 'insert'
- for a in args:
- if a: s = s + (' ' + a)
- return s
-
-
-def AtSelFirst():
- warnings.warn("tkinter.AtSelFirst will be removed in 3.4",
- DeprecationWarning, stacklevel=2)
- return 'sel.first'
-
-
-def AtSelLast():
- warnings.warn("tkinter.AtSelLast will be removed in 3.4",
- DeprecationWarning, stacklevel=2)
- return 'sel.last'
-
-
-def At(x, y=None):
- warnings.warn("tkinter.At will be removed in 3.4",
- DeprecationWarning, stacklevel=2)
- if y is None:
- return '@%r' % (x,)
- else:
- return '@%r,%r' % (x, y)
-
-
class Canvas(Widget, XView, YView):
"""Canvas widget to display graphical elements like lines or text."""
def __init__(self, master=None, cnf={}, **kw):
@@ -2627,22 +2622,19 @@ class Listbox(Widget, XView, YView):
def activate(self, index):
"""Activate item identified by INDEX."""
self.tk.call(self._w, 'activate', index)
- def bbox(self, *args):
+ def bbox(self, index):
"""Return a tuple of X1,Y1,X2,Y2 coordinates for a rectangle
- which encloses the item identified by index in ARGS."""
- return self._getints(
- self.tk.call((self._w, 'bbox') + args)) or None
+ which encloses the item identified by the given index."""
+ return self._getints(self.tk.call(self._w, 'bbox', index)) or None
def curselection(self):
- """Return list of indices of currently selected item."""
- # XXX Ought to apply self._getints()...
- return self.tk.splitlist(self.tk.call(
- self._w, 'curselection'))
+ """Return the indices of currently selected item."""
+ return self._getints(self.tk.call(self._w, 'curselection')) or ()
def delete(self, first, last=None):
- """Delete items from FIRST to LAST (not included)."""
+ """Delete items from FIRST to LAST (included)."""
self.tk.call(self._w, 'delete', first, last)
def get(self, first, last=None):
- """Get list of items from FIRST to LAST (not included)."""
- if last:
+ """Get list of items from FIRST to LAST (included)."""
+ if last is not None:
return self.tk.splitlist(self.tk.call(
self._w, 'get', first, last))
else:
@@ -2675,7 +2667,7 @@ class Listbox(Widget, XView, YView):
self.tk.call(self._w, 'selection', 'anchor', index)
select_anchor = selection_anchor
def selection_clear(self, first, last=None):
- """Clear the selection from FIRST to LAST (not included)."""
+ """Clear the selection from FIRST to LAST (included)."""
self.tk.call(self._w,
'selection', 'clear', first, last)
select_clear = selection_clear
@@ -2685,7 +2677,7 @@ class Listbox(Widget, XView, YView):
self._w, 'selection', 'includes', index))
select_includes = selection_includes
def selection_set(self, first, last=None):
- """Set the selection from FIRST to LAST (not included) without
+ """Set the selection from FIRST to LAST (included) without
changing the currently selected elements."""
self.tk.call(self._w, 'selection', 'set', first, last)
select_set = selection_set
@@ -2718,7 +2710,11 @@ class Menu(Widget):
selectcolor, takefocus, tearoff, tearoffcommand, title, type."""
Widget.__init__(self, master, 'menu', cnf, kw)
def tk_bindForTraversal(self):
- pass # obsolete since Tk 4.0
+ # obsolete since Tk 4.0
+ import warnings
+ warnings.warn('tk_bindForTraversal() does nothing and '
+ 'will be removed in 3.6',
+ DeprecationWarning, stacklevel=2)
def tk_mbPost(self):
self.tk.call('tk_mbPost', self._w)
def tk_mbUnpost(self):
@@ -2968,11 +2964,11 @@ class Text(Widget, XView, YView):
"""
Widget.__init__(self, master, 'text', cnf, kw)
- def bbox(self, *args):
+ def bbox(self, index):
"""Return a tuple of (x,y,width,height) which gives the bounding
- box of the visible part of the character at the index in ARGS."""
+ box of the visible part of the character at the given index."""
return self._getints(
- self.tk.call((self._w, 'bbox') + args)) or None
+ self.tk.call(self._w, 'bbox', index)) or None
def tk_textSelectTo(self, index):
self.tk.call('tk_textSelectTo', self._w, index)
def tk_textBackspace(self):
@@ -3364,7 +3360,7 @@ class Image:
master = _default_root
if not master:
raise RuntimeError('Too early to create image')
- self.tk = master.tk
+ self.tk = getattr(master, 'tk', master)
if not name:
Image._last_id += 1
name = "pyimage%r" % (Image._last_id,) # tk itself would use image<x>
@@ -3435,20 +3431,20 @@ class PhotoImage(Image):
# XXX copy -from, -to, ...?
def copy(self):
"""Return a new PhotoImage with the same image as this widget."""
- destImage = PhotoImage()
+ destImage = PhotoImage(master=self.tk)
self.tk.call(destImage, 'copy', self.name)
return destImage
def zoom(self,x,y=''):
"""Return a new PhotoImage with the same image as this widget
but zoom it with X and Y."""
- destImage = PhotoImage()
+ destImage = PhotoImage(master=self.tk)
if y=='': y=x
self.tk.call(destImage, 'copy', self.name, '-zoom',x,y)
return destImage
def subsample(self,x,y=''):
"""Return a new PhotoImage based on the same image as this widget
but use only every Xth or Yth pixel."""
- destImage = PhotoImage()
+ destImage = PhotoImage(master=self.tk)
if y=='': y=x
self.tk.call(destImage, 'copy', self.name, '-subsample',x,y)
return destImage
diff --git a/Lib/tkinter/_fix.py b/Lib/tkinter/_fix.py
index 5f32d25..fa88734 100644
--- a/Lib/tkinter/_fix.py
+++ b/Lib/tkinter/_fix.py
@@ -48,8 +48,8 @@ else:
prefix = os.path.join(sys.base_prefix,"tcl")
if not os.path.exists(prefix):
- # devdir/../tcltk/lib
- prefix = os.path.join(sys.base_prefix, os.path.pardir, "tcltk", "lib")
+ # devdir/externals/tcltk/lib
+ prefix = os.path.join(sys.base_prefix, "externals", "tcltk", "lib")
prefix = os.path.abspath(prefix)
# if this does not exist, no further search is needed
if os.path.exists(prefix):
diff --git a/Lib/tkinter/colorchooser.py b/Lib/tkinter/colorchooser.py
index 6027067..9dc9671 100644
--- a/Lib/tkinter/colorchooser.py
+++ b/Lib/tkinter/colorchooser.py
@@ -1,4 +1,4 @@
-# tk common colour chooser dialogue
+# tk common color chooser dialogue
#
# this module provides an interface to the native color dialogue
# available in Tk 4.2 and newer.
@@ -11,7 +11,7 @@
#
# options (all have default values):
#
-# - initialcolor: colour to mark as selected when dialog is displayed
+# - initialcolor: color to mark as selected when dialog is displayed
# (given as an RGB triplet or a Tk color string)
#
# - parent: which window to place the dialog on top of
diff --git a/Lib/tkinter/filedialog.py b/Lib/tkinter/filedialog.py
index 3ffb252..a71afb2 100644
--- a/Lib/tkinter/filedialog.py
+++ b/Lib/tkinter/filedialog.py
@@ -166,7 +166,7 @@ class FileDialog:
dir, pat = self.get_filter()
try:
names = os.listdir(dir)
- except os.error:
+ except OSError:
self.master.bell()
return
self.directory = dir
@@ -209,7 +209,7 @@ class FileDialog:
if not os.path.isabs(dir):
try:
pwd = os.getcwd()
- except os.error:
+ except OSError:
pwd = None
if pwd:
dir = os.path.join(pwd, dir)
diff --git a/Lib/tkinter/font.py b/Lib/tkinter/font.py
index 4929241..b966732 100644
--- a/Lib/tkinter/font.py
+++ b/Lib/tkinter/font.py
@@ -69,9 +69,10 @@ class Font:
**options):
if not root:
root = tkinter._default_root
+ tk = getattr(root, 'tk', root)
if font:
# get actual settings corresponding to the given font
- font = root.tk.splitlist(root.tk.call("font", "actual", font))
+ font = tk.splitlist(tk.call("font", "actual", font))
else:
font = self._set(options)
if not name:
@@ -81,20 +82,19 @@ class Font:
if exists:
self.delete_font = False
# confirm font exists
- if self.name not in root.tk.call("font", "names"):
+ if self.name not in tk.splitlist(tk.call("font", "names")):
raise tkinter._tkinter.TclError(
"named font %s does not already exist" % (self.name,))
# if font config info supplied, apply it
if font:
- root.tk.call("font", "configure", self.name, *font)
+ tk.call("font", "configure", self.name, *font)
else:
# create new font (raises TclError if the font exists)
- root.tk.call("font", "create", self.name, *font)
+ tk.call("font", "create", self.name, *font)
self.delete_font = True
- # backlinks!
- self._root = root
- self._split = root.tk.splitlist
- self._call = root.tk.call
+ self._tk = tk
+ self._split = tk.splitlist
+ self._call = tk.call
def __str__(self):
return self.name
@@ -119,7 +119,7 @@ class Font:
def copy(self):
"Return a distinct copy of the current font"
- return Font(self._root, **self.actual())
+ return Font(self._tk, **self.actual())
def actual(self, option=None, displayof=None):
"Return actual font attributes"
diff --git a/Lib/tkinter/test/runtktests.py b/Lib/tkinter/test/runtktests.py
index e21eca4..ccb3755 100644
--- a/Lib/tkinter/test/runtktests.py
+++ b/Lib/tkinter/test/runtktests.py
@@ -68,5 +68,4 @@ def get_tests(text=True, gui=True, packages=None):
yield test
if __name__ == "__main__":
- test.support.use_resources = ['gui']
test.support.run_unittest(*get_tests())
diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py
index fcd9ffc..52df104 100644
--- a/Lib/tkinter/test/support.py
+++ b/Lib/tkinter/test/support.py
@@ -1,74 +1,45 @@
-import sys
+import re
import tkinter
import unittest
-_tk_unavailable = None
-
-def check_tk_availability():
- """Check that Tk is installed and available."""
- global _tk_unavailable
-
- if _tk_unavailable is None:
- _tk_unavailable = False
- if sys.platform == 'darwin':
- # The Aqua Tk implementations on OS X can abort the process if
- # being called in an environment where a window server connection
- # cannot be made, for instance when invoked by a buildbot or ssh
- # process not running under the same user id as the current console
- # user. To avoid that, raise an exception if the window manager
- # connection is not available.
- from ctypes import cdll, c_int, pointer, Structure
- from ctypes.util import find_library
-
- app_services = cdll.LoadLibrary(find_library("ApplicationServices"))
-
- if app_services.CGMainDisplayID() == 0:
- _tk_unavailable = "cannot run without OS X window manager"
- else:
- class ProcessSerialNumber(Structure):
- _fields_ = [("highLongOfPSN", c_int),
- ("lowLongOfPSN", c_int)]
- psn = ProcessSerialNumber()
- psn_p = pointer(psn)
- if ( (app_services.GetCurrentProcess(psn_p) < 0) or
- (app_services.SetFrontProcess(psn_p) < 0) ):
- _tk_unavailable = "cannot run without OS X gui process"
- else: # not OS X
- import tkinter
- try:
- tkinter.Button()
- except tkinter.TclError as msg:
- # assuming tk is not available
- _tk_unavailable = "tk not available: %s" % msg
-
- if _tk_unavailable:
- raise unittest.SkipTest(_tk_unavailable)
- return
-
-def get_tk_root():
- check_tk_availability() # raise exception if tk unavailable
- try:
- root = tkinter._default_root
- except AttributeError:
- # it is possible to disable default root in Tkinter, although
- # I haven't seen people doing it (but apparently someone did it
- # here).
- root = None
-
- if root is None:
- # create a new master only if there isn't one already
- root = tkinter.Tk()
-
- return root
-
-def root_deiconify():
- root = get_tk_root()
- root.deiconify()
-
-def root_withdraw():
- root = get_tk_root()
- root.withdraw()
-
+class AbstractTkTest:
+
+ @classmethod
+ def setUpClass(cls):
+ cls._old_support_default_root = tkinter._support_default_root
+ destroy_default_root()
+ tkinter.NoDefaultRoot()
+ cls.root = tkinter.Tk()
+ cls.wantobjects = cls.root.wantobjects()
+ # De-maximize main window.
+ # Some window managers can maximize new windows.
+ cls.root.wm_state('normal')
+ try:
+ cls.root.wm_attributes('-zoomed', False)
+ except tkinter.TclError:
+ pass
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.root.update_idletasks()
+ cls.root.destroy()
+ cls.root = None
+ tkinter._default_root = None
+ tkinter._support_default_root = cls._old_support_default_root
+
+ def setUp(self):
+ self.root.deiconify()
+
+ def tearDown(self):
+ for w in self.root.winfo_children():
+ w.destroy()
+ self.root.withdraw()
+
+def destroy_default_root():
+ if getattr(tkinter, '_default_root', None):
+ tkinter._default_root.update_idletasks()
+ tkinter._default_root.destroy()
+ tkinter._default_root = None
def simulate_mouse_click(widget, x, y):
"""Generate proper events to click at the x, y position (tries to act
@@ -91,14 +62,15 @@ def get_tk_patchlevel():
global _tk_patchlevel
if _tk_patchlevel is None:
tcl = tkinter.Tcl()
- patchlevel = []
- for x in tcl.call('info', 'patchlevel').split('.'):
- try:
- x = int(x, 10)
- except ValueError:
- x = -1
- patchlevel.append(x)
- _tk_patchlevel = tuple(patchlevel)
+ patchlevel = tcl.call('info', 'patchlevel')
+ m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', patchlevel)
+ major, minor, releaselevel, serial = m.groups()
+ major, minor, serial = int(major), int(minor), int(serial)
+ releaselevel = {'a': 'alpha', 'b': 'beta', '.': 'final'}[releaselevel]
+ if releaselevel == 'final':
+ _tk_patchlevel = major, minor, serial, releaselevel, 0
+ else:
+ _tk_patchlevel = major, minor, 0, releaselevel, serial
return _tk_patchlevel
units = {
diff --git a/Lib/tkinter/test/test_tkinter/test_font.py b/Lib/tkinter/test/test_tkinter/test_font.py
index dfd630b..09c963e 100644
--- a/Lib/tkinter/test/test_tkinter/test_font.py
+++ b/Lib/tkinter/test/test_tkinter/test_font.py
@@ -2,26 +2,20 @@ import unittest
import tkinter
from tkinter import font
from test.support import requires, run_unittest
-import tkinter.test.support as support
+from tkinter.test.support import AbstractTkTest
requires('gui')
-class FontTest(unittest.TestCase):
-
- def setUp(self):
- support.root_deiconify()
-
- def tearDown(self):
- support.root_withdraw()
+class FontTest(AbstractTkTest, unittest.TestCase):
def test_font_eq(self):
fontname = "TkDefaultFont"
try:
- f = font.Font(name=fontname, exists=True)
+ f = font.Font(root=self.root, name=fontname, exists=True)
except tkinter._tkinter.TclError:
- f = font.Font(name=fontname, exists=False)
- font1 = font.nametofont(fontname)
- font2 = font.nametofont(fontname)
+ f = font.Font(root=self.root, name=fontname, exists=False)
+ font1 = font.Font(root=self.root, name=fontname, exists=True)
+ font2 = font.Font(root=self.root, name=fontname, exists=True)
self.assertIsNot(font1, font2)
self.assertEqual(font1, font2)
self.assertNotEqual(font1, font1.copy())
diff --git a/Lib/tkinter/test/test_tkinter/test_geometry_managers.py b/Lib/tkinter/test/test_tkinter/test_geometry_managers.py
new file mode 100644
index 0000000..e42b1be
--- /dev/null
+++ b/Lib/tkinter/test/test_tkinter/test_geometry_managers.py
@@ -0,0 +1,900 @@
+import unittest
+import re
+import tkinter
+from tkinter import TclError
+from test.support import requires
+
+from tkinter.test.support import pixels_conv, tcl_version, requires_tcl
+from tkinter.test.widget_tests import AbstractWidgetTest
+
+requires('gui')
+
+
+class PackTest(AbstractWidgetTest, unittest.TestCase):
+
+ def create2(self):
+ pack = tkinter.Toplevel(self.root, name='pack')
+ pack.wm_geometry('300x200+0+0')
+ pack.wm_minsize(1, 1)
+ a = tkinter.Frame(pack, name='a', width=20, height=40, bg='red')
+ b = tkinter.Frame(pack, name='b', width=50, height=30, bg='blue')
+ c = tkinter.Frame(pack, name='c', width=80, height=80, bg='green')
+ d = tkinter.Frame(pack, name='d', width=40, height=30, bg='yellow')
+ return pack, a, b, c, d
+
+ def test_pack_configure_after(self):
+ pack, a, b, c, d = self.create2()
+ with self.assertRaisesRegex(TclError, 'window "%s" isn\'t packed' % b):
+ a.pack_configure(after=b)
+ with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'):
+ a.pack_configure(after='.foo')
+ a.pack_configure(side='top')
+ b.pack_configure(side='top')
+ c.pack_configure(side='top')
+ d.pack_configure(side='top')
+ self.assertEqual(pack.pack_slaves(), [a, b, c, d])
+ a.pack_configure(after=b)
+ self.assertEqual(pack.pack_slaves(), [b, a, c, d])
+ a.pack_configure(after=a)
+ self.assertEqual(pack.pack_slaves(), [b, a, c, d])
+
+ def test_pack_configure_anchor(self):
+ pack, a, b, c, d = self.create2()
+ def check(anchor, geom):
+ a.pack_configure(side='top', ipadx=5, padx=10, ipady=15, pady=20,
+ expand=True, anchor=anchor)
+ self.root.update()
+ self.assertEqual(a.winfo_geometry(), geom)
+ check('n', '30x70+135+20')
+ check('ne', '30x70+260+20')
+ check('e', '30x70+260+65')
+ check('se', '30x70+260+110')
+ check('s', '30x70+135+110')
+ check('sw', '30x70+10+110')
+ check('w', '30x70+10+65')
+ check('nw', '30x70+10+20')
+ check('center', '30x70+135+65')
+
+ def test_pack_configure_before(self):
+ pack, a, b, c, d = self.create2()
+ with self.assertRaisesRegex(TclError, 'window "%s" isn\'t packed' % b):
+ a.pack_configure(before=b)
+ with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'):
+ a.pack_configure(before='.foo')
+ a.pack_configure(side='top')
+ b.pack_configure(side='top')
+ c.pack_configure(side='top')
+ d.pack_configure(side='top')
+ self.assertEqual(pack.pack_slaves(), [a, b, c, d])
+ a.pack_configure(before=d)
+ self.assertEqual(pack.pack_slaves(), [b, c, a, d])
+ a.pack_configure(before=a)
+ self.assertEqual(pack.pack_slaves(), [b, c, a, d])
+
+ def test_pack_configure_expand(self):
+ pack, a, b, c, d = self.create2()
+ def check(*geoms):
+ self.root.update()
+ self.assertEqual(a.winfo_geometry(), geoms[0])
+ self.assertEqual(b.winfo_geometry(), geoms[1])
+ self.assertEqual(c.winfo_geometry(), geoms[2])
+ self.assertEqual(d.winfo_geometry(), geoms[3])
+ a.pack_configure(side='left')
+ b.pack_configure(side='top')
+ c.pack_configure(side='right')
+ d.pack_configure(side='bottom')
+ check('20x40+0+80', '50x30+135+0', '80x80+220+75', '40x30+100+170')
+ a.pack_configure(side='left', expand='yes')
+ b.pack_configure(side='top', expand='on')
+ c.pack_configure(side='right', expand=True)
+ d.pack_configure(side='bottom', expand=1)
+ check('20x40+40+80', '50x30+175+35', '80x80+180+110', '40x30+100+135')
+ a.pack_configure(side='left', expand='yes', fill='both')
+ b.pack_configure(side='top', expand='on', fill='both')
+ c.pack_configure(side='right', expand=True, fill='both')
+ d.pack_configure(side='bottom', expand=1, fill='both')
+ check('100x200+0+0', '200x100+100+0', '160x100+140+100', '40x100+100+100')
+
+ def test_pack_configure_in(self):
+ pack, a, b, c, d = self.create2()
+ a.pack_configure(side='top')
+ b.pack_configure(side='top')
+ c.pack_configure(side='top')
+ d.pack_configure(side='top')
+ a.pack_configure(in_=pack)
+ self.assertEqual(pack.pack_slaves(), [b, c, d, a])
+ a.pack_configure(in_=c)
+ self.assertEqual(pack.pack_slaves(), [b, c, d])
+ self.assertEqual(c.pack_slaves(), [a])
+ with self.assertRaisesRegex(TclError,
+ 'can\'t pack %s inside itself' % (a,)):
+ a.pack_configure(in_=a)
+ with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'):
+ a.pack_configure(in_='.foo')
+
+ def test_pack_configure_padx_ipadx_fill(self):
+ pack, a, b, c, d = self.create2()
+ def check(geom1, geom2, **kwargs):
+ a.pack_forget()
+ b.pack_forget()
+ a.pack_configure(**kwargs)
+ b.pack_configure(expand=True, fill='both')
+ self.root.update()
+ self.assertEqual(a.winfo_geometry(), geom1)
+ self.assertEqual(b.winfo_geometry(), geom2)
+ check('20x40+260+80', '240x200+0+0', side='right', padx=20)
+ check('20x40+250+80', '240x200+0+0', side='right', padx=(10, 30))
+ check('60x40+240+80', '240x200+0+0', side='right', ipadx=20)
+ check('30x40+260+80', '250x200+0+0', side='right', ipadx=5, padx=10)
+ check('20x40+260+80', '240x200+0+0', side='right', padx=20, fill='x')
+ check('20x40+249+80', '240x200+0+0',
+ side='right', padx=(9, 31), fill='x')
+ check('60x40+240+80', '240x200+0+0', side='right', ipadx=20, fill='x')
+ check('30x40+260+80', '250x200+0+0',
+ side='right', ipadx=5, padx=10, fill='x')
+ check('30x40+255+80', '250x200+0+0',
+ side='right', ipadx=5, padx=(5, 15), fill='x')
+ check('20x40+140+0', '300x160+0+40', side='top', padx=20)
+ check('20x40+120+0', '300x160+0+40', side='top', padx=(0, 40))
+ check('60x40+120+0', '300x160+0+40', side='top', ipadx=20)
+ check('30x40+135+0', '300x160+0+40', side='top', ipadx=5, padx=10)
+ check('30x40+130+0', '300x160+0+40', side='top', ipadx=5, padx=(5, 15))
+ check('260x40+20+0', '300x160+0+40', side='top', padx=20, fill='x')
+ check('260x40+25+0', '300x160+0+40',
+ side='top', padx=(25, 15), fill='x')
+ check('300x40+0+0', '300x160+0+40', side='top', ipadx=20, fill='x')
+ check('280x40+10+0', '300x160+0+40',
+ side='top', ipadx=5, padx=10, fill='x')
+ check('280x40+5+0', '300x160+0+40',
+ side='top', ipadx=5, padx=(5, 15), fill='x')
+ a.pack_configure(padx='1c')
+ self.assertEqual(a.pack_info()['padx'],
+ self._str(pack.winfo_pixels('1c')))
+ a.pack_configure(ipadx='1c')
+ self.assertEqual(a.pack_info()['ipadx'],
+ self._str(pack.winfo_pixels('1c')))
+
+ def test_pack_configure_pady_ipady_fill(self):
+ pack, a, b, c, d = self.create2()
+ def check(geom1, geom2, **kwargs):
+ a.pack_forget()
+ b.pack_forget()
+ a.pack_configure(**kwargs)
+ b.pack_configure(expand=True, fill='both')
+ self.root.update()
+ self.assertEqual(a.winfo_geometry(), geom1)
+ self.assertEqual(b.winfo_geometry(), geom2)
+ check('20x40+280+80', '280x200+0+0', side='right', pady=20)
+ check('20x40+280+70', '280x200+0+0', side='right', pady=(10, 30))
+ check('20x80+280+60', '280x200+0+0', side='right', ipady=20)
+ check('20x50+280+75', '280x200+0+0', side='right', ipady=5, pady=10)
+ check('20x40+280+80', '280x200+0+0', side='right', pady=20, fill='x')
+ check('20x40+280+69', '280x200+0+0',
+ side='right', pady=(9, 31), fill='x')
+ check('20x80+280+60', '280x200+0+0', side='right', ipady=20, fill='x')
+ check('20x50+280+75', '280x200+0+0',
+ side='right', ipady=5, pady=10, fill='x')
+ check('20x50+280+70', '280x200+0+0',
+ side='right', ipady=5, pady=(5, 15), fill='x')
+ check('20x40+140+20', '300x120+0+80', side='top', pady=20)
+ check('20x40+140+0', '300x120+0+80', side='top', pady=(0, 40))
+ check('20x80+140+0', '300x120+0+80', side='top', ipady=20)
+ check('20x50+140+10', '300x130+0+70', side='top', ipady=5, pady=10)
+ check('20x50+140+5', '300x130+0+70', side='top', ipady=5, pady=(5, 15))
+ check('300x40+0+20', '300x120+0+80', side='top', pady=20, fill='x')
+ check('300x40+0+25', '300x120+0+80',
+ side='top', pady=(25, 15), fill='x')
+ check('300x80+0+0', '300x120+0+80', side='top', ipady=20, fill='x')
+ check('300x50+0+10', '300x130+0+70',
+ side='top', ipady=5, pady=10, fill='x')
+ check('300x50+0+5', '300x130+0+70',
+ side='top', ipady=5, pady=(5, 15), fill='x')
+ a.pack_configure(pady='1c')
+ self.assertEqual(a.pack_info()['pady'],
+ self._str(pack.winfo_pixels('1c')))
+ a.pack_configure(ipady='1c')
+ self.assertEqual(a.pack_info()['ipady'],
+ self._str(pack.winfo_pixels('1c')))
+
+ def test_pack_configure_side(self):
+ pack, a, b, c, d = self.create2()
+ def check(side, geom1, geom2):
+ a.pack_configure(side=side)
+ self.assertEqual(a.pack_info()['side'], side)
+ b.pack_configure(expand=True, fill='both')
+ self.root.update()
+ self.assertEqual(a.winfo_geometry(), geom1)
+ self.assertEqual(b.winfo_geometry(), geom2)
+ check('top', '20x40+140+0', '300x160+0+40')
+ check('bottom', '20x40+140+160', '300x160+0+0')
+ check('left', '20x40+0+80', '280x200+20+0')
+ check('right', '20x40+280+80', '280x200+0+0')
+
+ def test_pack_forget(self):
+ pack, a, b, c, d = self.create2()
+ a.pack_configure()
+ b.pack_configure()
+ c.pack_configure()
+ self.assertEqual(pack.pack_slaves(), [a, b, c])
+ b.pack_forget()
+ self.assertEqual(pack.pack_slaves(), [a, c])
+ b.pack_forget()
+ self.assertEqual(pack.pack_slaves(), [a, c])
+ d.pack_forget()
+
+ def test_pack_info(self):
+ pack, a, b, c, d = self.create2()
+ with self.assertRaisesRegex(TclError, 'window "%s" isn\'t packed' % a):
+ a.pack_info()
+ a.pack_configure()
+ b.pack_configure(side='right', in_=a, anchor='s', expand=True, fill='x',
+ ipadx=5, padx=10, ipady=2, pady=(5, 15))
+ info = a.pack_info()
+ self.assertIsInstance(info, dict)
+ self.assertEqual(info['anchor'], 'center')
+ self.assertEqual(info['expand'], self._str(0))
+ self.assertEqual(info['fill'], 'none')
+ self.assertEqual(info['in'], pack)
+ self.assertEqual(info['ipadx'], self._str(0))
+ self.assertEqual(info['ipady'], self._str(0))
+ self.assertEqual(info['padx'], self._str(0))
+ self.assertEqual(info['pady'], self._str(0))
+ self.assertEqual(info['side'], 'top')
+ info = b.pack_info()
+ self.assertIsInstance(info, dict)
+ self.assertEqual(info['anchor'], 's')
+ self.assertEqual(info['expand'], self._str(1))
+ self.assertEqual(info['fill'], 'x')
+ self.assertEqual(info['in'], a)
+ self.assertEqual(info['ipadx'], self._str(5))
+ self.assertEqual(info['ipady'], self._str(2))
+ self.assertEqual(info['padx'], self._str(10))
+ self.assertEqual(info['pady'], self._str((5, 15)))
+ self.assertEqual(info['side'], 'right')
+
+ def test_pack_propagate(self):
+ pack, a, b, c, d = self.create2()
+ pack.configure(width=300, height=200)
+ a.pack_configure()
+ pack.pack_propagate(False)
+ self.root.update()
+ self.assertEqual(pack.winfo_reqwidth(), 300)
+ self.assertEqual(pack.winfo_reqheight(), 200)
+ pack.pack_propagate(True)
+ self.root.update()
+ self.assertEqual(pack.winfo_reqwidth(), 20)
+ self.assertEqual(pack.winfo_reqheight(), 40)
+
+ def test_pack_slaves(self):
+ pack, a, b, c, d = self.create2()
+ self.assertEqual(pack.pack_slaves(), [])
+ a.pack_configure()
+ self.assertEqual(pack.pack_slaves(), [a])
+ b.pack_configure()
+ self.assertEqual(pack.pack_slaves(), [a, b])
+
+
+class PlaceTest(AbstractWidgetTest, unittest.TestCase):
+
+ def create2(self):
+ t = tkinter.Toplevel(self.root, width=300, height=200, bd=0)
+ t.wm_geometry('300x200+0+0')
+ f = tkinter.Frame(t, width=154, height=84, bd=2, relief='raised')
+ f.place_configure(x=48, y=38)
+ f2 = tkinter.Frame(t, width=30, height=60, bd=2, relief='raised')
+ self.root.update()
+ return t, f, f2
+
+ def test_place_configure_in(self):
+ t, f, f2 = self.create2()
+ self.assertEqual(f2.winfo_manager(), '')
+ with self.assertRaisesRegex(TclError, "can't place %s relative to "
+ "itself" % re.escape(str(f2))):
+ f2.place_configure(in_=f2)
+ if tcl_version >= (8, 5):
+ self.assertEqual(f2.winfo_manager(), '')
+ with self.assertRaisesRegex(TclError, 'bad window path name'):
+ f2.place_configure(in_='spam')
+ f2.place_configure(in_=f)
+ self.assertEqual(f2.winfo_manager(), 'place')
+
+ def test_place_configure_x(self):
+ t, f, f2 = self.create2()
+ f2.place_configure(in_=f)
+ self.assertEqual(f2.place_info()['x'], '0')
+ self.root.update()
+ self.assertEqual(f2.winfo_x(), 50)
+ f2.place_configure(x=100)
+ self.assertEqual(f2.place_info()['x'], '100')
+ self.root.update()
+ self.assertEqual(f2.winfo_x(), 150)
+ f2.place_configure(x=-10, relx=1)
+ self.assertEqual(f2.place_info()['x'], '-10')
+ self.root.update()
+ self.assertEqual(f2.winfo_x(), 190)
+ with self.assertRaisesRegex(TclError, 'bad screen distance "spam"'):
+ f2.place_configure(in_=f, x='spam')
+
+ def test_place_configure_y(self):
+ t, f, f2 = self.create2()
+ f2.place_configure(in_=f)
+ self.assertEqual(f2.place_info()['y'], '0')
+ self.root.update()
+ self.assertEqual(f2.winfo_y(), 40)
+ f2.place_configure(y=50)
+ self.assertEqual(f2.place_info()['y'], '50')
+ self.root.update()
+ self.assertEqual(f2.winfo_y(), 90)
+ f2.place_configure(y=-10, rely=1)
+ self.assertEqual(f2.place_info()['y'], '-10')
+ self.root.update()
+ self.assertEqual(f2.winfo_y(), 110)
+ with self.assertRaisesRegex(TclError, 'bad screen distance "spam"'):
+ f2.place_configure(in_=f, y='spam')
+
+ def test_place_configure_relx(self):
+ t, f, f2 = self.create2()
+ f2.place_configure(in_=f)
+ self.assertEqual(f2.place_info()['relx'], '0')
+ self.root.update()
+ self.assertEqual(f2.winfo_x(), 50)
+ f2.place_configure(relx=0.5)
+ self.assertEqual(f2.place_info()['relx'], '0.5')
+ self.root.update()
+ self.assertEqual(f2.winfo_x(), 125)
+ f2.place_configure(relx=1)
+ self.assertEqual(f2.place_info()['relx'], '1')
+ self.root.update()
+ self.assertEqual(f2.winfo_x(), 200)
+ with self.assertRaisesRegex(TclError, 'expected floating-point number '
+ 'but got "spam"'):
+ f2.place_configure(in_=f, relx='spam')
+
+ def test_place_configure_rely(self):
+ t, f, f2 = self.create2()
+ f2.place_configure(in_=f)
+ self.assertEqual(f2.place_info()['rely'], '0')
+ self.root.update()
+ self.assertEqual(f2.winfo_y(), 40)
+ f2.place_configure(rely=0.5)
+ self.assertEqual(f2.place_info()['rely'], '0.5')
+ self.root.update()
+ self.assertEqual(f2.winfo_y(), 80)
+ f2.place_configure(rely=1)
+ self.assertEqual(f2.place_info()['rely'], '1')
+ self.root.update()
+ self.assertEqual(f2.winfo_y(), 120)
+ with self.assertRaisesRegex(TclError, 'expected floating-point number '
+ 'but got "spam"'):
+ f2.place_configure(in_=f, rely='spam')
+
+ def test_place_configure_anchor(self):
+ f = tkinter.Frame(self.root)
+ with self.assertRaisesRegex(TclError, 'bad anchor "j"'):
+ f.place_configure(anchor='j')
+ with self.assertRaisesRegex(TclError, 'ambiguous anchor ""'):
+ f.place_configure(anchor='')
+ for value in 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center':
+ f.place_configure(anchor=value)
+ self.assertEqual(f.place_info()['anchor'], value)
+
+ def test_place_configure_width(self):
+ t, f, f2 = self.create2()
+ f2.place_configure(in_=f, width=120)
+ self.root.update()
+ self.assertEqual(f2.winfo_width(), 120)
+ f2.place_configure(width='')
+ self.root.update()
+ self.assertEqual(f2.winfo_width(), 30)
+ with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'):
+ f2.place_configure(width='abcd')
+
+ def test_place_configure_height(self):
+ t, f, f2 = self.create2()
+ f2.place_configure(in_=f, height=120)
+ self.root.update()
+ self.assertEqual(f2.winfo_height(), 120)
+ f2.place_configure(height='')
+ self.root.update()
+ self.assertEqual(f2.winfo_height(), 60)
+ with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'):
+ f2.place_configure(height='abcd')
+
+ def test_place_configure_relwidth(self):
+ t, f, f2 = self.create2()
+ f2.place_configure(in_=f, relwidth=0.5)
+ self.root.update()
+ self.assertEqual(f2.winfo_width(), 75)
+ f2.place_configure(relwidth='')
+ self.root.update()
+ self.assertEqual(f2.winfo_width(), 30)
+ with self.assertRaisesRegex(TclError, 'expected floating-point number '
+ 'but got "abcd"'):
+ f2.place_configure(relwidth='abcd')
+
+ def test_place_configure_relheight(self):
+ t, f, f2 = self.create2()
+ f2.place_configure(in_=f, relheight=0.5)
+ self.root.update()
+ self.assertEqual(f2.winfo_height(), 40)
+ f2.place_configure(relheight='')
+ self.root.update()
+ self.assertEqual(f2.winfo_height(), 60)
+ with self.assertRaisesRegex(TclError, 'expected floating-point number '
+ 'but got "abcd"'):
+ f2.place_configure(relheight='abcd')
+
+ def test_place_configure_bordermode(self):
+ f = tkinter.Frame(self.root)
+ with self.assertRaisesRegex(TclError, 'bad bordermode "j"'):
+ f.place_configure(bordermode='j')
+ with self.assertRaisesRegex(TclError, 'ambiguous bordermode ""'):
+ f.place_configure(bordermode='')
+ for value in 'inside', 'outside', 'ignore':
+ f.place_configure(bordermode=value)
+ self.assertEqual(f.place_info()['bordermode'], value)
+
+ def test_place_forget(self):
+ foo = tkinter.Frame(self.root)
+ foo.place_configure(width=50, height=50)
+ self.root.update()
+ foo.place_forget()
+ self.root.update()
+ self.assertFalse(foo.winfo_ismapped())
+ with self.assertRaises(TypeError):
+ foo.place_forget(0)
+
+ def test_place_info(self):
+ t, f, f2 = self.create2()
+ f2.place_configure(in_=f, x=1, y=2, width=3, height=4,
+ relx=0.1, rely=0.2, relwidth=0.3, relheight=0.4,
+ anchor='se', bordermode='outside')
+ info = f2.place_info()
+ self.assertIsInstance(info, dict)
+ self.assertEqual(info['x'], '1')
+ self.assertEqual(info['y'], '2')
+ self.assertEqual(info['width'], '3')
+ self.assertEqual(info['height'], '4')
+ self.assertEqual(info['relx'], '0.1')
+ self.assertEqual(info['rely'], '0.2')
+ self.assertEqual(info['relwidth'], '0.3')
+ self.assertEqual(info['relheight'], '0.4')
+ self.assertEqual(info['anchor'], 'se')
+ self.assertEqual(info['bordermode'], 'outside')
+ self.assertEqual(info['x'], '1')
+ self.assertEqual(info['x'], '1')
+ with self.assertRaises(TypeError):
+ f2.place_info(0)
+
+ def test_place_slaves(self):
+ foo = tkinter.Frame(self.root)
+ bar = tkinter.Frame(self.root)
+ self.assertEqual(foo.place_slaves(), [])
+ bar.place_configure(in_=foo)
+ self.assertEqual(foo.place_slaves(), [bar])
+ with self.assertRaises(TypeError):
+ foo.place_slaves(0)
+
+
+class GridTest(AbstractWidgetTest, unittest.TestCase):
+
+ def tearDown(self):
+ cols, rows = self.root.grid_size()
+ for i in range(cols + 1):
+ self.root.grid_columnconfigure(i, weight=0, minsize=0, pad=0, uniform='')
+ for i in range(rows + 1):
+ self.root.grid_rowconfigure(i, weight=0, minsize=0, pad=0, uniform='')
+ self.root.grid_propagate(1)
+ if tcl_version >= (8, 5):
+ self.root.grid_anchor('nw')
+ super().tearDown()
+
+ def test_grid_configure(self):
+ b = tkinter.Button(self.root)
+ self.assertEqual(b.grid_info(), {})
+ b.grid_configure()
+ self.assertEqual(b.grid_info()['in'], self.root)
+ self.assertEqual(b.grid_info()['column'], self._str(0))
+ self.assertEqual(b.grid_info()['row'], self._str(0))
+ b.grid_configure({'column': 1}, row=2)
+ self.assertEqual(b.grid_info()['column'], self._str(1))
+ self.assertEqual(b.grid_info()['row'], self._str(2))
+
+ def test_grid_configure_column(self):
+ b = tkinter.Button(self.root)
+ with self.assertRaisesRegex(TclError, 'bad column value "-1": '
+ 'must be a non-negative integer'):
+ b.grid_configure(column=-1)
+ b.grid_configure(column=2)
+ self.assertEqual(b.grid_info()['column'], self._str(2))
+
+ def test_grid_configure_columnspan(self):
+ b = tkinter.Button(self.root)
+ with self.assertRaisesRegex(TclError, 'bad columnspan value "0": '
+ 'must be a positive integer'):
+ b.grid_configure(columnspan=0)
+ b.grid_configure(columnspan=2)
+ self.assertEqual(b.grid_info()['columnspan'], self._str(2))
+
+ def test_grid_configure_in(self):
+ f = tkinter.Frame(self.root)
+ b = tkinter.Button(self.root)
+ self.assertEqual(b.grid_info(), {})
+ b.grid_configure()
+ self.assertEqual(b.grid_info()['in'], self.root)
+ b.grid_configure(in_=f)
+ self.assertEqual(b.grid_info()['in'], f)
+ b.grid_configure({'in': self.root})
+ self.assertEqual(b.grid_info()['in'], self.root)
+
+ def test_grid_configure_ipadx(self):
+ b = tkinter.Button(self.root)
+ with self.assertRaisesRegex(TclError, 'bad ipadx value "-1": '
+ 'must be positive screen distance'):
+ b.grid_configure(ipadx=-1)
+ b.grid_configure(ipadx=1)
+ self.assertEqual(b.grid_info()['ipadx'], self._str(1))
+ b.grid_configure(ipadx='.5c')
+ self.assertEqual(b.grid_info()['ipadx'],
+ self._str(round(pixels_conv('.5c') * self.scaling)))
+
+ def test_grid_configure_ipady(self):
+ b = tkinter.Button(self.root)
+ with self.assertRaisesRegex(TclError, 'bad ipady value "-1": '
+ 'must be positive screen distance'):
+ b.grid_configure(ipady=-1)
+ b.grid_configure(ipady=1)
+ self.assertEqual(b.grid_info()['ipady'], self._str(1))
+ b.grid_configure(ipady='.5c')
+ self.assertEqual(b.grid_info()['ipady'],
+ self._str(round(pixels_conv('.5c') * self.scaling)))
+
+ def test_grid_configure_padx(self):
+ b = tkinter.Button(self.root)
+ with self.assertRaisesRegex(TclError, 'bad pad value "-1": '
+ 'must be positive screen distance'):
+ b.grid_configure(padx=-1)
+ b.grid_configure(padx=1)
+ self.assertEqual(b.grid_info()['padx'], self._str(1))
+ b.grid_configure(padx=(10, 5))
+ self.assertEqual(b.grid_info()['padx'], self._str((10, 5)))
+ b.grid_configure(padx='.5c')
+ self.assertEqual(b.grid_info()['padx'],
+ self._str(round(pixels_conv('.5c') * self.scaling)))
+
+ def test_grid_configure_pady(self):
+ b = tkinter.Button(self.root)
+ with self.assertRaisesRegex(TclError, 'bad pad value "-1": '
+ 'must be positive screen distance'):
+ b.grid_configure(pady=-1)
+ b.grid_configure(pady=1)
+ self.assertEqual(b.grid_info()['pady'], self._str(1))
+ b.grid_configure(pady=(10, 5))
+ self.assertEqual(b.grid_info()['pady'], self._str((10, 5)))
+ b.grid_configure(pady='.5c')
+ self.assertEqual(b.grid_info()['pady'],
+ self._str(round(pixels_conv('.5c') * self.scaling)))
+
+ def test_grid_configure_row(self):
+ b = tkinter.Button(self.root)
+ with self.assertRaisesRegex(TclError, 'bad (row|grid) value "-1": '
+ 'must be a non-negative integer'):
+ b.grid_configure(row=-1)
+ b.grid_configure(row=2)
+ self.assertEqual(b.grid_info()['row'], self._str(2))
+
+ def test_grid_configure_rownspan(self):
+ b = tkinter.Button(self.root)
+ with self.assertRaisesRegex(TclError, 'bad rowspan value "0": '
+ 'must be a positive integer'):
+ b.grid_configure(rowspan=0)
+ b.grid_configure(rowspan=2)
+ self.assertEqual(b.grid_info()['rowspan'], self._str(2))
+
+ def test_grid_configure_sticky(self):
+ f = tkinter.Frame(self.root, bg='red')
+ with self.assertRaisesRegex(TclError, 'bad stickyness value "glue"'):
+ f.grid_configure(sticky='glue')
+ f.grid_configure(sticky='ne')
+ self.assertEqual(f.grid_info()['sticky'], 'ne')
+ f.grid_configure(sticky='n,s,e,w')
+ self.assertEqual(f.grid_info()['sticky'], 'nesw')
+
+ def test_grid_columnconfigure(self):
+ with self.assertRaises(TypeError):
+ self.root.grid_columnconfigure()
+ self.assertEqual(self.root.grid_columnconfigure(0),
+ {'minsize': 0, 'pad': 0, 'uniform': None, 'weight': 0})
+ with self.assertRaisesRegex(TclError, 'bad option "-foo"'):
+ self.root.grid_columnconfigure(0, 'foo')
+ self.root.grid_columnconfigure((0, 3), weight=2)
+ with self.assertRaisesRegex(TclError,
+ 'must specify a single element on retrieval'):
+ self.root.grid_columnconfigure((0, 3))
+ b = tkinter.Button(self.root)
+ b.grid_configure(column=0, row=0)
+ if tcl_version >= (8, 5):
+ self.root.grid_columnconfigure('all', weight=3)
+ with self.assertRaisesRegex(TclError, 'expected integer but got "all"'):
+ self.root.grid_columnconfigure('all')
+ self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 3)
+ self.assertEqual(self.root.grid_columnconfigure(3, 'weight'), 2)
+ self.assertEqual(self.root.grid_columnconfigure(265, 'weight'), 0)
+ if tcl_version >= (8, 5):
+ self.root.grid_columnconfigure(b, weight=4)
+ self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 4)
+
+ def test_grid_columnconfigure_minsize(self):
+ with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'):
+ self.root.grid_columnconfigure(0, minsize='foo')
+ self.root.grid_columnconfigure(0, minsize=10)
+ self.assertEqual(self.root.grid_columnconfigure(0, 'minsize'), 10)
+ self.assertEqual(self.root.grid_columnconfigure(0)['minsize'], 10)
+
+ def test_grid_columnconfigure_weight(self):
+ with self.assertRaisesRegex(TclError, 'expected integer but got "bad"'):
+ self.root.grid_columnconfigure(0, weight='bad')
+ with self.assertRaisesRegex(TclError, 'invalid arg "-weight": '
+ 'should be non-negative'):
+ self.root.grid_columnconfigure(0, weight=-3)
+ self.root.grid_columnconfigure(0, weight=3)
+ self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 3)
+ self.assertEqual(self.root.grid_columnconfigure(0)['weight'], 3)
+
+ def test_grid_columnconfigure_pad(self):
+ with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'):
+ self.root.grid_columnconfigure(0, pad='foo')
+ with self.assertRaisesRegex(TclError, 'invalid arg "-pad": '
+ 'should be non-negative'):
+ self.root.grid_columnconfigure(0, pad=-3)
+ self.root.grid_columnconfigure(0, pad=3)
+ self.assertEqual(self.root.grid_columnconfigure(0, 'pad'), 3)
+ self.assertEqual(self.root.grid_columnconfigure(0)['pad'], 3)
+
+ def test_grid_columnconfigure_uniform(self):
+ self.root.grid_columnconfigure(0, uniform='foo')
+ self.assertEqual(self.root.grid_columnconfigure(0, 'uniform'), 'foo')
+ self.assertEqual(self.root.grid_columnconfigure(0)['uniform'], 'foo')
+
+ def test_grid_rowconfigure(self):
+ with self.assertRaises(TypeError):
+ self.root.grid_rowconfigure()
+ self.assertEqual(self.root.grid_rowconfigure(0),
+ {'minsize': 0, 'pad': 0, 'uniform': None, 'weight': 0})
+ with self.assertRaisesRegex(TclError, 'bad option "-foo"'):
+ self.root.grid_rowconfigure(0, 'foo')
+ self.root.grid_rowconfigure((0, 3), weight=2)
+ with self.assertRaisesRegex(TclError,
+ 'must specify a single element on retrieval'):
+ self.root.grid_rowconfigure((0, 3))
+ b = tkinter.Button(self.root)
+ b.grid_configure(column=0, row=0)
+ if tcl_version >= (8, 5):
+ self.root.grid_rowconfigure('all', weight=3)
+ with self.assertRaisesRegex(TclError, 'expected integer but got "all"'):
+ self.root.grid_rowconfigure('all')
+ self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 3)
+ self.assertEqual(self.root.grid_rowconfigure(3, 'weight'), 2)
+ self.assertEqual(self.root.grid_rowconfigure(265, 'weight'), 0)
+ if tcl_version >= (8, 5):
+ self.root.grid_rowconfigure(b, weight=4)
+ self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 4)
+
+ def test_grid_rowconfigure_minsize(self):
+ with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'):
+ self.root.grid_rowconfigure(0, minsize='foo')
+ self.root.grid_rowconfigure(0, minsize=10)
+ self.assertEqual(self.root.grid_rowconfigure(0, 'minsize'), 10)
+ self.assertEqual(self.root.grid_rowconfigure(0)['minsize'], 10)
+
+ def test_grid_rowconfigure_weight(self):
+ with self.assertRaisesRegex(TclError, 'expected integer but got "bad"'):
+ self.root.grid_rowconfigure(0, weight='bad')
+ with self.assertRaisesRegex(TclError, 'invalid arg "-weight": '
+ 'should be non-negative'):
+ self.root.grid_rowconfigure(0, weight=-3)
+ self.root.grid_rowconfigure(0, weight=3)
+ self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 3)
+ self.assertEqual(self.root.grid_rowconfigure(0)['weight'], 3)
+
+ def test_grid_rowconfigure_pad(self):
+ with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'):
+ self.root.grid_rowconfigure(0, pad='foo')
+ with self.assertRaisesRegex(TclError, 'invalid arg "-pad": '
+ 'should be non-negative'):
+ self.root.grid_rowconfigure(0, pad=-3)
+ self.root.grid_rowconfigure(0, pad=3)
+ self.assertEqual(self.root.grid_rowconfigure(0, 'pad'), 3)
+ self.assertEqual(self.root.grid_rowconfigure(0)['pad'], 3)
+
+ def test_grid_rowconfigure_uniform(self):
+ self.root.grid_rowconfigure(0, uniform='foo')
+ self.assertEqual(self.root.grid_rowconfigure(0, 'uniform'), 'foo')
+ self.assertEqual(self.root.grid_rowconfigure(0)['uniform'], 'foo')
+
+ def test_grid_forget(self):
+ b = tkinter.Button(self.root)
+ c = tkinter.Button(self.root)
+ b.grid_configure(row=2, column=2, rowspan=2, columnspan=2,
+ padx=3, pady=4, sticky='ns')
+ self.assertEqual(self.root.grid_slaves(), [b])
+ b.grid_forget()
+ c.grid_forget()
+ self.assertEqual(self.root.grid_slaves(), [])
+ self.assertEqual(b.grid_info(), {})
+ b.grid_configure(row=0, column=0)
+ info = b.grid_info()
+ self.assertEqual(info['row'], self._str(0))
+ self.assertEqual(info['column'], self._str(0))
+ self.assertEqual(info['rowspan'], self._str(1))
+ self.assertEqual(info['columnspan'], self._str(1))
+ self.assertEqual(info['padx'], self._str(0))
+ self.assertEqual(info['pady'], self._str(0))
+ self.assertEqual(info['sticky'], '')
+
+ def test_grid_remove(self):
+ b = tkinter.Button(self.root)
+ c = tkinter.Button(self.root)
+ b.grid_configure(row=2, column=2, rowspan=2, columnspan=2,
+ padx=3, pady=4, sticky='ns')
+ self.assertEqual(self.root.grid_slaves(), [b])
+ b.grid_remove()
+ c.grid_remove()
+ self.assertEqual(self.root.grid_slaves(), [])
+ self.assertEqual(b.grid_info(), {})
+ b.grid_configure(row=0, column=0)
+ info = b.grid_info()
+ self.assertEqual(info['row'], self._str(0))
+ self.assertEqual(info['column'], self._str(0))
+ self.assertEqual(info['rowspan'], self._str(2))
+ self.assertEqual(info['columnspan'], self._str(2))
+ self.assertEqual(info['padx'], self._str(3))
+ self.assertEqual(info['pady'], self._str(4))
+ self.assertEqual(info['sticky'], 'ns')
+
+ def test_grid_info(self):
+ b = tkinter.Button(self.root)
+ self.assertEqual(b.grid_info(), {})
+ b.grid_configure(row=2, column=2, rowspan=2, columnspan=2,
+ padx=3, pady=4, sticky='ns')
+ info = b.grid_info()
+ self.assertIsInstance(info, dict)
+ self.assertEqual(info['in'], self.root)
+ self.assertEqual(info['row'], self._str(2))
+ self.assertEqual(info['column'], self._str(2))
+ self.assertEqual(info['rowspan'], self._str(2))
+ self.assertEqual(info['columnspan'], self._str(2))
+ self.assertEqual(info['padx'], self._str(3))
+ self.assertEqual(info['pady'], self._str(4))
+ self.assertEqual(info['sticky'], 'ns')
+
+ @requires_tcl(8, 5)
+ def test_grid_anchor(self):
+ with self.assertRaisesRegex(TclError, 'bad anchor "x"'):
+ self.root.grid_anchor('x')
+ with self.assertRaisesRegex(TclError, 'ambiguous anchor ""'):
+ self.root.grid_anchor('')
+ with self.assertRaises(TypeError):
+ self.root.grid_anchor('se', 'nw')
+ self.root.grid_anchor('se')
+ self.assertEqual(self.root.tk.call('grid', 'anchor', self.root), 'se')
+
+ def test_grid_bbox(self):
+ self.assertEqual(self.root.grid_bbox(), (0, 0, 0, 0))
+ self.assertEqual(self.root.grid_bbox(0, 0), (0, 0, 0, 0))
+ self.assertEqual(self.root.grid_bbox(0, 0, 1, 1), (0, 0, 0, 0))
+ with self.assertRaisesRegex(TclError, 'expected integer but got "x"'):
+ self.root.grid_bbox('x', 0)
+ with self.assertRaisesRegex(TclError, 'expected integer but got "x"'):
+ self.root.grid_bbox(0, 'x')
+ with self.assertRaisesRegex(TclError, 'expected integer but got "x"'):
+ self.root.grid_bbox(0, 0, 'x', 0)
+ with self.assertRaisesRegex(TclError, 'expected integer but got "x"'):
+ self.root.grid_bbox(0, 0, 0, 'x')
+ with self.assertRaises(TypeError):
+ self.root.grid_bbox(0, 0, 0, 0, 0)
+ t = self.root
+ # de-maximize
+ t.wm_geometry('1x1+0+0')
+ t.wm_geometry('')
+ f1 = tkinter.Frame(t, width=75, height=75, bg='red')
+ f2 = tkinter.Frame(t, width=90, height=90, bg='blue')
+ f1.grid_configure(row=0, column=0)
+ f2.grid_configure(row=1, column=1)
+ self.root.update()
+ self.assertEqual(t.grid_bbox(), (0, 0, 165, 165))
+ self.assertEqual(t.grid_bbox(0, 0), (0, 0, 75, 75))
+ self.assertEqual(t.grid_bbox(0, 0, 1, 1), (0, 0, 165, 165))
+ self.assertEqual(t.grid_bbox(1, 1), (75, 75, 90, 90))
+ self.assertEqual(t.grid_bbox(10, 10, 0, 0), (0, 0, 165, 165))
+ self.assertEqual(t.grid_bbox(-2, -2, -1, -1), (0, 0, 0, 0))
+ self.assertEqual(t.grid_bbox(10, 10, 12, 12), (165, 165, 0, 0))
+
+ def test_grid_location(self):
+ with self.assertRaises(TypeError):
+ self.root.grid_location()
+ with self.assertRaises(TypeError):
+ self.root.grid_location(0)
+ with self.assertRaises(TypeError):
+ self.root.grid_location(0, 0, 0)
+ with self.assertRaisesRegex(TclError, 'bad screen distance "x"'):
+ self.root.grid_location('x', 'y')
+ with self.assertRaisesRegex(TclError, 'bad screen distance "y"'):
+ self.root.grid_location('1c', 'y')
+ t = self.root
+ # de-maximize
+ t.wm_geometry('1x1+0+0')
+ t.wm_geometry('')
+ f = tkinter.Frame(t, width=200, height=100,
+ highlightthickness=0, bg='red')
+ self.assertEqual(f.grid_location(10, 10), (-1, -1))
+ f.grid_configure()
+ self.root.update()
+ self.assertEqual(t.grid_location(-10, -10), (-1, -1))
+ self.assertEqual(t.grid_location(-10, 0), (-1, 0))
+ self.assertEqual(t.grid_location(-1, 0), (-1, 0))
+ self.assertEqual(t.grid_location(0, -10), (0, -1))
+ self.assertEqual(t.grid_location(0, -1), (0, -1))
+ self.assertEqual(t.grid_location(0, 0), (0, 0))
+ self.assertEqual(t.grid_location(200, 0), (0, 0))
+ self.assertEqual(t.grid_location(201, 0), (1, 0))
+ self.assertEqual(t.grid_location(0, 100), (0, 0))
+ self.assertEqual(t.grid_location(0, 101), (0, 1))
+ self.assertEqual(t.grid_location(201, 101), (1, 1))
+
+ def test_grid_propagate(self):
+ self.assertEqual(self.root.grid_propagate(), True)
+ with self.assertRaises(TypeError):
+ self.root.grid_propagate(False, False)
+ self.root.grid_propagate(False)
+ self.assertFalse(self.root.grid_propagate())
+ f = tkinter.Frame(self.root, width=100, height=100, bg='red')
+ f.grid_configure(row=0, column=0)
+ self.root.update()
+ self.assertEqual(f.winfo_width(), 100)
+ self.assertEqual(f.winfo_height(), 100)
+ f.grid_propagate(False)
+ g = tkinter.Frame(self.root, width=75, height=85, bg='green')
+ g.grid_configure(in_=f, row=0, column=0)
+ self.root.update()
+ self.assertEqual(f.winfo_width(), 100)
+ self.assertEqual(f.winfo_height(), 100)
+ f.grid_propagate(True)
+ self.root.update()
+ self.assertEqual(f.winfo_width(), 75)
+ self.assertEqual(f.winfo_height(), 85)
+
+ def test_grid_size(self):
+ with self.assertRaises(TypeError):
+ self.root.grid_size(0)
+ self.assertEqual(self.root.grid_size(), (0, 0))
+ f = tkinter.Scale(self.root)
+ f.grid_configure(row=0, column=0)
+ self.assertEqual(self.root.grid_size(), (1, 1))
+ f.grid_configure(row=4, column=5)
+ self.assertEqual(self.root.grid_size(), (6, 5))
+
+ def test_grid_slaves(self):
+ self.assertEqual(self.root.grid_slaves(), [])
+ a = tkinter.Label(self.root)
+ a.grid_configure(row=0, column=1)
+ b = tkinter.Label(self.root)
+ b.grid_configure(row=1, column=0)
+ c = tkinter.Label(self.root)
+ c.grid_configure(row=1, column=1)
+ d = tkinter.Label(self.root)
+ d.grid_configure(row=1, column=1)
+ self.assertEqual(self.root.grid_slaves(), [d, c, b, a])
+ self.assertEqual(self.root.grid_slaves(row=0), [a])
+ self.assertEqual(self.root.grid_slaves(row=1), [d, c, b])
+ self.assertEqual(self.root.grid_slaves(column=0), [b])
+ self.assertEqual(self.root.grid_slaves(column=1), [d, c, a])
+ self.assertEqual(self.root.grid_slaves(row=1, column=1), [d, c])
+
+
+tests_gui = (
+ PackTest, PlaceTest, GridTest,
+)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Lib/tkinter/test/test_tkinter/test_images.py b/Lib/tkinter/test/test_tkinter/test_images.py
new file mode 100644
index 0000000..85a8cd0
--- /dev/null
+++ b/Lib/tkinter/test/test_tkinter/test_images.py
@@ -0,0 +1,327 @@
+import unittest
+import tkinter
+from test import support
+from tkinter.test.support import AbstractTkTest, requires_tcl
+
+support.requires('gui')
+
+
+class MiscTest(AbstractTkTest, unittest.TestCase):
+
+ def test_image_types(self):
+ image_types = self.root.image_types()
+ self.assertIsInstance(image_types, tuple)
+ self.assertIn('photo', image_types)
+ self.assertIn('bitmap', image_types)
+
+ def test_image_names(self):
+ image_names = self.root.image_names()
+ self.assertIsInstance(image_names, tuple)
+
+
+class BitmapImageTest(AbstractTkTest, unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ AbstractTkTest.setUpClass.__func__(cls)
+ cls.testfile = support.findfile('python.xbm', subdir='imghdrdata')
+
+ def test_create_from_file(self):
+ image = tkinter.BitmapImage('::img::test', master=self.root,
+ foreground='yellow', background='blue',
+ file=self.testfile)
+ self.assertEqual(str(image), '::img::test')
+ self.assertEqual(image.type(), 'bitmap')
+ self.assertEqual(image.width(), 16)
+ self.assertEqual(image.height(), 16)
+ self.assertIn('::img::test', self.root.image_names())
+ del image
+ self.assertNotIn('::img::test', self.root.image_names())
+
+ def test_create_from_data(self):
+ with open(self.testfile, 'rb') as f:
+ data = f.read()
+ image = tkinter.BitmapImage('::img::test', master=self.root,
+ foreground='yellow', background='blue',
+ data=data)
+ self.assertEqual(str(image), '::img::test')
+ self.assertEqual(image.type(), 'bitmap')
+ self.assertEqual(image.width(), 16)
+ self.assertEqual(image.height(), 16)
+ self.assertIn('::img::test', self.root.image_names())
+ del image
+ self.assertNotIn('::img::test', self.root.image_names())
+
+ def assertEqualStrList(self, actual, expected):
+ self.assertIsInstance(actual, str)
+ self.assertEqual(self.root.splitlist(actual), expected)
+
+ def test_configure_data(self):
+ image = tkinter.BitmapImage('::img::test', master=self.root)
+ self.assertEqual(image['data'], '-data {} {} {} {}')
+ with open(self.testfile, 'rb') as f:
+ data = f.read()
+ image.configure(data=data)
+ self.assertEqualStrList(image['data'],
+ ('-data', '', '', '', data.decode('ascii')))
+ self.assertEqual(image.width(), 16)
+ self.assertEqual(image.height(), 16)
+
+ self.assertEqual(image['maskdata'], '-maskdata {} {} {} {}')
+ image.configure(maskdata=data)
+ self.assertEqualStrList(image['maskdata'],
+ ('-maskdata', '', '', '', data.decode('ascii')))
+
+ def test_configure_file(self):
+ image = tkinter.BitmapImage('::img::test', master=self.root)
+ self.assertEqual(image['file'], '-file {} {} {} {}')
+ image.configure(file=self.testfile)
+ self.assertEqualStrList(image['file'],
+ ('-file', '', '', '',self.testfile))
+ self.assertEqual(image.width(), 16)
+ self.assertEqual(image.height(), 16)
+
+ self.assertEqual(image['maskfile'], '-maskfile {} {} {} {}')
+ image.configure(maskfile=self.testfile)
+ self.assertEqualStrList(image['maskfile'],
+ ('-maskfile', '', '', '', self.testfile))
+
+ def test_configure_background(self):
+ image = tkinter.BitmapImage('::img::test', master=self.root)
+ self.assertEqual(image['background'], '-background {} {} {} {}')
+ image.configure(background='blue')
+ self.assertEqual(image['background'], '-background {} {} {} blue')
+
+ def test_configure_foreground(self):
+ image = tkinter.BitmapImage('::img::test', master=self.root)
+ self.assertEqual(image['foreground'],
+ '-foreground {} {} #000000 #000000')
+ image.configure(foreground='yellow')
+ self.assertEqual(image['foreground'],
+ '-foreground {} {} #000000 yellow')
+
+
+class PhotoImageTest(AbstractTkTest, unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ AbstractTkTest.setUpClass.__func__(cls)
+ cls.testfile = support.findfile('python.gif', subdir='imghdrdata')
+
+ def create(self):
+ return tkinter.PhotoImage('::img::test', master=self.root,
+ file=self.testfile)
+
+ def colorlist(self, *args):
+ if tkinter.TkVersion >= 8.6 and self.wantobjects:
+ return args
+ else:
+ return tkinter._join(args)
+
+ def check_create_from_file(self, ext):
+ testfile = support.findfile('python.' + ext, subdir='imghdrdata')
+ image = tkinter.PhotoImage('::img::test', master=self.root,
+ file=testfile)
+ self.assertEqual(str(image), '::img::test')
+ self.assertEqual(image.type(), 'photo')
+ self.assertEqual(image.width(), 16)
+ self.assertEqual(image.height(), 16)
+ self.assertEqual(image['data'], '')
+ self.assertEqual(image['file'], testfile)
+ self.assertIn('::img::test', self.root.image_names())
+ del image
+ self.assertNotIn('::img::test', self.root.image_names())
+
+ def check_create_from_data(self, ext):
+ testfile = support.findfile('python.' + ext, subdir='imghdrdata')
+ with open(testfile, 'rb') as f:
+ data = f.read()
+ image = tkinter.PhotoImage('::img::test', master=self.root,
+ data=data)
+ self.assertEqual(str(image), '::img::test')
+ self.assertEqual(image.type(), 'photo')
+ self.assertEqual(image.width(), 16)
+ self.assertEqual(image.height(), 16)
+ self.assertEqual(image['data'], data if self.wantobjects
+ else data.decode('latin1'))
+ self.assertEqual(image['file'], '')
+ self.assertIn('::img::test', self.root.image_names())
+ del image
+ self.assertNotIn('::img::test', self.root.image_names())
+
+ def test_create_from_ppm_file(self):
+ self.check_create_from_file('ppm')
+
+ def test_create_from_ppm_data(self):
+ self.check_create_from_data('ppm')
+
+ def test_create_from_pgm_file(self):
+ self.check_create_from_file('pgm')
+
+ def test_create_from_pgm_data(self):
+ self.check_create_from_data('pgm')
+
+ def test_create_from_gif_file(self):
+ self.check_create_from_file('gif')
+
+ def test_create_from_gif_data(self):
+ self.check_create_from_data('gif')
+
+ @requires_tcl(8, 6)
+ def test_create_from_png_file(self):
+ self.check_create_from_file('png')
+
+ @requires_tcl(8, 6)
+ def test_create_from_png_data(self):
+ self.check_create_from_data('png')
+
+ def test_configure_data(self):
+ image = tkinter.PhotoImage('::img::test', master=self.root)
+ self.assertEqual(image['data'], '')
+ with open(self.testfile, 'rb') as f:
+ data = f.read()
+ image.configure(data=data)
+ self.assertEqual(image['data'], data if self.wantobjects
+ else data.decode('latin1'))
+ self.assertEqual(image.width(), 16)
+ self.assertEqual(image.height(), 16)
+
+ def test_configure_format(self):
+ image = tkinter.PhotoImage('::img::test', master=self.root)
+ self.assertEqual(image['format'], '')
+ image.configure(file=self.testfile, format='gif')
+ self.assertEqual(image['format'], ('gif',) if self.wantobjects
+ else 'gif')
+ self.assertEqual(image.width(), 16)
+ self.assertEqual(image.height(), 16)
+
+ def test_configure_file(self):
+ image = tkinter.PhotoImage('::img::test', master=self.root)
+ self.assertEqual(image['file'], '')
+ image.configure(file=self.testfile)
+ self.assertEqual(image['file'], self.testfile)
+ self.assertEqual(image.width(), 16)
+ self.assertEqual(image.height(), 16)
+
+ def test_configure_gamma(self):
+ image = tkinter.PhotoImage('::img::test', master=self.root)
+ self.assertEqual(image['gamma'], '1.0')
+ image.configure(gamma=2.0)
+ self.assertEqual(image['gamma'], '2.0')
+
+ def test_configure_width_height(self):
+ image = tkinter.PhotoImage('::img::test', master=self.root)
+ self.assertEqual(image['width'], '0')
+ self.assertEqual(image['height'], '0')
+ image.configure(width=20)
+ image.configure(height=10)
+ self.assertEqual(image['width'], '20')
+ self.assertEqual(image['height'], '10')
+ self.assertEqual(image.width(), 20)
+ self.assertEqual(image.height(), 10)
+
+ def test_configure_palette(self):
+ image = tkinter.PhotoImage('::img::test', master=self.root)
+ self.assertEqual(image['palette'], '')
+ image.configure(palette=256)
+ self.assertEqual(image['palette'], '256')
+ image.configure(palette='3/4/2')
+ self.assertEqual(image['palette'], '3/4/2')
+
+ def test_blank(self):
+ image = self.create()
+ image.blank()
+ self.assertEqual(image.width(), 16)
+ self.assertEqual(image.height(), 16)
+ self.assertEqual(image.get(4, 6), self.colorlist(0, 0, 0))
+
+ def test_copy(self):
+ image = self.create()
+ image2 = image.copy()
+ self.assertEqual(image2.width(), 16)
+ self.assertEqual(image2.height(), 16)
+ self.assertEqual(image.get(4, 6), image.get(4, 6))
+
+ def test_subsample(self):
+ image = self.create()
+ image2 = image.subsample(2, 3)
+ self.assertEqual(image2.width(), 8)
+ self.assertEqual(image2.height(), 6)
+ self.assertEqual(image2.get(2, 2), image.get(4, 6))
+
+ image2 = image.subsample(2)
+ self.assertEqual(image2.width(), 8)
+ self.assertEqual(image2.height(), 8)
+ self.assertEqual(image2.get(2, 3), image.get(4, 6))
+
+ def test_zoom(self):
+ image = self.create()
+ image2 = image.zoom(2, 3)
+ self.assertEqual(image2.width(), 32)
+ self.assertEqual(image2.height(), 48)
+ self.assertEqual(image2.get(8, 18), image.get(4, 6))
+ self.assertEqual(image2.get(9, 20), image.get(4, 6))
+
+ image2 = image.zoom(2)
+ self.assertEqual(image2.width(), 32)
+ self.assertEqual(image2.height(), 32)
+ self.assertEqual(image2.get(8, 12), image.get(4, 6))
+ self.assertEqual(image2.get(9, 13), image.get(4, 6))
+
+ def test_put(self):
+ image = self.create()
+ image.put('{red green} {blue yellow}', to=(4, 6))
+ self.assertEqual(image.get(4, 6), self.colorlist(255, 0, 0))
+ self.assertEqual(image.get(5, 6),
+ self.colorlist(0, 128 if tkinter.TkVersion >= 8.6
+ else 255, 0))
+ self.assertEqual(image.get(4, 7), self.colorlist(0, 0, 255))
+ self.assertEqual(image.get(5, 7), self.colorlist(255, 255, 0))
+
+ image.put((('#f00', '#00ff00'), ('#000000fff', '#ffffffff0000')))
+ self.assertEqual(image.get(0, 0), self.colorlist(255, 0, 0))
+ self.assertEqual(image.get(1, 0), self.colorlist(0, 255, 0))
+ self.assertEqual(image.get(0, 1), self.colorlist(0, 0, 255))
+ self.assertEqual(image.get(1, 1), self.colorlist(255, 255, 0))
+
+ def test_get(self):
+ image = self.create()
+ self.assertEqual(image.get(4, 6), self.colorlist(62, 116, 162))
+ self.assertEqual(image.get(0, 0), self.colorlist(0, 0, 0))
+ self.assertEqual(image.get(15, 15), self.colorlist(0, 0, 0))
+ self.assertRaises(tkinter.TclError, image.get, -1, 0)
+ self.assertRaises(tkinter.TclError, image.get, 0, -1)
+ self.assertRaises(tkinter.TclError, image.get, 16, 15)
+ self.assertRaises(tkinter.TclError, image.get, 15, 16)
+
+ def test_write(self):
+ image = self.create()
+ self.addCleanup(support.unlink, support.TESTFN)
+
+ image.write(support.TESTFN)
+ image2 = tkinter.PhotoImage('::img::test2', master=self.root,
+ format='ppm',
+ file=support.TESTFN)
+ self.assertEqual(str(image2), '::img::test2')
+ self.assertEqual(image2.type(), 'photo')
+ self.assertEqual(image2.width(), 16)
+ self.assertEqual(image2.height(), 16)
+ self.assertEqual(image2.get(0, 0), image.get(0, 0))
+ self.assertEqual(image2.get(15, 8), image.get(15, 8))
+
+ image.write(support.TESTFN, format='gif', from_coords=(4, 6, 6, 9))
+ image3 = tkinter.PhotoImage('::img::test3', master=self.root,
+ format='gif',
+ file=support.TESTFN)
+ self.assertEqual(str(image3), '::img::test3')
+ self.assertEqual(image3.type(), 'photo')
+ self.assertEqual(image3.width(), 2)
+ self.assertEqual(image3.height(), 3)
+ self.assertEqual(image3.get(0, 0), image.get(4, 6))
+ self.assertEqual(image3.get(1, 2), image.get(5, 8))
+
+
+tests_gui = (MiscTest, BitmapImageTest, PhotoImageTest,)
+
+if __name__ == "__main__":
+ support.run_unittest(*tests_gui)
diff --git a/Lib/tkinter/test/test_tkinter/test_misc.py b/Lib/tkinter/test/test_tkinter/test_misc.py
index d325b31..d8de949 100644
--- a/Lib/tkinter/test/test_tkinter/test_misc.py
+++ b/Lib/tkinter/test/test_tkinter/test_misc.py
@@ -1,14 +1,11 @@
import unittest
import tkinter
-from tkinter import ttk
from test import support
+from tkinter.test.support import AbstractTkTest
support.requires('gui')
-class MiscTest(unittest.TestCase):
-
- def setUp(self):
- self.root = ttk.setup_master()
+class MiscTest(AbstractTkTest, unittest.TestCase):
def test_tk_setPalette(self):
root = self.root
diff --git a/Lib/tkinter/test/test_tkinter/test_text.py b/Lib/tkinter/test/test_tkinter/test_text.py
index 4c3fa04..13b7c56 100644
--- a/Lib/tkinter/test/test_tkinter/test_text.py
+++ b/Lib/tkinter/test/test_tkinter/test_text.py
@@ -1,19 +1,16 @@
import unittest
import tkinter
from test.support import requires, run_unittest
-from tkinter.ttk import setup_master
+from tkinter.test.support import AbstractTkTest
requires('gui')
-class TextTest(unittest.TestCase):
+class TextTest(AbstractTkTest, unittest.TestCase):
def setUp(self):
- self.root = setup_master()
+ super().setUp()
self.text = tkinter.Text(self.root)
- def tearDown(self):
- self.text.destroy()
-
def test_debug(self):
text = self.text
olddebug = text.debug()
diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py
index 9d910ac..4b72943 100644
--- a/Lib/tkinter/test/test_tkinter/test_variables.py
+++ b/Lib/tkinter/test/test_tkinter/test_variables.py
@@ -1,6 +1,7 @@
import unittest
-from tkinter import Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tk
+from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
+ TclError)
class Var(Variable):
@@ -16,10 +17,10 @@ class Var(Variable):
class TestBase(unittest.TestCase):
def setUp(self):
- self.root = Tk()
+ self.root = Tcl()
def tearDown(self):
- self.root.destroy()
+ del self.root
class TestVariable(TestBase):
@@ -81,7 +82,7 @@ class TestVariable(TestBase):
self.root.setvar(b'var\x00name', "value")
def test_initialize(self):
- v = Var()
+ v = Var(self.root)
self.assertFalse(v.side_effect)
v.set("value")
self.assertTrue(v.side_effect)
@@ -159,16 +160,41 @@ class TestBooleanVar(TestBase):
def test_default(self):
v = BooleanVar(self.root)
- self.assertEqual(False, v.get())
+ self.assertIs(v.get(), False)
def test_get(self):
v = BooleanVar(self.root, True, "name")
- self.assertAlmostEqual(True, v.get())
+ self.assertIs(v.get(), True)
self.root.globalsetvar("name", "0")
- self.assertAlmostEqual(False, v.get())
+ self.assertIs(v.get(), False)
+ self.root.globalsetvar("name", 42 if self.root.wantobjects() else 1)
+ self.assertIs(v.get(), True)
+ self.root.globalsetvar("name", 0)
+ self.assertIs(v.get(), False)
+ self.root.globalsetvar("name", "on")
+ self.assertIs(v.get(), True)
+
+ def test_set(self):
+ true = 1 if self.root.wantobjects() else "1"
+ false = 0 if self.root.wantobjects() else "0"
+ v = BooleanVar(self.root, name="name")
+ v.set(True)
+ self.assertEqual(self.root.globalgetvar("name"), true)
+ v.set("0")
+ self.assertEqual(self.root.globalgetvar("name"), false)
+ v.set(42)
+ self.assertEqual(self.root.globalgetvar("name"), true)
+ v.set(0)
+ self.assertEqual(self.root.globalgetvar("name"), false)
+ v.set("on")
+ self.assertEqual(self.root.globalgetvar("name"), true)
def test_invalid_value_domain(self):
+ false = 0 if self.root.wantobjects() else "0"
v = BooleanVar(self.root, name="name")
+ with self.assertRaises(TclError):
+ v.set("value")
+ self.assertEqual(self.root.globalgetvar("name"), false)
self.root.globalsetvar("name", "value")
with self.assertRaises(ValueError):
v.get()
diff --git a/Lib/tkinter/test/test_tkinter/test_widgets.py b/Lib/tkinter/test/test_tkinter/test_widgets.py
index 6ef7750..8be0371 100644
--- a/Lib/tkinter/test/test_tkinter/test_widgets.py
+++ b/Lib/tkinter/test/test_tkinter/test_widgets.py
@@ -1,5 +1,6 @@
import unittest
import tkinter
+from tkinter import TclError
import os
import sys
from test.support import requires
@@ -65,7 +66,7 @@ class ToplevelTest(AbstractToplevelTest, unittest.TestCase):
'takefocus', 'use', 'visual', 'width',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Toplevel(self.root, **kwargs)
def test_menu(self):
@@ -104,7 +105,7 @@ class FrameTest(AbstractToplevelTest, unittest.TestCase):
'relief', 'takefocus', 'visual', 'width',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Frame(self.root, **kwargs)
@@ -119,7 +120,7 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
'takefocus', 'text', 'visual', 'width',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.LabelFrame(self.root, **kwargs)
def test_labelanchor(self):
@@ -157,7 +158,7 @@ class LabelTest(AbstractLabelTest, unittest.TestCase):
'underline', 'width', 'wraplength',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Label(self.root, **kwargs)
@@ -174,7 +175,7 @@ class ButtonTest(AbstractLabelTest, unittest.TestCase):
'state', 'takefocus', 'text', 'textvariable',
'underline', 'width', 'wraplength')
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Button(self.root, **kwargs)
def test_default(self):
@@ -198,7 +199,7 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
'underline', 'variable', 'width', 'wraplength',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Checkbutton(self.root, **kwargs)
@@ -226,7 +227,7 @@ class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):
'underline', 'value', 'variable', 'width', 'wraplength',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Radiobutton(self.root, **kwargs)
def test_value(self):
@@ -249,7 +250,7 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
)
_conv_pixels = staticmethod(pixels_round)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Menubutton(self.root, **kwargs)
def test_direction(self):
@@ -267,7 +268,7 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
'crashes with Cocoa Tk (issue19733)')
def test_image(self):
widget = self.create()
- image = tkinter.PhotoImage('image1')
+ image = tkinter.PhotoImage(master=self.root, name='image1')
self.checkParam(widget, 'image', image, conv=str)
errmsg = 'image "spam" doesn\'t exist'
with self.assertRaises(tkinter.TclError) as cm:
@@ -302,7 +303,7 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
class OptionMenuTest(MenubuttonTest, unittest.TestCase):
- def _create(self, default='b', values=('a', 'b', 'c'), **kwargs):
+ def create(self, default='b', values=('a', 'b', 'c'), **kwargs):
return tkinter.OptionMenu(self.root, None, default, *values, **kwargs)
@@ -321,7 +322,7 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
'validate', 'validatecommand', 'width', 'xscrollcommand',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Entry(self.root, **kwargs)
def test_disabledbackground(self):
@@ -395,7 +396,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
'width', 'wrap', 'xscrollcommand',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Spinbox(self.root, **kwargs)
test_show = None
@@ -466,11 +467,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
def test_bbox(self):
widget = self.create()
- bbox = widget.bbox(0)
- self.assertEqual(len(bbox), 4)
- for item in bbox:
- self.assertIsInstance(item, int)
-
+ self.assertIsBoundingBox(widget.bbox(0))
self.assertRaises(tkinter.TclError, widget.bbox, 'noindex')
self.assertRaises(tkinter.TclError, widget.bbox, None)
self.assertRaises(TypeError, widget.bbox)
@@ -493,9 +490,9 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
'xscrollcommand', 'yscrollcommand',
)
if tcl_version < (8, 5):
- wantobjects = False
+ _stringify = True
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Text(self.root, **kwargs)
def test_autoseparators(self):
@@ -623,16 +620,12 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
def test_bbox(self):
widget = self.create()
- bbox = widget.bbox('1.1')
- self.assertEqual(len(bbox), 4)
- for item in bbox:
- self.assertIsInstance(item, int)
-
+ self.assertIsBoundingBox(widget.bbox('1.1'))
self.assertIsNone(widget.bbox('end'))
self.assertRaises(tkinter.TclError, widget.bbox, 'noindex')
self.assertRaises(tkinter.TclError, widget.bbox, None)
- self.assertRaises(tkinter.TclError, widget.bbox)
- self.assertRaises(tkinter.TclError, widget.bbox, '1.1', 'end')
+ self.assertRaises(TypeError, widget.bbox)
+ self.assertRaises(TypeError, widget.bbox, '1.1', 'end')
@add_standard_options(PixelSizeTests, StandardOptionsTests)
@@ -651,9 +644,9 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
)
_conv_pixels = round
- wantobjects = False
+ _stringify = True
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Canvas(self.root, **kwargs)
def test_closeenough(self):
@@ -706,7 +699,7 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase):
'takefocus', 'width', 'xscrollcommand', 'yscrollcommand',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Listbox(self.root, **kwargs)
def test_activestyle(self):
@@ -716,7 +709,7 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase):
def test_listvariable(self):
widget = self.create()
- var = tkinter.DoubleVar()
+ var = tkinter.DoubleVar(self.root)
self.checkVariableParam(widget, 'listvariable', var)
def test_selectmode(self):
@@ -730,6 +723,101 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase):
widget = self.create()
self.checkEnumParam(widget, 'state', 'disabled', 'normal')
+ def test_itemconfigure(self):
+ widget = self.create()
+ with self.assertRaisesRegex(TclError, 'item number "0" out of range'):
+ widget.itemconfigure(0)
+ colors = 'red orange yellow green blue white violet'.split()
+ widget.insert('end', *colors)
+ for i, color in enumerate(colors):
+ widget.itemconfigure(i, background=color)
+ with self.assertRaises(TypeError):
+ widget.itemconfigure()
+ with self.assertRaisesRegex(TclError, 'bad listbox index "red"'):
+ widget.itemconfigure('red')
+ self.assertEqual(widget.itemconfigure(0, 'background'),
+ ('background', 'background', 'Background', '', 'red'))
+ self.assertEqual(widget.itemconfigure('end', 'background'),
+ ('background', 'background', 'Background', '', 'violet'))
+ self.assertEqual(widget.itemconfigure('@0,0', 'background'),
+ ('background', 'background', 'Background', '', 'red'))
+
+ d = widget.itemconfigure(0)
+ self.assertIsInstance(d, dict)
+ for k, v in d.items():
+ self.assertIn(len(v), (2, 5))
+ if len(v) == 5:
+ self.assertEqual(v, widget.itemconfigure(0, k))
+ self.assertEqual(v[4], widget.itemcget(0, k))
+
+ def check_itemconfigure(self, name, value):
+ widget = self.create()
+ widget.insert('end', 'a', 'b', 'c', 'd')
+ widget.itemconfigure(0, **{name: value})
+ self.assertEqual(widget.itemconfigure(0, name)[4], value)
+ self.assertEqual(widget.itemcget(0, name), value)
+ with self.assertRaisesRegex(TclError, 'unknown color name "spam"'):
+ widget.itemconfigure(0, **{name: 'spam'})
+
+ def test_itemconfigure_background(self):
+ self.check_itemconfigure('background', '#ff0000')
+
+ def test_itemconfigure_bg(self):
+ self.check_itemconfigure('bg', '#ff0000')
+
+ def test_itemconfigure_fg(self):
+ self.check_itemconfigure('fg', '#110022')
+
+ def test_itemconfigure_foreground(self):
+ self.check_itemconfigure('foreground', '#110022')
+
+ def test_itemconfigure_selectbackground(self):
+ self.check_itemconfigure('selectbackground', '#110022')
+
+ def test_itemconfigure_selectforeground(self):
+ self.check_itemconfigure('selectforeground', '#654321')
+
+ def test_box(self):
+ lb = self.create()
+ lb.insert(0, *('el%d' % i for i in range(8)))
+ lb.pack()
+ self.assertIsBoundingBox(lb.bbox(0))
+ self.assertIsNone(lb.bbox(-1))
+ self.assertIsNone(lb.bbox(10))
+ self.assertRaises(TclError, lb.bbox, 'noindex')
+ self.assertRaises(TclError, lb.bbox, None)
+ self.assertRaises(TypeError, lb.bbox)
+ self.assertRaises(TypeError, lb.bbox, 0, 1)
+
+ def test_curselection(self):
+ lb = self.create()
+ lb.insert(0, *('el%d' % i for i in range(8)))
+ lb.selection_clear(0, tkinter.END)
+ lb.selection_set(2, 4)
+ lb.selection_set(6)
+ self.assertEqual(lb.curselection(), (2, 3, 4, 6))
+ self.assertRaises(TypeError, lb.curselection, 0)
+
+ def test_get(self):
+ lb = self.create()
+ lb.insert(0, *('el%d' % i for i in range(8)))
+ self.assertEqual(lb.get(0), 'el0')
+ self.assertEqual(lb.get(3), 'el3')
+ self.assertEqual(lb.get('end'), 'el7')
+ self.assertEqual(lb.get(8), '')
+ self.assertEqual(lb.get(-1), '')
+ self.assertEqual(lb.get(3, 5), ('el3', 'el4', 'el5'))
+ self.assertEqual(lb.get(5, 'end'), ('el5', 'el6', 'el7'))
+ self.assertEqual(lb.get(5, 0), ())
+ self.assertEqual(lb.get(0, 0), ('el0',))
+ self.assertRaises(TclError, lb.get, 'noindex')
+ self.assertRaises(TclError, lb.get, None)
+ self.assertRaises(TypeError, lb.get)
+ self.assertRaises(TclError, lb.get, 'end', 'noindex')
+ self.assertRaises(TypeError, lb.get, 1, 2, 3)
+ self.assertRaises(TclError, lb.get, 2.4)
+
+
@add_standard_options(PixelSizeTests, StandardOptionsTests)
class ScaleTest(AbstractWidgetTest, unittest.TestCase):
OPTIONS = (
@@ -743,7 +831,7 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
)
default_orient = 'vertical'
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Scale(self.root, **kwargs)
def test_bigincrement(self):
@@ -809,10 +897,10 @@ class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):
'takefocus', 'troughcolor', 'width',
)
_conv_pixels = round
- wantobjects = False
+ _stringify = True
default_orient = 'vertical'
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Scrollbar(self.root, **kwargs)
def test_activerelief(self):
@@ -828,6 +916,24 @@ class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):
self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal',
errmsg='bad orientation "{}": must be vertical or horizontal')
+ def test_activate(self):
+ sb = self.create()
+ for e in ('arrow1', 'slider', 'arrow2'):
+ sb.activate(e)
+ sb.activate('')
+ self.assertRaises(TypeError, sb.activate)
+ self.assertRaises(TypeError, sb.activate, 'arrow1', 'arrow2')
+
+ def test_set(self):
+ sb = self.create()
+ sb.set(0.2, 0.4)
+ self.assertEqual(sb.get(), (0.2, 0.4))
+ self.assertRaises(TclError, sb.set, 'abc', 'def')
+ self.assertRaises(TclError, sb.set, 0.6, 'def')
+ self.assertRaises(TclError, sb.set, 0.6, None)
+ self.assertRaises(TclError, sb.set, 0.6)
+ self.assertRaises(TclError, sb.set, 0.6, 0.7, 0.8)
+
@add_standard_options(StandardOptionsTests)
class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
@@ -840,7 +946,7 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
)
default_orient = 'horizontal'
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.PanedWindow(self.root, **kwargs)
def test_handlepad(self):
@@ -887,6 +993,105 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i',
conv=noconv)
+ def create2(self):
+ p = self.create()
+ b = tkinter.Button(p)
+ c = tkinter.Button(p)
+ p.add(b)
+ p.add(c)
+ return p, b, c
+
+ def test_paneconfigure(self):
+ p, b, c = self.create2()
+ self.assertRaises(TypeError, p.paneconfigure)
+ d = p.paneconfigure(b)
+ self.assertIsInstance(d, dict)
+ for k, v in d.items():
+ self.assertEqual(len(v), 5)
+ self.assertEqual(v, p.paneconfigure(b, k))
+ self.assertEqual(v[4], p.panecget(b, k))
+
+ def check_paneconfigure(self, p, b, name, value, expected, stringify=False):
+ conv = lambda x: x
+ if not self.wantobjects or stringify:
+ expected = str(expected)
+ if self.wantobjects and stringify:
+ conv = str
+ p.paneconfigure(b, **{name: value})
+ self.assertEqual(conv(p.paneconfigure(b, name)[4]), expected)
+ self.assertEqual(conv(p.panecget(b, name)), expected)
+
+ def check_paneconfigure_bad(self, p, b, name, msg):
+ with self.assertRaisesRegex(TclError, msg):
+ p.paneconfigure(b, **{name: 'badValue'})
+
+ def test_paneconfigure_after(self):
+ p, b, c = self.create2()
+ self.check_paneconfigure(p, b, 'after', c, str(c))
+ self.check_paneconfigure_bad(p, b, 'after',
+ 'bad window path name "badValue"')
+
+ def test_paneconfigure_before(self):
+ p, b, c = self.create2()
+ self.check_paneconfigure(p, b, 'before', c, str(c))
+ self.check_paneconfigure_bad(p, b, 'before',
+ 'bad window path name "badValue"')
+
+ def test_paneconfigure_height(self):
+ p, b, c = self.create2()
+ self.check_paneconfigure(p, b, 'height', 10, 10,
+ stringify=get_tk_patchlevel() < (8, 5, 11))
+ self.check_paneconfigure_bad(p, b, 'height',
+ 'bad screen distance "badValue"')
+
+ @requires_tcl(8, 5)
+ def test_paneconfigure_hide(self):
+ p, b, c = self.create2()
+ self.check_paneconfigure(p, b, 'hide', False, 0)
+ self.check_paneconfigure_bad(p, b, 'hide',
+ 'expected boolean value but got "badValue"')
+
+ def test_paneconfigure_minsize(self):
+ p, b, c = self.create2()
+ self.check_paneconfigure(p, b, 'minsize', 10, 10)
+ self.check_paneconfigure_bad(p, b, 'minsize',
+ 'bad screen distance "badValue"')
+
+ def test_paneconfigure_padx(self):
+ p, b, c = self.create2()
+ self.check_paneconfigure(p, b, 'padx', 1.3, 1)
+ self.check_paneconfigure_bad(p, b, 'padx',
+ 'bad screen distance "badValue"')
+
+ def test_paneconfigure_pady(self):
+ p, b, c = self.create2()
+ self.check_paneconfigure(p, b, 'pady', 1.3, 1)
+ self.check_paneconfigure_bad(p, b, 'pady',
+ 'bad screen distance "badValue"')
+
+ def test_paneconfigure_sticky(self):
+ p, b, c = self.create2()
+ self.check_paneconfigure(p, b, 'sticky', 'nsew', 'nesw')
+ self.check_paneconfigure_bad(p, b, 'sticky',
+ 'bad stickyness value "badValue": must '
+ 'be a string containing zero or more of '
+ 'n, e, s, and w')
+
+ @requires_tcl(8, 5)
+ def test_paneconfigure_stretch(self):
+ p, b, c = self.create2()
+ self.check_paneconfigure(p, b, 'stretch', 'alw', 'always')
+ self.check_paneconfigure_bad(p, b, 'stretch',
+ 'bad stretch "badValue": must be '
+ 'always, first, last, middle, or never')
+
+ def test_paneconfigure_width(self):
+ p, b, c = self.create2()
+ self.check_paneconfigure(p, b, 'width', 10, 10,
+ stringify=get_tk_patchlevel() < (8, 5, 11))
+ self.check_paneconfigure_bad(p, b, 'width',
+ 'bad screen distance "badValue"')
+
@add_standard_options(StandardOptionsTests)
class MenuTest(AbstractWidgetTest, unittest.TestCase):
@@ -899,7 +1104,7 @@ class MenuTest(AbstractWidgetTest, unittest.TestCase):
)
_conv_pixels = noconv
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Menu(self.root, **kwargs)
def test_postcommand(self):
@@ -923,6 +1128,39 @@ class MenuTest(AbstractWidgetTest, unittest.TestCase):
self.checkEnumParam(widget, 'type',
'normal', 'tearoff', 'menubar')
+ def test_entryconfigure(self):
+ m1 = self.create()
+ m1.add_command(label='test')
+ self.assertRaises(TypeError, m1.entryconfigure)
+ with self.assertRaisesRegex(TclError, 'bad menu entry index "foo"'):
+ m1.entryconfigure('foo')
+ d = m1.entryconfigure(1)
+ self.assertIsInstance(d, dict)
+ for k, v in d.items():
+ self.assertIsInstance(k, str)
+ self.assertIsInstance(v, tuple)
+ self.assertEqual(len(v), 5)
+ self.assertEqual(v[0], k)
+ self.assertEqual(m1.entrycget(1, k), v[4])
+ m1.destroy()
+
+ def test_entryconfigure_label(self):
+ m1 = self.create()
+ m1.add_command(label='test')
+ self.assertEqual(m1.entrycget(1, 'label'), 'test')
+ m1.entryconfigure(1, label='changed')
+ self.assertEqual(m1.entrycget(1, 'label'), 'changed')
+
+ def test_entryconfigure_variable(self):
+ m1 = self.create()
+ v1 = tkinter.BooleanVar(self.root)
+ v2 = tkinter.BooleanVar(self.root)
+ m1.add_checkbutton(variable=v1, onvalue=True, offvalue=False,
+ label='Nonsense')
+ self.assertEqual(str(m1.entrycget(1, 'variable')), str(v1))
+ m1.entryconfigure(1, variable=v2)
+ self.assertEqual(str(m1.entrycget(1, 'variable')), str(v2))
+
@add_standard_options(PixelSizeTests, StandardOptionsTests)
class MessageTest(AbstractWidgetTest, unittest.TestCase):
@@ -935,7 +1173,7 @@ class MessageTest(AbstractWidgetTest, unittest.TestCase):
)
_conv_pad_pixels = noconv
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return tkinter.Message(self.root, **kwargs)
def test_aspect(self):
diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py
index d699546..c3af06c 100644
--- a/Lib/tkinter/test/test_ttk/test_extensions.py
+++ b/Lib/tkinter/test/test_ttk/test_extensions.py
@@ -2,34 +2,30 @@ import sys
import unittest
import tkinter
from tkinter import ttk
-from test.support import requires, run_unittest
-
-import tkinter.test.support as support
+from test.support import requires, run_unittest, swap_attr
+from tkinter.test.support import AbstractTkTest, destroy_default_root
requires('gui')
-class LabeledScaleTest(unittest.TestCase):
-
- def setUp(self):
- support.root_deiconify()
+class LabeledScaleTest(AbstractTkTest, unittest.TestCase):
def tearDown(self):
- support.root_withdraw()
-
+ self.root.update_idletasks()
+ super().tearDown()
def test_widget_destroy(self):
# automatically created variable
- x = ttk.LabeledScale()
+ x = ttk.LabeledScale(self.root)
var = x._variable._name
x.destroy()
self.assertRaises(tkinter.TclError, x.tk.globalgetvar, var)
# manually created variable
- myvar = tkinter.DoubleVar()
+ myvar = tkinter.DoubleVar(self.root)
name = myvar._name
- x = ttk.LabeledScale(variable=myvar)
+ x = ttk.LabeledScale(self.root, variable=myvar)
x.destroy()
- if x.tk.wantobjects():
+ if self.wantobjects:
self.assertEqual(x.tk.globalgetvar(name), myvar.get())
else:
self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get())
@@ -37,26 +33,36 @@ class LabeledScaleTest(unittest.TestCase):
self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name)
# checking that the tracing callback is properly removed
- myvar = tkinter.IntVar()
+ myvar = tkinter.IntVar(self.root)
# LabeledScale will start tracing myvar
- x = ttk.LabeledScale(variable=myvar)
+ x = ttk.LabeledScale(self.root, variable=myvar)
x.destroy()
# Unless the tracing callback was removed, creating a new
# LabeledScale with the same var will cause an error now. This
# happens because the variable will be set to (possibly) a new
# value which causes the tracing callback to be called and then
# it tries calling instance attributes not yet defined.
- ttk.LabeledScale(variable=myvar)
+ ttk.LabeledScale(self.root, variable=myvar)
if hasattr(sys, 'last_type'):
self.assertNotEqual(sys.last_type, tkinter.TclError)
+ def test_initialization_no_master(self):
+ # no master passing
+ with swap_attr(tkinter, '_default_root', None), \
+ swap_attr(tkinter, '_support_default_root', True):
+ try:
+ x = ttk.LabeledScale()
+ self.assertIsNotNone(tkinter._default_root)
+ self.assertEqual(x.master, tkinter._default_root)
+ self.assertEqual(x.tk, tkinter._default_root.tk)
+ x.destroy()
+ finally:
+ destroy_default_root()
+
def test_initialization(self):
# master passing
- x = ttk.LabeledScale()
- self.assertEqual(x.master, tkinter._default_root)
- x.destroy()
- master = tkinter.Frame()
+ master = tkinter.Frame(self.root)
x = ttk.LabeledScale(master)
self.assertEqual(x.master, master)
x.destroy()
@@ -64,25 +70,25 @@ class LabeledScaleTest(unittest.TestCase):
# variable initialization/passing
passed_expected = (('0', 0), (0, 0), (10, 10),
(-1, -1), (sys.maxsize + 1, sys.maxsize + 1))
- if x.tk.wantobjects():
+ if self.wantobjects:
passed_expected += ((2.5, 2),)
for pair in passed_expected:
- x = ttk.LabeledScale(from_=pair[0])
+ x = ttk.LabeledScale(self.root, from_=pair[0])
self.assertEqual(x.value, pair[1])
x.destroy()
- x = ttk.LabeledScale(from_='2.5')
+ x = ttk.LabeledScale(self.root, from_='2.5')
self.assertRaises(ValueError, x._variable.get)
x.destroy()
- x = ttk.LabeledScale(from_=None)
+ x = ttk.LabeledScale(self.root, from_=None)
self.assertRaises(ValueError, x._variable.get)
x.destroy()
# variable should have its default value set to the from_ value
- myvar = tkinter.DoubleVar(value=20)
- x = ttk.LabeledScale(variable=myvar)
+ myvar = tkinter.DoubleVar(self.root, value=20)
+ x = ttk.LabeledScale(self.root, variable=myvar)
self.assertEqual(x.value, 0)
x.destroy()
# check that it is really using a DoubleVar
- x = ttk.LabeledScale(variable=myvar, from_=0.5)
+ x = ttk.LabeledScale(self.root, variable=myvar, from_=0.5)
self.assertEqual(x.value, 0.5)
self.assertEqual(x._variable._name, myvar._name)
x.destroy()
@@ -91,25 +97,26 @@ class LabeledScaleTest(unittest.TestCase):
def check_positions(scale, scale_pos, label, label_pos):
self.assertEqual(scale.pack_info()['side'], scale_pos)
self.assertEqual(label.place_info()['anchor'], label_pos)
- x = ttk.LabeledScale(compound='top')
+ x = ttk.LabeledScale(self.root, compound='top')
check_positions(x.scale, 'bottom', x.label, 'n')
x.destroy()
- x = ttk.LabeledScale(compound='bottom')
+ x = ttk.LabeledScale(self.root, compound='bottom')
check_positions(x.scale, 'top', x.label, 's')
x.destroy()
- x = ttk.LabeledScale(compound='unknown') # invert default positions
+ # invert default positions
+ x = ttk.LabeledScale(self.root, compound='unknown')
check_positions(x.scale, 'top', x.label, 's')
x.destroy()
- x = ttk.LabeledScale() # take default positions
+ x = ttk.LabeledScale(self.root) # take default positions
check_positions(x.scale, 'bottom', x.label, 'n')
x.destroy()
# extra, and invalid, kwargs
- self.assertRaises(tkinter.TclError, ttk.LabeledScale, a='b')
+ self.assertRaises(tkinter.TclError, ttk.LabeledScale, master, a='b')
def test_horizontal_range(self):
- lscale = ttk.LabeledScale(from_=0, to=10)
+ lscale = ttk.LabeledScale(self.root, from_=0, to=10)
lscale.pack()
lscale.wait_visibility()
lscale.update()
@@ -128,7 +135,7 @@ class LabeledScaleTest(unittest.TestCase):
self.assertNotEqual(prev_xcoord, curr_xcoord)
# the label widget should have been repositioned too
linfo_2 = lscale.label.place_info()
- self.assertEqual(lscale.label['text'], 0 if lscale.tk.wantobjects() else '0')
+ self.assertEqual(lscale.label['text'], 0 if self.wantobjects else '0')
self.assertEqual(curr_xcoord, int(linfo_2['x']))
# change the range back
lscale.scale.configure(from_=0, to=10)
@@ -139,7 +146,7 @@ class LabeledScaleTest(unittest.TestCase):
def test_variable_change(self):
- x = ttk.LabeledScale()
+ x = ttk.LabeledScale(self.root)
x.pack()
x.wait_visibility()
x.update()
@@ -151,13 +158,13 @@ class LabeledScaleTest(unittest.TestCase):
# at the same time this shouldn't affect test outcome
x.update()
self.assertEqual(x.label['text'],
- newval if x.tk.wantobjects() else str(newval))
+ newval if self.wantobjects else str(newval))
self.assertGreater(x.scale.coords()[0], curr_xcoord)
self.assertEqual(x.scale.coords()[0],
int(x.label.place_info()['x']))
# value outside range
- if x.tk.wantobjects():
+ if self.wantobjects:
conv = lambda x: x
else:
conv = int
@@ -171,7 +178,7 @@ class LabeledScaleTest(unittest.TestCase):
def test_resize(self):
- x = ttk.LabeledScale()
+ x = ttk.LabeledScale(self.root)
x.pack(expand=True, fill='both')
x.wait_visibility()
x.update()
@@ -190,20 +197,20 @@ class LabeledScaleTest(unittest.TestCase):
x.destroy()
-class OptionMenuTest(unittest.TestCase):
+class OptionMenuTest(AbstractTkTest, unittest.TestCase):
def setUp(self):
- support.root_deiconify()
- self.textvar = tkinter.StringVar()
+ super().setUp()
+ self.textvar = tkinter.StringVar(self.root)
def tearDown(self):
del self.textvar
- support.root_withdraw()
+ super().tearDown()
def test_widget_destroy(self):
- var = tkinter.StringVar()
- optmenu = ttk.OptionMenu(None, var)
+ var = tkinter.StringVar(self.root)
+ optmenu = ttk.OptionMenu(self.root, var)
name = var._name
optmenu.update_idletasks()
optmenu.destroy()
@@ -214,9 +221,9 @@ class OptionMenuTest(unittest.TestCase):
def test_initialization(self):
self.assertRaises(tkinter.TclError,
- ttk.OptionMenu, None, self.textvar, invalid='thing')
+ ttk.OptionMenu, self.root, self.textvar, invalid='thing')
- optmenu = ttk.OptionMenu(None, self.textvar, 'b', 'a', 'b')
+ optmenu = ttk.OptionMenu(self.root, self.textvar, 'b', 'a', 'b')
self.assertEqual(optmenu._variable.get(), 'b')
self.assertTrue(optmenu['menu'])
@@ -228,7 +235,7 @@ class OptionMenuTest(unittest.TestCase):
def test_menu(self):
items = ('a', 'b', 'c')
default = 'a'
- optmenu = ttk.OptionMenu(None, self.textvar, default, *items)
+ optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items)
found_default = False
for i in range(len(items)):
value = optmenu['menu'].entrycget(i, 'value')
@@ -240,7 +247,7 @@ class OptionMenuTest(unittest.TestCase):
# default shouldn't be in menu if it is not part of values
default = 'd'
- optmenu = ttk.OptionMenu(None, self.textvar, default, *items)
+ optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items)
curr = None
i = 0
while True:
@@ -269,7 +276,7 @@ class OptionMenuTest(unittest.TestCase):
def cb_test(item):
self.assertEqual(item, items[1])
success.append(True)
- optmenu = ttk.OptionMenu(None, self.textvar, 'a', command=cb_test,
+ optmenu = ttk.OptionMenu(self.root, self.textvar, 'a', command=cb_test,
*items)
optmenu['menu'].invoke(1)
if not success:
diff --git a/Lib/tkinter/test/test_ttk/test_functions.py b/Lib/tkinter/test/test_ttk/test_functions.py
index 1986e66..c9dcf97 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'
@@ -312,26 +324,13 @@ class InternalFunctionsTest(unittest.TestCase):
"-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):
@@ -352,20 +351,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 +379,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 +388,35 @@ 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
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
+
+ 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(options, func), options)
+ self.assertEqual(ttk._val_or_dict(tk, {'test': 3}, 'x:y'),
+ {'test': 3})
def test_convert_stringval(self):
diff --git a/Lib/tkinter/test/test_ttk/test_style.py b/Lib/tkinter/test/test_ttk/test_style.py
index 0da0e5d..3537536 100644
--- a/Lib/tkinter/test/test_ttk/test_style.py
+++ b/Lib/tkinter/test/test_ttk/test_style.py
@@ -2,15 +2,15 @@ import unittest
import tkinter
from tkinter import ttk
from test.support import requires, run_unittest
-
-import tkinter.test.support as support
+from tkinter.test.support import AbstractTkTest
requires('gui')
-class StyleTest(unittest.TestCase):
+class StyleTest(AbstractTkTest, unittest.TestCase):
def setUp(self):
- self.style = ttk.Style()
+ super().setUp()
+ self.style = ttk.Style(self.root)
def test_configure(self):
@@ -25,7 +25,7 @@ class StyleTest(unittest.TestCase):
style = self.style
style.map('TButton', background=[('active', 'background', 'blue')])
self.assertEqual(style.map('TButton', 'background'),
- [('active', 'background', 'blue')] if style.tk.wantobjects() else
+ [('active', 'background', 'blue')] if self.wantobjects else
[('active background', 'blue')])
self.assertIsInstance(style.map('TButton'), dict)
diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py
index 3ac14be..afd3230 100644
--- a/Lib/tkinter/test/test_ttk/test_widgets.py
+++ b/Lib/tkinter/test/test_ttk/test_widgets.py
@@ -1,12 +1,12 @@
import unittest
import tkinter
-from tkinter import ttk
+from tkinter import ttk, TclError
from test.support import requires
import sys
-import tkinter.test.support as support
from tkinter.test.test_ttk.test_functions import MockTclObj
-from tkinter.test.support import tcl_version, get_tk_patchlevel
+from tkinter.test.support import (AbstractTkTest, tcl_version, get_tk_patchlevel,
+ simulate_mouse_click)
from tkinter.test.widget_tests import (add_standard_options, noconv,
AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests,
setUpModule)
@@ -20,7 +20,7 @@ class StandardTtkOptionsTests(StandardOptionsTests):
widget = self.create()
self.assertEqual(widget['class'], '')
errmsg='attempt to change read-only option'
- if get_tk_patchlevel() < (8, 6, 0): # actually this was changed in 8.6b3
+ if get_tk_patchlevel() < (8, 6, 0, 'beta', 3):
errmsg='Attempt to change read-only option'
self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg)
widget2 = self.create(class_='Foo')
@@ -53,19 +53,15 @@ class StandardTtkOptionsTests(StandardOptionsTests):
pass
-class WidgetTest(unittest.TestCase):
+class WidgetTest(AbstractTkTest, unittest.TestCase):
"""Tests methods available in every ttk widget."""
def setUp(self):
- support.root_deiconify()
- self.widget = ttk.Button(width=0, text="Text")
+ super().setUp()
+ self.widget = ttk.Button(self.root, width=0, text="Text")
self.widget.pack()
self.widget.wait_visibility()
- def tearDown(self):
- self.widget.destroy()
- support.root_withdraw()
-
def test_identify(self):
self.widget.update_idletasks()
@@ -128,7 +124,7 @@ class FrameTest(AbstractToplevelTest, unittest.TestCase):
'width',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Frame(self.root, **kwargs)
@@ -141,7 +137,7 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
'text', 'underline', 'width',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.LabelFrame(self.root, **kwargs)
def test_labelanchor(self):
@@ -161,8 +157,8 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
class AbstractLabelTest(AbstractWidgetTest):
def checkImageParam(self, widget, name):
- image = tkinter.PhotoImage('image1')
- image2 = tkinter.PhotoImage('image2')
+ image = tkinter.PhotoImage(master=self.root, name='image1')
+ image2 = tkinter.PhotoImage(master=self.root, name='image2')
self.checkParam(widget, name, image, expected=('image1',))
self.checkParam(widget, name, 'image1', expected=('image1',))
self.checkParam(widget, name, (image,), expected=('image1',))
@@ -199,7 +195,7 @@ class LabelTest(AbstractLabelTest, unittest.TestCase):
)
_conv_pixels = noconv
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Label(self.root, **kwargs)
def test_font(self):
@@ -216,7 +212,7 @@ class ButtonTest(AbstractLabelTest, unittest.TestCase):
'underline', 'width',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Button(self.root, **kwargs)
def test_default(self):
@@ -225,7 +221,7 @@ class ButtonTest(AbstractLabelTest, unittest.TestCase):
def test_invoke(self):
success = []
- btn = ttk.Button(command=lambda: success.append(1))
+ btn = ttk.Button(self.root, command=lambda: success.append(1))
btn.invoke()
self.assertTrue(success)
@@ -241,7 +237,7 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
'underline', 'variable', 'width',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Checkbutton(self.root, **kwargs)
def test_offvalue(self):
@@ -258,7 +254,7 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
success.append(1)
return "cb test called"
- cbtn = ttk.Checkbutton(command=cb_test)
+ cbtn = ttk.Checkbutton(self.root, command=cb_test)
# the variable automatically created by ttk.Checkbutton is actually
# undefined till we invoke the Checkbutton
self.assertEqual(cbtn.state(), ('alternate', ))
@@ -289,15 +285,9 @@ class ComboboxTest(AbstractWidgetTest, unittest.TestCase):
def setUp(self):
super().setUp()
- support.root_deiconify()
self.combo = self.create()
- def tearDown(self):
- self.combo.destroy()
- support.root_withdraw()
- super().tearDown()
-
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Combobox(self.root, **kwargs)
def test_height(self):
@@ -362,7 +352,8 @@ class ComboboxTest(AbstractWidgetTest, unittest.TestCase):
expected=('mon', 'tue', 'wed', 'thur'))
self.checkParam(self.combo, 'values', ('mon', 'tue', 'wed', 'thur'))
self.checkParam(self.combo, 'values', (42, 3.14, '', 'any string'))
- self.checkParam(self.combo, 'values', '', expected=())
+ self.checkParam(self.combo, 'values', '',
+ expected='' if get_tk_patchlevel() < (8, 5, 10) else ())
self.combo['values'] = ['a', 1, 'c']
@@ -405,7 +396,7 @@ class ComboboxTest(AbstractWidgetTest, unittest.TestCase):
self.assertRaises(tkinter.TclError, self.combo.current, '')
# testing creating combobox with empty string in values
- combo2 = ttk.Combobox(values=[1, 2, ''])
+ combo2 = ttk.Combobox(self.root, values=[1, 2, ''])
self.assertEqual(combo2['values'],
('1', '2', '') if self.wantobjects else '1 2 {}')
combo2.destroy()
@@ -423,15 +414,9 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
def setUp(self):
super().setUp()
- support.root_deiconify()
self.entry = self.create()
- def tearDown(self):
- self.entry.destroy()
- support.root_withdraw()
- super().tearDown()
-
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Entry(self.root, **kwargs)
def test_invalidcommand(self):
@@ -460,10 +445,7 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
def test_bbox(self):
- self.assertEqual(len(self.entry.bbox(0)), 4)
- for item in self.entry.bbox(0):
- self.assertIsInstance(item, int)
-
+ self.assertIsBoundingBox(self.entry.bbox(0))
self.assertRaises(tkinter.TclError, self.entry.bbox, 'noindex')
self.assertRaises(tkinter.TclError, self.entry.bbox, None)
@@ -561,22 +543,16 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
def setUp(self):
super().setUp()
- support.root_deiconify()
self.paned = self.create()
- def tearDown(self):
- self.paned.destroy()
- support.root_withdraw()
- super().tearDown()
-
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.PanedWindow(self.root, **kwargs)
def test_orient(self):
widget = self.create()
self.assertEqual(str(widget['orient']), 'vertical')
errmsg='attempt to change read-only option'
- if get_tk_patchlevel() < (8, 6, 0): # actually this was changed in 8.6b3
+ if get_tk_patchlevel() < (8, 6, 0, 'beta', 3):
errmsg='Attempt to change read-only option'
self.checkInvalidParam(widget, 'orient', 'horizontal',
errmsg=errmsg)
@@ -591,13 +567,13 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
label.destroy()
child.destroy()
# another attempt
- label = ttk.Label()
+ label = ttk.Label(self.root)
child = ttk.Label(label)
self.assertRaises(tkinter.TclError, self.paned.add, child)
child.destroy()
label.destroy()
- good_child = ttk.Label()
+ good_child = ttk.Label(self.root)
self.paned.add(good_child)
# re-adding a child is not accepted
self.assertRaises(tkinter.TclError, self.paned.add, good_child)
@@ -615,7 +591,7 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
self.assertRaises(tkinter.TclError, self.paned.forget, None)
self.assertRaises(tkinter.TclError, self.paned.forget, 0)
- self.paned.add(ttk.Label())
+ self.paned.add(ttk.Label(self.root))
self.paned.forget(0)
self.assertRaises(tkinter.TclError, self.paned.forget, 0)
@@ -625,9 +601,9 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
self.assertRaises(tkinter.TclError, self.paned.insert, 0, None)
self.assertRaises(tkinter.TclError, self.paned.insert, 0, 0)
- child = ttk.Label()
- child2 = ttk.Label()
- child3 = ttk.Label()
+ child = ttk.Label(self.root)
+ child2 = ttk.Label(self.root)
+ child3 = ttk.Label(self.root)
self.assertRaises(tkinter.TclError, self.paned.insert, 0, child)
@@ -658,7 +634,7 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
def test_pane(self):
self.assertRaises(tkinter.TclError, self.paned.pane, 0)
- child = ttk.Label()
+ child = ttk.Label(self.root)
self.paned.add(child)
self.assertIsInstance(self.paned.pane(0), dict)
self.assertEqual(self.paned.pane(0, weight=None),
@@ -703,7 +679,7 @@ class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):
'underline', 'value', 'variable', 'width',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Radiobutton(self.root, **kwargs)
def test_value(self):
@@ -716,9 +692,11 @@ class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):
success.append(1)
return "cb test called"
- myvar = tkinter.IntVar()
- cbtn = ttk.Radiobutton(command=cb_test, variable=myvar, value=0)
- cbtn2 = ttk.Radiobutton(command=cb_test, variable=myvar, value=1)
+ myvar = tkinter.IntVar(self.root)
+ cbtn = ttk.Radiobutton(self.root, command=cb_test,
+ variable=myvar, value=0)
+ cbtn2 = ttk.Radiobutton(self.root, command=cb_test,
+ variable=myvar, value=1)
if self.wantobjects:
conv = lambda x: x
@@ -751,7 +729,7 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
'underline', 'width',
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Menubutton(self.root, **kwargs)
def test_direction(self):
@@ -777,17 +755,11 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
def setUp(self):
super().setUp()
- support.root_deiconify()
self.scale = self.create()
self.scale.pack()
self.scale.update()
- def tearDown(self):
- self.scale.destroy()
- support.root_withdraw()
- super().tearDown()
-
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Scale(self.root, **kwargs)
def test_from(self):
@@ -859,7 +831,7 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
self.assertEqual(conv(self.scale.get()), min)
# changing directly the variable doesn't impose this limitation tho
- var = tkinter.DoubleVar()
+ var = tkinter.DoubleVar(self.root)
self.scale['variable'] = var
var.set(max + 5)
self.assertEqual(conv(self.scale.get()), var.get())
@@ -889,7 +861,7 @@ class ProgressbarTest(AbstractWidgetTest, unittest.TestCase):
_conv_pixels = noconv
default_orient = 'horizontal'
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Progressbar(self.root, **kwargs)
def test_length(self):
@@ -923,7 +895,7 @@ class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):
)
default_orient = 'vertical'
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Scrollbar(self.root, **kwargs)
@@ -935,21 +907,13 @@ class NotebookTest(AbstractWidgetTest, unittest.TestCase):
def setUp(self):
super().setUp()
- support.root_deiconify()
self.nb = self.create(padding=0)
- self.child1 = ttk.Label()
- self.child2 = ttk.Label()
+ self.child1 = ttk.Label(self.root)
+ self.child2 = ttk.Label(self.root)
self.nb.add(self.child1, text='a')
self.nb.add(self.child2, text='b')
- def tearDown(self):
- self.child1.destroy()
- self.child2.destroy()
- self.nb.destroy()
- support.root_withdraw()
- super().tearDown()
-
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Notebook(self.root, **kwargs)
def test_tab_identifiers(self):
@@ -988,7 +952,7 @@ class NotebookTest(AbstractWidgetTest, unittest.TestCase):
self.assertRaises(tkinter.TclError, self.nb.hide, 'hi')
self.assertRaises(tkinter.TclError, self.nb.hide, None)
self.assertRaises(tkinter.TclError, self.nb.add, None)
- self.assertRaises(tkinter.TclError, self.nb.add, ttk.Label(),
+ self.assertRaises(tkinter.TclError, self.nb.add, ttk.Label(self.root),
unknown='option')
tabs = self.nb.tabs()
@@ -996,7 +960,7 @@ class NotebookTest(AbstractWidgetTest, unittest.TestCase):
self.nb.add(self.child1)
self.assertEqual(self.nb.tabs(), tabs)
- child = ttk.Label()
+ child = ttk.Label(self.root)
self.nb.add(child, text='c')
tabs = self.nb.tabs()
@@ -1054,7 +1018,7 @@ class NotebookTest(AbstractWidgetTest, unittest.TestCase):
self.assertRaises(tkinter.TclError, self.nb.insert, -1, tabs[0])
# new tab
- child3 = ttk.Label()
+ child3 = ttk.Label(self.root)
self.nb.insert(1, child3)
self.assertEqual(self.nb.tabs(), (tabs[0], str(child3), tabs[1]))
self.nb.forget(child3)
@@ -1120,7 +1084,7 @@ class NotebookTest(AbstractWidgetTest, unittest.TestCase):
self.nb.select(0)
- support.simulate_mouse_click(self.nb, 5, 5)
+ simulate_mouse_click(self.nb, 5, 5)
self.nb.focus_force()
self.nb.event_generate('<Control-Tab>')
self.assertEqual(self.nb.select(), str(self.child2))
@@ -1134,7 +1098,7 @@ class NotebookTest(AbstractWidgetTest, unittest.TestCase):
self.nb.tab(self.child1, text='a', underline=0)
self.nb.enable_traversal()
self.nb.focus_force()
- support.simulate_mouse_click(self.nb, 5, 5)
+ simulate_mouse_click(self.nb, 5, 5)
if sys.platform == 'darwin':
self.nb.event_generate('<Option-a>')
else:
@@ -1152,15 +1116,9 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
def setUp(self):
super().setUp()
- support.root_deiconify()
self.tv = self.create(padding=0)
- def tearDown(self):
- self.tv.destroy()
- support.root_withdraw()
- super().tearDown()
-
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Treeview(self.root, **kwargs)
def test_columns(self):
@@ -1168,7 +1126,8 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
self.checkParam(widget, 'columns', 'a b c',
expected=('a', 'b', 'c'))
self.checkParam(widget, 'columns', ('a', 'b', 'c'))
- self.checkParam(widget, 'columns', ())
+ self.checkParam(widget, 'columns', (),
+ expected='' if get_tk_patchlevel() < (8, 5, 10) else ())
def test_displaycolumns(self):
widget = self.create()
@@ -1216,12 +1175,7 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
self.assertTrue(children)
bbox = self.tv.bbox(children[0])
- self.assertEqual(len(bbox), 4)
- self.assertIsInstance(bbox, tuple)
- for item in bbox:
- if not isinstance(item, int):
- self.fail("Invalid bounding box: %s" % bbox)
- break
+ self.assertIsBoundingBox(bbox)
# compare width in bboxes
self.tv['columns'] = ['test']
@@ -1401,7 +1355,7 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
def test_heading_callback(self):
def simulate_heading_click(x, y):
- support.simulate_mouse_click(self.tv, x, y)
+ simulate_mouse_click(self.tv, x, y)
self.tv.update()
success = [] # no success for now
@@ -1590,7 +1544,7 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
self.assertEqual(len(pos_y), 2) # item1 and item2 y pos
for y in pos_y:
- support.simulate_mouse_click(self.tv, 0, y)
+ simulate_mouse_click(self.tv, 0, y)
# by now there should be 4 things in the events list, since each
# item had a bind for two events that were simulated above
@@ -1611,6 +1565,21 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
'blue')
self.assertIsInstance(self.tv.tag_configure('test'), dict)
+ def test_tag_has(self):
+ item1 = self.tv.insert('', 'end', text='Item 1', tags=['tag1'])
+ item2 = self.tv.insert('', 'end', text='Item 2', tags=['tag2'])
+ self.assertRaises(TypeError, self.tv.tag_has)
+ self.assertRaises(TclError, self.tv.tag_has, 'tag1', 'non-existing')
+ self.assertTrue(self.tv.tag_has('tag1', item1))
+ self.assertFalse(self.tv.tag_has('tag1', item2))
+ self.assertFalse(self.tv.tag_has('tag2', item1))
+ self.assertTrue(self.tv.tag_has('tag2', item2))
+ self.assertFalse(self.tv.tag_has('tag3', item1))
+ self.assertFalse(self.tv.tag_has('tag3', item2))
+ self.assertEqual(self.tv.tag_has('tag1'), (item1,))
+ self.assertEqual(self.tv.tag_has('tag2'), (item2,))
+ self.assertEqual(self.tv.tag_has('tag3'), ())
+
@add_standard_options(StandardTtkOptionsTests)
class SeparatorTest(AbstractWidgetTest, unittest.TestCase):
@@ -1620,7 +1589,7 @@ class SeparatorTest(AbstractWidgetTest, unittest.TestCase):
)
default_orient = 'horizontal'
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Separator(self.root, **kwargs)
@@ -1631,7 +1600,7 @@ class SizegripTest(AbstractWidgetTest, unittest.TestCase):
# 'state'?
)
- def _create(self, **kwargs):
+ def create(self, **kwargs):
return ttk.Sizegrip(self.root, **kwargs)
tests_gui = (
diff --git a/Lib/tkinter/test/widget_tests.py b/Lib/tkinter/test/widget_tests.py
index a9820a7..779538d 100644
--- a/Lib/tkinter/test/widget_tests.py
+++ b/Lib/tkinter/test/widget_tests.py
@@ -3,9 +3,9 @@
import unittest
import sys
import tkinter
-from tkinter.ttk import setup_master, Scale
-from tkinter.test.support import (tcl_version, requires_tcl, get_tk_patchlevel,
- pixels_conv, tcl_obj_eq)
+from tkinter.ttk import Scale
+from tkinter.test.support import (AbstractTkTest, tcl_version, requires_tcl,
+ get_tk_patchlevel, pixels_conv, tcl_obj_eq)
import test.support
@@ -22,21 +22,25 @@ if get_tk_patchlevel()[:3] == (8, 5, 11):
_sentinel = object()
-class AbstractWidgetTest:
+class AbstractWidgetTest(AbstractTkTest):
_conv_pixels = staticmethod(pixels_round)
_conv_pad_pixels = None
- wantobjects = True
-
- def setUp(self):
- self.root = setup_master()
- self.scaling = float(self.root.call('tk', 'scaling'))
- if not self.root.wantobjects():
- self.wantobjects = False
-
- def create(self, **kwargs):
- widget = self._create(**kwargs)
- self.addCleanup(widget.destroy)
- return widget
+ _stringify = False
+
+ @property
+ def scaling(self):
+ try:
+ return self._scaling
+ except AttributeError:
+ self._scaling = float(self.root.call('tk', 'scaling'))
+ return self._scaling
+
+ def _str(self, value):
+ if not self._stringify and self.wantobjects and tcl_version >= (8, 6):
+ return value
+ if isinstance(value, tuple):
+ return ' '.join(map(self._str, value))
+ return str(value)
def assertEqual2(self, actual, expected, msg=None, eq=object.__eq__):
if eq(actual, expected):
@@ -50,7 +54,7 @@ class AbstractWidgetTest:
expected = value
if conv:
expected = conv(expected)
- if not self.wantobjects:
+ if self._stringify or not self.wantobjects:
if isinstance(expected, tuple):
expected = tkinter._join(expected)
else:
@@ -182,7 +186,7 @@ class AbstractWidgetTest:
errmsg=errmsg)
def checkImageParam(self, widget, name):
- image = tkinter.PhotoImage('image1')
+ image = tkinter.PhotoImage(master=self.root, name='image1')
self.checkParam(widget, name, image, conv=str)
self.checkInvalidParam(widget, name, 'spam',
errmsg='image "spam" doesn\'t exist')
@@ -191,6 +195,16 @@ class AbstractWidgetTest:
def checkVariableParam(self, widget, name, var):
self.checkParam(widget, name, var, conv=str)
+ def assertIsBoundingBox(self, bbox):
+ self.assertIsNotNone(bbox)
+ self.assertIsInstance(bbox, tuple)
+ if len(bbox) != 4:
+ self.fail('Invalid bounding box: %r' % (bbox,))
+ for item in bbox:
+ if not isinstance(item, int):
+ self.fail('Invalid bounding box: %r' % (bbox,))
+ break
+
class StandardOptionsTests:
STANDARD_OPTIONS = (
@@ -393,7 +407,7 @@ class StandardOptionsTests:
def test_textvariable(self):
widget = self.create()
- var = tkinter.StringVar()
+ var = tkinter.StringVar(self.root)
self.checkVariableParam(widget, 'textvariable', var)
def test_troughcolor(self):
@@ -454,7 +468,7 @@ class StandardOptionsTests:
def test_variable(self):
widget = self.create()
- var = tkinter.DoubleVar()
+ var = tkinter.DoubleVar(self.root)
self.checkVariableParam(widget, 'variable', var)
diff --git a/Lib/tkinter/tix.py b/Lib/tkinter/tix.py
index 131aa06..c1cdfa7 100644
--- a/Lib/tkinter/tix.py
+++ b/Lib/tkinter/tix.py
@@ -27,7 +27,7 @@
#
from tkinter import *
-from tkinter import _flatten, _cnfmerge, _default_root
+from tkinter import _cnfmerge, _default_root
# WARNING - TkVersion is a limited precision floating point number
if TkVersion < 3.999:
diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py
index ca90273..b9c57ad 100644
--- a/Lib/tkinter/ttk.py
+++ b/Lib/tkinter/ttk.py
@@ -26,7 +26,7 @@ __all__ = ["Button", "Checkbutton", "Combobox", "Entry", "Frame", "Label",
"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 @@ def _script_from_settings(settings):
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."""
@@ -272,9 +257,10 @@ 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."""
+ ltuple = tk.splitlist(ltuple)
res = []
indx = 0
@@ -293,17 +279,14 @@ 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)
+ 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 +294,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 _splitdict(tk, res, conv=_tclobj_to_py)
def _convert_stringval(value):
"""Converts a value to, hopefully, a more appropriate Python object."""
@@ -338,20 +319,24 @@ def _to_number(x):
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, 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
@@ -396,7 +381,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):
@@ -411,8 +396,10 @@ class Style(object):
return _list_from_statespec(self.tk.splitlist(
self.tk.call(self._name, "map", style, '-%s' % query_opt)))
- return _dict_from_tcltuple(
- 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):
@@ -466,8 +453,8 @@ 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(
- self.tk.call(self._name, "layout", style, lspec)))
+ return _list_from_layouttuple(self.tk,
+ self.tk.call(self._name, "layout", style, lspec))
def element_create(self, elementname, etype, *args, **kw):
@@ -586,7 +573,7 @@ class Widget(tkinter.Widget):
if ret and callback:
return callback(*args, **kw)
- return bool(ret)
+ return ret
def state(self, statespec=None):
@@ -694,7 +681,7 @@ class Entry(Widget, tkinter.Entry):
"""Force revalidation, independent of the conditions specified
by the validate option. Returns False if validation fails, True
if it succeeds. Sets or clears the invalid state accordingly."""
- return bool(self.tk.getboolean(self.tk.call(self._w, "validate")))
+ return self.tk.getboolean(self.tk.call(self._w, "validate"))
class Combobox(Entry):
@@ -907,7 +894,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 +971,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 +1210,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):
@@ -1244,7 +1231,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
def exists(self, item):
"""Returns True if the specified item is present in the tree,
False otherwise."""
- return bool(self.tk.getboolean(self.tk.call(self._w, "exists", item)))
+ return self.tk.getboolean(self.tk.call(self._w, "exists", item))
def focus(self, item=None):
@@ -1282,7 +1269,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 +1348,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):
@@ -1429,13 +1416,16 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
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
@@ -1456,7 +1446,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)
@@ -1466,7 +1456,11 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
all items which have the specified tag.
* Availability: Tk 8.6"""
- return self.tk.getboolean(
+ if item is None:
+ return self.tk.splitlist(
+ self.tk.call(self._w, "tag", "has", tagname))
+ else:
+ return self.tk.getboolean(
self.tk.call(self._w, "tag", "has", tagname, item))