summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/idle_test/tkinter_testing_utils.py
diff options
context:
space:
mode:
authorTal Einat <532281+taleinat@users.noreply.github.com>2021-04-28 22:27:55 (GMT)
committerGitHub <noreply@github.com>2021-04-28 22:27:55 (GMT)
commit15d386185659683fc044ccaa300aa8cd7d49cc1a (patch)
tree6fac7df4ac125b39648d8f0d7fbb008212dc6ba8 /Lib/idlelib/idle_test/tkinter_testing_utils.py
parent103d5e420dd90489933ad9da8bb1d6008773384d (diff)
downloadcpython-15d386185659683fc044ccaa300aa8cd7d49cc1a.zip
cpython-15d386185659683fc044ccaa300aa8cd7d49cc1a.tar.gz
cpython-15d386185659683fc044ccaa300aa8cd7d49cc1a.tar.bz2
bpo-37903: IDLE: Shell sidebar with prompts (GH-22682)
The first followup will change shell indents to spaces. More are expected. Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
Diffstat (limited to 'Lib/idlelib/idle_test/tkinter_testing_utils.py')
-rw-r--r--Lib/idlelib/idle_test/tkinter_testing_utils.py56
1 files changed, 56 insertions, 0 deletions
diff --git a/Lib/idlelib/idle_test/tkinter_testing_utils.py b/Lib/idlelib/idle_test/tkinter_testing_utils.py
new file mode 100644
index 0000000..a9f8386
--- /dev/null
+++ b/Lib/idlelib/idle_test/tkinter_testing_utils.py
@@ -0,0 +1,56 @@
+"""Utilities for testing with Tkinter"""
+import functools
+
+
+def run_in_tk_mainloop(test_method):
+ """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.
+
+ 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(['>>>', '>>>'])
+ """
+ @functools.wraps(test_method)
+ def new_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
+ def after_callback():
+ nonlocal exception
+ try:
+ next(test_generator)
+ except StopIteration:
+ root.quit()
+ except Exception as exc:
+ 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(1, root.after_idle, after_callback)
+ root.after(0, root.after_idle, after_callback)
+ root.mainloop()
+
+ if exception:
+ raise exception
+
+ return new_test_method