• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import re
2import tkinter
3import unittest
4
5class AbstractTkTest:
6
7    @classmethod
8    def setUpClass(cls):
9        cls._old_support_default_root = tkinter._support_default_root
10        destroy_default_root()
11        tkinter.NoDefaultRoot()
12        cls.root = tkinter.Tk()
13        cls.wantobjects = cls.root.wantobjects()
14        # De-maximize main window.
15        # Some window managers can maximize new windows.
16        cls.root.wm_state('normal')
17        try:
18            cls.root.wm_attributes('-zoomed', False)
19        except tkinter.TclError:
20            pass
21
22    @classmethod
23    def tearDownClass(cls):
24        cls.root.update_idletasks()
25        cls.root.destroy()
26        del cls.root
27        tkinter._default_root = None
28        tkinter._support_default_root = cls._old_support_default_root
29
30    def setUp(self):
31        self.root.deiconify()
32
33    def tearDown(self):
34        for w in self.root.winfo_children():
35            w.destroy()
36        self.root.withdraw()
37
38def destroy_default_root():
39    if getattr(tkinter, '_default_root', None):
40        tkinter._default_root.update_idletasks()
41        tkinter._default_root.destroy()
42        tkinter._default_root = None
43
44def simulate_mouse_click(widget, x, y):
45    """Generate proper events to click at the x, y position (tries to act
46    like an X server)."""
47    widget.event_generate('<Enter>', x=0, y=0)
48    widget.event_generate('<Motion>', x=x, y=y)
49    widget.event_generate('<ButtonPress-1>', x=x, y=y)
50    widget.event_generate('<ButtonRelease-1>', x=x, y=y)
51
52
53import _tkinter
54tcl_version = tuple(map(int, _tkinter.TCL_VERSION.split('.')))
55
56def requires_tcl(*version):
57    return unittest.skipUnless(tcl_version >= version,
58            'requires Tcl version >= ' + '.'.join(map(str, version)))
59
60_tk_patchlevel = None
61def get_tk_patchlevel():
62    global _tk_patchlevel
63    if _tk_patchlevel is None:
64        tcl = tkinter.Tcl()
65        patchlevel = tcl.call('info', 'patchlevel')
66        m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', patchlevel)
67        major, minor, releaselevel, serial = m.groups()
68        major, minor, serial = int(major), int(minor), int(serial)
69        releaselevel = {'a': 'alpha', 'b': 'beta', '.': 'final'}[releaselevel]
70        if releaselevel == 'final':
71            _tk_patchlevel = major, minor, serial, releaselevel, 0
72        else:
73            _tk_patchlevel = major, minor, 0, releaselevel, serial
74    return _tk_patchlevel
75
76units = {
77    'c': 72 / 2.54,     # centimeters
78    'i': 72,            # inches
79    'm': 72 / 25.4,     # millimeters
80    'p': 1,             # points
81}
82
83def pixels_conv(value):
84    return float(value[:-1]) * units[value[-1:]]
85
86def tcl_obj_eq(actual, expected):
87    if actual == expected:
88        return True
89    if isinstance(actual, _tkinter.Tcl_Obj):
90        if isinstance(expected, str):
91            return str(actual) == expected
92    if isinstance(actual, tuple):
93        if isinstance(expected, tuple):
94            return (len(actual) == len(expected) and
95                    all(tcl_obj_eq(act, exp)
96                        for act, exp in zip(actual, expected)))
97    return False
98
99def widget_eq(actual, expected):
100    if actual == expected:
101        return True
102    if isinstance(actual, (str, tkinter.Widget)):
103        if isinstance(expected, (str, tkinter.Widget)):
104            return str(actual) == str(expected)
105    return False
106