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