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