support.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import functools
  2. import re
  3. import tkinter
  4. import unittest
  5. class AbstractTkTest:
  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. @classmethod
  21. def tearDownClass(cls):
  22. cls.root.update_idletasks()
  23. cls.root.destroy()
  24. del cls.root
  25. tkinter._default_root = None
  26. tkinter._support_default_root = cls._old_support_default_root
  27. def setUp(self):
  28. self.root.deiconify()
  29. def tearDown(self):
  30. for w in self.root.winfo_children():
  31. w.destroy()
  32. self.root.withdraw()
  33. def destroy_default_root():
  34. if getattr(tkinter, '_default_root', None):
  35. tkinter._default_root.update_idletasks()
  36. tkinter._default_root.destroy()
  37. tkinter._default_root = None
  38. def simulate_mouse_click(widget, x, y):
  39. """Generate proper events to click at the x, y position (tries to act
  40. like an X server)."""
  41. widget.event_generate('<Enter>', x=0, y=0)
  42. widget.event_generate('<Motion>', x=x, y=y)
  43. widget.event_generate('<ButtonPress-1>', x=x, y=y)
  44. widget.event_generate('<ButtonRelease-1>', x=x, y=y)
  45. import _tkinter
  46. tcl_version = tuple(map(int, _tkinter.TCL_VERSION.split('.')))
  47. def requires_tcl(*version):
  48. if len(version) <= 2:
  49. return unittest.skipUnless(tcl_version >= version,
  50. 'requires Tcl version >= ' + '.'.join(map(str, version)))
  51. def deco(test):
  52. @functools.wraps(test)
  53. def newtest(self):
  54. if get_tk_patchlevel() < version:
  55. self.skipTest('requires Tcl version >= ' +
  56. '.'.join(map(str, version)))
  57. test(self)
  58. return newtest
  59. return deco
  60. _tk_patchlevel = None
  61. def 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. units = {
  76. 'c': 72 / 2.54, # centimeters
  77. 'i': 72, # inches
  78. 'm': 72 / 25.4, # millimeters
  79. 'p': 1, # points
  80. }
  81. def pixels_conv(value):
  82. return float(value[:-1]) * units[value[-1:]]
  83. def tcl_obj_eq(actual, expected):
  84. if actual == expected:
  85. return True
  86. if isinstance(actual, _tkinter.Tcl_Obj):
  87. if isinstance(expected, str):
  88. return str(actual) == expected
  89. if isinstance(actual, tuple):
  90. if isinstance(expected, tuple):
  91. return (len(actual) == len(expected) and
  92. all(tcl_obj_eq(act, exp)
  93. for act, exp in zip(actual, expected)))
  94. return False
  95. def widget_eq(actual, expected):
  96. if actual == expected:
  97. return True
  98. if isinstance(actual, (str, tkinter.Widget)):
  99. if isinstance(expected, (str, tkinter.Widget)):
  100. return str(actual) == str(expected)
  101. return False