99import sys
1010import unittest
1111import warnings
12+ try :
13+ from contextlib import nullcontext
14+ except ImportError :
15+ from contextlib import ExitStack as nullcontext # Py3.6.
1216
1317import matplotlib as mpl
1418import 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
223229def _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