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,32 @@ 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+ return func
30+
31+ @pytest .mark .skipif (
32+ importlib .util .find_spec ('tkinter' ),
33+ reason = "missing tkinter"
34+ )
35+ @pytest .mark .skipif (
36+ sys .platform == "linux" and not _c_internal_utils .display_is_valid (),
37+ reason = "$DISPLAY and $WAYLAND_DISPLAY are unset"
38+ )
3439 @functools .wraps (func )
3540 def test_func ():
41+ # even if the package exists, may not actually be importable this can
42+ # be the case on some CI systems.
43+ pytest .importorskip ('tkinter' )
3644 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 ,
45+ proc = subprocess_run_helper (
46+ func , timeout = _test_timeout ,
47+ MPLBACKEND = "TkAgg" ,
48+ MPL_TEST_ESCAPE_HATCH = "1"
4549 )
4650 except subprocess .TimeoutExpired :
4751 pytest .fail ("Subprocess timed out" )
@@ -59,9 +63,8 @@ def test_func():
5963 return test_func
6064
6165
62- @pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
6366@_isolated_tk_test (success_count = 6 ) # len(bad_boxes)
64- def test_blit (): # pragma: no cover
67+ def test_blit ():
6568 import matplotlib .pyplot as plt
6669 import numpy as np
6770 import matplotlib .backends .backend_tkagg # noqa
@@ -88,9 +91,8 @@ def test_blit(): # pragma: no cover
8891 print ("success" )
8992
9093
91- @pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
9294@_isolated_tk_test (success_count = 1 )
93- def test_figuremanager_preserves_host_mainloop (): # pragma: no cover
95+ def test_figuremanager_preserves_host_mainloop ():
9496 import tkinter
9597 import matplotlib .pyplot as plt
9698 success = []
@@ -116,10 +118,9 @@ def legitimate_quit():
116118@pytest .mark .skipif (platform .python_implementation () != 'CPython' ,
117119 reason = 'PyPy does not support Tkinter threading: '
118120 'https://foss.heptapod.net/pypy/pypy/-/issues/1929' )
119- @pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
120121@pytest .mark .flaky (reruns = 3 )
121122@_isolated_tk_test (success_count = 1 )
122- def test_figuremanager_cleans_own_mainloop (): # pragma: no cover
123+ def test_figuremanager_cleans_own_mainloop ():
123124 import tkinter
124125 import time
125126 import matplotlib .pyplot as plt
@@ -144,10 +145,9 @@ def target():
144145 thread .join ()
145146
146147
147- @pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
148148@pytest .mark .flaky (reruns = 3 )
149149@_isolated_tk_test (success_count = 0 )
150- def test_never_update (): # pragma: no cover
150+ def test_never_update ():
151151 import tkinter
152152 del tkinter .Misc .update
153153 del tkinter .Misc .update_idletasks
@@ -171,9 +171,8 @@ def test_never_update(): # pragma: no cover
171171 # checks them.
172172
173173
174- @pytest .mark .backend ('TkAgg' , skip_on_importerror = True )
175174@_isolated_tk_test (success_count = 2 )
176- def test_missing_back_button (): # pragma: no cover
175+ def test_missing_back_button ():
177176 import matplotlib .pyplot as plt
178177 from matplotlib .backends .backend_tkagg import NavigationToolbar2Tk
179178
0 commit comments