Skip to content

Commit 6253d37

Browse files
Migrate tk backend tests into subprocesses
Try to isolate suspected interactions between tests
1 parent d592ebb commit 6253d37

File tree

2 files changed

+80
-46
lines changed

2 files changed

+80
-46
lines changed

lib/matplotlib/tests/test_backend_tk.py

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import os
22
import subprocess
33
import sys
4-
import tkinter
54

65
import numpy as np
76
import pytest
87

98
from matplotlib import pyplot as plt
9+
_test_timeout = 10 # Empirically, 1s is not enough on Travis.
1010

1111

1212
@pytest.mark.backend('TkAgg', skip_on_importerror=True)
@@ -36,25 +36,42 @@ def evil_blit(photoimage, aggimage, offsets, bboxptr):
3636

3737
@pytest.mark.backend('TkAgg', skip_on_importerror=True)
3838
def test_figuremanager_preserves_host_mainloop():
39-
success = False
40-
41-
def do_plot():
42-
plt.figure()
43-
plt.plot([1, 2], [3, 5])
44-
plt.close()
45-
root.after(0, legitimate_quit)
39+
script = """
40+
import tkinter
41+
import matplotlib.pyplot as plt
42+
success = False
4643
47-
def legitimate_quit():
48-
root.quit()
49-
nonlocal success
50-
success = True
44+
def do_plot():
45+
plt.figure()
46+
plt.plot([1, 2], [3, 5])
47+
plt.close()
48+
root.after(0, legitimate_quit)
5149
52-
root = tkinter.Tk()
53-
root.after(0, do_plot)
54-
root.mainloop()
50+
def legitimate_quit():
51+
root.quit()
52+
global success
53+
success = True
5554
56-
assert success
55+
root = tkinter.Tk()
56+
root.after(0, do_plot)
57+
root.mainloop()
5758
59+
if success:
60+
print("success")
61+
"""
62+
try:
63+
proc = subprocess.run(
64+
[sys.executable, "-c", script,],
65+
env={**os.environ, "SOURCE_DATE_EPOCH": "0"},
66+
timeout=_test_timeout,
67+
stdout=subprocess.PIPE,
68+
check=True,
69+
universal_newlines=True,
70+
)
71+
except subprocess.CalledProcessError:
72+
pytest.fail("Subprocess failed to test intended behavior")
73+
else:
74+
assert proc.stdout.count("success") == 1
5875

5976
@pytest.mark.backend('TkAgg', skip_on_importerror=True)
6077
@pytest.mark.flaky(reruns=3)
@@ -90,7 +107,7 @@ def target():
90107
env={**os.environ,
91108
"MPLBACKEND": "TkAgg",
92109
"SOURCE_DATE_EPOCH": "0"},
93-
timeout=10,
110+
timeout=_test_timeout,
94111
stdout=subprocess.PIPE,
95112
universal_newlines=True,
96113
check=True
@@ -102,6 +119,52 @@ def target():
102119
assert proc.stdout.count("success") == 1
103120

104121

122+
@pytest.mark.backend('TkAgg', skip_on_importerror=True)
123+
@pytest.mark.flaky(reruns=3)
124+
def test_never_update():
125+
script = """
126+
import tkinter
127+
del tkinter.Misc.update
128+
del tkinter.Misc.update_idletasks
129+
130+
import matplotlib.pyplot as plt
131+
fig = plt.figure()
132+
plt.show(block=False)
133+
134+
# regression test on FigureCanvasTkAgg
135+
plt.draw()
136+
# regression test on NavigationToolbar2Tk
137+
fig.canvas.toolbar.configure_subplots()
138+
139+
# check for update() or update_idletasks() in the event queue
140+
# functionally equivalent to tkinter.Misc.update
141+
# must pause >= 1 ms to process tcl idle events plus
142+
# extra time to avoid flaky tests on slow systems
143+
plt.pause(0.1)
144+
145+
# regression test on FigureCanvasTk filter_destroy callback
146+
plt.close(fig)
147+
"""
148+
try:
149+
proc = subprocess.run(
150+
[sys.executable, "-c", script,],
151+
env={**os.environ, "SOURCE_DATE_EPOCH": "0"},
152+
timeout=_test_timeout,
153+
capture_output=True,
154+
check=True,
155+
universal_newlines=True,
156+
)
157+
except subprocess.CalledProcessError:
158+
pytest.fail("Subprocess failed to test intended behavior")
159+
else:
160+
# test framework doesn't see tkinter callback exceptions normally
161+
# see tkinter.Misc.report_callback_exception
162+
assert "Exception in Tkinter callback" not in proc.stderr
163+
finally:
164+
# make sure we can see other issues
165+
print(proc.stderr, file=sys.stderr)
166+
167+
105168
@pytest.mark.backend('TkAgg', skip_on_importerror=True)
106169
def test_missing_back_button():
107170
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk

lib/matplotlib/tests/test_backends_interactive.py

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -201,35 +201,6 @@ def test_webagg():
201201
assert proc.wait(timeout=_test_timeout) == 0
202202

203203

204-
@pytest.mark.backend('TkAgg', skip_on_importerror=True)
205-
def test_never_update(monkeypatch, capsys):
206-
import tkinter
207-
monkeypatch.delattr(tkinter.Misc, 'update')
208-
monkeypatch.delattr(tkinter.Misc, 'update_idletasks')
209-
210-
import matplotlib.pyplot as plt
211-
fig = plt.figure()
212-
plt.show(block=False)
213-
214-
# regression test on FigureCanvasTkAgg
215-
plt.draw()
216-
# regression test on NavigationToolbar2Tk
217-
fig.canvas.toolbar.configure_subplots()
218-
219-
# check for update() or update_idletasks() in the event queue
220-
# functionally equivalent to tkinter.Misc.update
221-
# must pause >= 1 ms to process tcl idle events plus
222-
# extra time to avoid flaky tests on slow systems
223-
plt.pause(0.1)
224-
225-
# regression test on FigureCanvasTk filter_destroy callback
226-
plt.close(fig)
227-
228-
# test framework doesn't see tkinter callback exceptions normally
229-
# see tkinter.Misc.report_callback_exception
230-
assert "Exception in Tkinter callback" not in capsys.readouterr().err
231-
232-
233204
@pytest.mark.skipif(sys.platform != "linux", reason="this a linux-only test")
234205
@pytest.mark.backend('Qt5Agg', skip_on_importerror=True)
235206
def test_lazy_linux_headless():

0 commit comments

Comments
 (0)