Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit edd23a4

Browse files
committed
TST: Add a lock on parametrized image comparisons.
This should prevent tests (if run with xdist) from overwriting each other's files in the middle of checking them.
1 parent f1be02c commit edd23a4

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

lib/matplotlib/testing/decorators.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
import sys
1010
import unittest
1111
import warnings
12+
try:
13+
from contextlib import nullcontext
14+
except ImportError:
15+
from contextlib import ExitStack as nullcontext # Py3.6.
1216

1317
import matplotlib as mpl
1418
import matplotlib.style
@@ -200,7 +204,7 @@ def copy_baseline(self, baseline, extension):
200204
f"{orig_expected_path}") from err
201205
return expected_fname
202206

203-
def compare(self, idx, baseline, extension):
207+
def compare(self, idx, baseline, extension, *, _lock=False):
204208
__tracebackhide__ = True
205209
fignum = plt.get_fignums()[idx]
206210
fig = plt.figure(fignum)
@@ -214,10 +218,12 @@ def compare(self, idx, baseline, extension):
214218
kwargs.setdefault('metadata',
215219
{'Creator': None, 'Producer': None,
216220
'CreationDate': None})
217-
fig.savefig(actual_path, **kwargs)
218221

219-
expected_path = self.copy_baseline(baseline, extension)
220-
_raise_on_image_difference(expected_path, actual_path, self.tol)
222+
lock = cbook._lock_path(actual_path) if _lock else nullcontext()
223+
with lock:
224+
fig.savefig(actual_path, **kwargs)
225+
expected_path = self.copy_baseline(baseline, extension)
226+
_raise_on_image_difference(expected_path, actual_path, self.tol)
221227

222228

223229
def _pytest_image_comparison(baseline_images, extensions, tol,
@@ -254,6 +260,13 @@ def wrapper(*args, extension, request, **kwargs):
254260
matplotlib.testing.set_font_settings_for_testing()
255261
func(*args, **kwargs)
256262

263+
# If the test is parametrized in any way other than applied via
264+
# this decorator, then we need to use a lock to prevent two
265+
# processes from touching the same output file.
266+
needs_lock = any(
267+
marker.args[0] != 'extension'
268+
for marker in request.node.iter_markers('parametrize'))
269+
257270
if baseline_images is not None:
258271
our_baseline_images = baseline_images
259272
else:
@@ -266,7 +279,7 @@ def wrapper(*args, extension, request, **kwargs):
266279
"Test generated {} images but there are {} baseline images"
267280
.format(len(plt.get_fignums()), len(our_baseline_images)))
268281
for idx, baseline in enumerate(our_baseline_images):
269-
img.compare(idx, baseline, extension)
282+
img.compare(idx, baseline, extension, _lock=needs_lock)
270283

271284
parameters = list(old_sig.parameters.values())
272285
if 'extension' not in old_sig.parameters:

0 commit comments

Comments
 (0)