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 _tk_patchlevel = tcl.info_patchlevel() 105 return _tk_patchlevel 106 107units = { 108 'c': 72 / 2.54, # centimeters 109 'i': 72, # inches 110 'm': 72 / 25.4, # millimeters 111 'p': 1, # points 112} 113 114def pixels_conv(value): 115 return float(value[:-1]) * units[value[-1:]] 116 117def tcl_obj_eq(actual, expected): 118 if actual == expected: 119 return True 120 if isinstance(actual, _tkinter.Tcl_Obj): 121 if isinstance(expected, str): 122 return str(actual) == expected 123 if isinstance(actual, tuple): 124 if isinstance(expected, tuple): 125 return (len(actual) == len(expected) and 126 all(tcl_obj_eq(act, exp) 127 for act, exp in zip(actual, expected))) 128 return False 129 130def widget_eq(actual, expected): 131 if actual == expected: 132 return True 133 if isinstance(actual, (str, tkinter.Widget)): 134 if isinstance(expected, (str, tkinter.Widget)): 135 return str(actual) == str(expected) 136 return False 137