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