- Notifications
You must be signed in to change notification settings - Fork 31.8k
/
Copy pathtkinter_testing_utils.py
62 lines (51 loc) · 2.28 KB
/
tkinter_testing_utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
"""Utilities for testing with Tkinter"""
importfunctools
defrun_in_tk_mainloop(delay=1):
"""Decorator for running a test method with a real Tk mainloop.
This starts a Tk mainloop before running the test, and stops it
at the end. This is faster and more robust than the common
alternative method of calling .update() and/or .update_idletasks().
Test methods using this must be written as generator functions,
using "yield" to allow the mainloop to process events and "after"
callbacks, and then continue the test from that point.
The delay argument is passed into root.after(...) calls as the number
of ms to wait before passing execution back to the generator function.
This also assumes that the test class has a .root attribute,
which is a tkinter.Tk object.
For example (from test_sidebar.py):
@run_test_with_tk_mainloop()
def test_single_empty_input(self):
self.do_input('\n')
yield
self.assert_sidebar_lines_end_with(['>>>', '>>>'])
"""
defdecorator(test_method):
@functools.wraps(test_method)
defnew_test_method(self):
test_generator=test_method(self)
root=self.root
# Exceptions raised by self.assert...() need to be raised
# outside of the after() callback in order for the test
# harness to capture them.
exception=None
defafter_callback():
nonlocalexception
try:
next(test_generator)
exceptStopIteration:
root.quit()
exceptExceptionasexc:
exception=exc
root.quit()
else:
# Schedule the Tk mainloop to call this function again,
# using a robust method of ensuring that it gets a
# chance to process queued events before doing so.
# See: https://stackoverflow.com/q/18499082#comment65004099_38817470
root.after(delay, root.after_idle, after_callback)
root.after(0, root.after_idle, after_callback)
root.mainloop()
ifexception:
raiseexception
returnnew_test_method
returndecorator