9
9
import sys
10
10
import unittest
11
11
import warnings
12
+ try :
13
+ from contextlib import nullcontext
14
+ except ImportError :
15
+ from contextlib import ExitStack as nullcontext # Py3.6.
12
16
13
17
import matplotlib as mpl
14
18
import matplotlib .style
@@ -200,7 +204,7 @@ def copy_baseline(self, baseline, extension):
200
204
f"{ orig_expected_path } " ) from err
201
205
return expected_fname
202
206
203
- def compare (self , idx , baseline , extension ):
207
+ def compare (self , idx , baseline , extension , * , _lock = False ):
204
208
__tracebackhide__ = True
205
209
fignum = plt .get_fignums ()[idx ]
206
210
fig = plt .figure (fignum )
@@ -214,10 +218,12 @@ def compare(self, idx, baseline, extension):
214
218
kwargs .setdefault ('metadata' ,
215
219
{'Creator' : None , 'Producer' : None ,
216
220
'CreationDate' : None })
217
- fig .savefig (actual_path , ** kwargs )
218
221
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 )
221
227
222
228
223
229
def _pytest_image_comparison (baseline_images , extensions , tol ,
@@ -254,6 +260,13 @@ def wrapper(*args, extension, request, **kwargs):
254
260
matplotlib .testing .set_font_settings_for_testing ()
255
261
func (* args , ** kwargs )
256
262
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
+
257
270
if baseline_images is not None :
258
271
our_baseline_images = baseline_images
259
272
else :
@@ -266,7 +279,7 @@ def wrapper(*args, extension, request, **kwargs):
266
279
"Test generated {} images but there are {} baseline images"
267
280
.format (len (plt .get_fignums ()), len (our_baseline_images )))
268
281
for idx , baseline in enumerate (our_baseline_images ):
269
- img .compare (idx , baseline , extension )
282
+ img .compare (idx , baseline , extension , _lock = needs_lock )
270
283
271
284
parameters = list (old_sig .parameters .values ())
272
285
if 'extension' not in old_sig .parameters :
0 commit comments