11import functools
2- import inspect
2+ import importlib
33import os
44import platform
5- import re
65import subprocess
76import sys
87
98import pytest
109
10+ from matplotlib .testing import subprocess_run_helper
11+ from matplotlib import _c_internal_utils
12+
1113_test_timeout = 60 # A reasonably safe value for slower architectures.
1214
1315
@@ -18,30 +20,33 @@ def _isolated_tk_test(success_count, func=None):
1820
1921 TkAgg tests seem to have interactions between tests, so isolate each test
2022 in a subprocess. See GH#18261
21-
22- The decorated function must be fully self-contained, and thus perform
23- all the imports it needs. Because its source is extracted and run by
24- itself, coverage will consider it as not being run, so it should be marked
25- with ``# pragma: no cover``
2623 """
2724
2825 if func is None :
2926 return functools .partial (_isolated_tk_test , success_count )
3027
31- # Remove decorators.
32- source = re .search (r"(?ms)^def .*" , inspect .getsource (func )).group (0 )
33-
28+ if "MPL_TEST_ESCAPE_HATCH" in os .environ :
29+ # set in subprocess_run_helper() below
30+ return func
31+
32+ @pytest .mark .skipif (
33+ not importlib .util .find_spec ('tkinter' ),
34+ reason = "missing tkinter"
35+ )
36+ @pytest .mark .skipif (
37+ sys .platform == "linux" and not _c_internal_utils .display_is_valid (),
38+ reason = "$DISPLAY and $WAYLAND_DISPLAY are unset"
39+ )
3440 @functools .wraps (func )
3541 def test_func ():
42+ # even if the package exists, may not actually be importable this can
43+ # be the case on some CI systems.
44+ pytest .importorskip ('tkinter' )
3645 try :
37- proc = subprocess .run (
38- [sys .executable , "-c" , f"{ source } \n { func .__name__ } ()" ],
39- env = {** os .environ , "MPLBACKEND" : "TkAgg" },
40- timeout = _test_timeout ,
41- stdout = subprocess .PIPE ,
42- stderr = subprocess .PIPE ,
43- check = True ,
44- universal_newlines = True ,
46+ proc = subprocess_run_helper (
47+ func , timeout = _test_timeout ,
48+ MPLBACKEND = "TkAgg" ,
49+ MPL_TEST_ESCAPE_HATCH = "1"
4550 )
4651 except subprocess .TimeoutExpired :
4752 pytest .fail ("Subprocess timed out" )
@@ -59,9 +64,8 @@ def test_func():
5964 return test_func
6065
6166
62- @pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
6367@_isolated_tk_test (success_count = 6 ) # len(bad_boxes)
64- def test_blit (): # pragma: no cover
68+ def test_blit ():
6569 import matplotlib .pyplot as plt
6670 import numpy as np
6771 import matplotlib .backends .backend_tkagg # noqa
@@ -88,9 +92,8 @@ def test_blit(): # pragma: no cover
8892 print ("success" )
8993
9094
91- @pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
9295@_isolated_tk_test (success_count = 1 )
93- def test_figuremanager_preserves_host_mainloop (): # pragma: no cover
96+ def test_figuremanager_preserves_host_mainloop ():
9497 import tkinter
9598 import matplotlib .pyplot as plt
9699 success = []
@@ -116,10 +119,9 @@ def legitimate_quit():
116119@pytest .mark .skipif (platform .python_implementation () != 'CPython' ,
117120 reason = 'PyPy does not support Tkinter threading: '
118121 'https://foss.heptapod.net/pypy/pypy/-/issues/1929' )
119- @pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
120122@pytest .mark .flaky (reruns = 3 )
121123@_isolated_tk_test (success_count = 1 )
122- def test_figuremanager_cleans_own_mainloop (): # pragma: no cover
124+ def test_figuremanager_cleans_own_mainloop ():
123125 import tkinter
124126 import time
125127 import matplotlib .pyplot as plt
@@ -144,10 +146,9 @@ def target():
144146 thread .join ()
145147
146148
147- @pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
148149@pytest .mark .flaky (reruns = 3 )
149150@_isolated_tk_test (success_count = 0 )
150- def test_never_update (): # pragma: no cover
151+ def test_never_update ():
151152 import tkinter
152153 del tkinter .Misc .update
153154 del tkinter .Misc .update_idletasks
@@ -171,9 +172,8 @@ def test_never_update(): # pragma: no cover
171172 # checks them.
172173
173174
174- @pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
175175@_isolated_tk_test (success_count = 2 )
176- def test_missing_back_button (): # pragma: no cover
176+ def test_missing_back_button ():
177177 import matplotlib .pyplot as plt
178178 from matplotlib .backends .backend_tkagg import NavigationToolbar2Tk
179179
@@ -190,7 +190,7 @@ class Toolbar(NavigationToolbar2Tk):
190190
191191@pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
192192@_isolated_tk_test (success_count = 1 )
193- def test_canvas_focus (): # pragma: no cover
193+ def test_canvas_focus ():
194194 import tkinter as tk
195195 import matplotlib .pyplot as plt
196196 success = []
0 commit comments