|
2 | 2 | import subprocess
|
3 | 3 | import sys
|
4 | 4 |
|
5 |
| -import numpy as np |
6 | 5 | import pytest
|
7 | 6 |
|
8 |
| -from matplotlib import pyplot as plt |
9 | 7 | _test_timeout = 10 # Empirically, 1s is not enough on Travis.
|
10 | 8 |
|
| 9 | +# NOTE: TkAgg tests seem to have interactions between tests, |
| 10 | +# So isolate each test in a subprocess. See GH#18261 |
| 11 | + |
11 | 12 |
|
12 | 13 | @pytest.mark.backend('TkAgg', skip_on_importerror=True)
|
13 | 14 | def test_blit():
|
14 |
| - from matplotlib.backends import _tkagg |
15 |
| - def evil_blit(photoimage, aggimage, offsets, bboxptr): |
16 |
| - data = np.asarray(aggimage) |
17 |
| - height, width = data.shape[:2] |
18 |
| - dataptr = (height, width, data.ctypes.data) |
19 |
| - _tkagg.blit( |
20 |
| - photoimage.tk.interpaddr(), str(photoimage), dataptr, offsets, |
21 |
| - bboxptr) |
22 |
| - |
23 |
| - fig, ax = plt.subplots() |
24 |
| - for bad_boxes in ((-1, 2, 0, 2), |
25 |
| - (2, 0, 0, 2), |
26 |
| - (1, 6, 0, 2), |
27 |
| - (0, 2, -1, 2), |
28 |
| - (0, 2, 2, 0), |
29 |
| - (0, 2, 1, 6)): |
30 |
| - with pytest.raises(ValueError): |
31 |
| - evil_blit(fig.canvas._tkphoto, |
32 |
| - np.ones((4, 4, 4)), |
33 |
| - (0, 1, 2, 3), |
34 |
| - bad_boxes) |
| 15 | + script = """ |
| 16 | +import matplotlib.pyplot as plt |
| 17 | +import numpy as np |
| 18 | +from matplotlib.backends import _tkagg |
| 19 | +def evil_blit(photoimage, aggimage, offsets, bboxptr): |
| 20 | + data = np.asarray(aggimage) |
| 21 | + height, width = data.shape[:2] |
| 22 | + dataptr = (height, width, data.ctypes.data) |
| 23 | + _tkagg.blit( |
| 24 | + photoimage.tk.interpaddr(), str(photoimage), dataptr, offsets, |
| 25 | + bboxptr) |
| 26 | +
|
| 27 | +fig, ax = plt.subplots() |
| 28 | +bad_boxes = ((-1, 2, 0, 2), |
| 29 | + (2, 0, 0, 2), |
| 30 | + (1, 6, 0, 2), |
| 31 | + (0, 2, -1, 2), |
| 32 | + (0, 2, 2, 0), |
| 33 | + (0, 2, 1, 6)) |
| 34 | +for bad_box in bad_boxes: |
| 35 | + try: |
| 36 | + evil_blit(fig.canvas._tkphoto, |
| 37 | + np.ones((4, 4, 4)), |
| 38 | + (0, 1, 2, 3), |
| 39 | + bad_box) |
| 40 | + except ValueError: |
| 41 | + print("success") |
| 42 | +""" |
| 43 | + try: |
| 44 | + proc = subprocess.run( |
| 45 | + [sys.executable, "-c", script], |
| 46 | + env={**os.environ, |
| 47 | + "MPLBACKEND": "TkAgg", |
| 48 | + "SOURCE_DATE_EPOCH": "0"}, |
| 49 | + timeout=_test_timeout, |
| 50 | + stdout=subprocess.PIPE, |
| 51 | + check=True, |
| 52 | + universal_newlines=True, |
| 53 | + ) |
| 54 | + except subprocess.CalledProcessError: |
| 55 | + pytest.fail("Likely regression on out-of-bounds data access" |
| 56 | + " in _tkagg.cpp") |
| 57 | + else: |
| 58 | + print(proc.stdout) |
| 59 | + assert proc.stdout.count("success") == 6 # len(bad_boxes) |
35 | 60 |
|
36 | 61 |
|
37 | 62 | @pytest.mark.backend('TkAgg', skip_on_importerror=True)
|
@@ -172,12 +197,32 @@ def test_never_update():
|
172 | 197 |
|
173 | 198 | @pytest.mark.backend('TkAgg', skip_on_importerror=True)
|
174 | 199 | def test_missing_back_button():
|
175 |
| - from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk |
176 |
| - class Toolbar(NavigationToolbar2Tk): |
177 |
| - # only display the buttons we need |
178 |
| - toolitems = [t for t in NavigationToolbar2Tk.toolitems if |
179 |
| - t[0] in ('Home', 'Pan', 'Zoom')] |
180 |
| - |
181 |
| - fig = plt.figure() |
182 |
| - # this should not raise |
183 |
| - Toolbar(fig.canvas, fig.canvas.manager.window) |
| 200 | + script = """ |
| 201 | +import matplotlib.pyplot as plt |
| 202 | +from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk |
| 203 | +class Toolbar(NavigationToolbar2Tk): |
| 204 | + # only display the buttons we need |
| 205 | + toolitems = [t for t in NavigationToolbar2Tk.toolitems if |
| 206 | + t[0] in ('Home', 'Pan', 'Zoom')] |
| 207 | +
|
| 208 | +fig = plt.figure() |
| 209 | +print("setup complete") |
| 210 | +# this should not raise |
| 211 | +Toolbar(fig.canvas, fig.canvas.manager.window) |
| 212 | +print("success") |
| 213 | +""" |
| 214 | + try: |
| 215 | + proc = subprocess.run( |
| 216 | + [sys.executable, "-c", script], |
| 217 | + env={**os.environ, |
| 218 | + "MPLBACKEND": "TkAgg", |
| 219 | + "SOURCE_DATE_EPOCH": "0"}, |
| 220 | + timeout=_test_timeout, |
| 221 | + stdout=subprocess.PIPE, |
| 222 | + universal_newlines=True, |
| 223 | + ) |
| 224 | + except subprocess.TimeoutExpired: |
| 225 | + pytest.fail("Subprocess timed out") |
| 226 | + else: |
| 227 | + assert proc.stdout.count("setup complete") == 1 |
| 228 | + assert proc.stdout.count("success") == 1 |
0 commit comments