5252 Actual shape: {actual_shape}
5353 {actual_path}"""
5454
55+ # The following are the subsets of formats supported by the Matplotlib image
56+ # comparison machinery
57+ RASTER_IMAGE_FORMATS = ['png' ]
58+ VECTOR_IMAGE_FORMATS = ['eps' , 'pdf' , 'svg' ]
59+ ALL_IMAGE_FORMATS = RASTER_IMAGE_FORMATS + VECTOR_IMAGE_FORMATS
60+
5561
5662def _hash_file (in_stream ):
5763 """
@@ -70,8 +76,8 @@ def pathify(path):
7076 """
7177 path = Path (path )
7278 ext = ''
73- if path .suffixes [- 1 ] == '.png' :
74- ext = '.png'
79+ if path .suffixes [- 1 ][ 1 :] in ALL_IMAGE_FORMATS :
80+ ext = path . suffixes [ - 1 ]
7581 path = str (path ).split (ext )[0 ]
7682 path = str (path )
7783 path = path .replace ('[' , '_' ).replace (']' , '_' )
@@ -315,18 +321,24 @@ def __init__(self,
315321 self .logger .setLevel (level )
316322 self .logger .addHandler (handler )
317323
324+ def _file_extension (self , item ):
325+ compare = get_compare (item )
326+ savefig_kwargs = compare .kwargs .get ('savefig_kwargs' , {})
327+ return savefig_kwargs .get ('format' , 'png' )
328+
318329 def generate_filename (self , item ):
319330 """
320331 Given a pytest item, generate the figure filename.
321332 """
333+ ext = self ._file_extension (item )
322334 if self .config .getini ('mpl-use-full-test-name' ):
323- filename = generate_test_name (item ) + '.png '
335+ filename = generate_test_name (item ) + f'. { ext } '
324336 else :
325337 compare = get_compare (item )
326338 # Find test name to use as plot name
327339 filename = compare .kwargs .get ('filename' , None )
328340 if filename is None :
329- filename = item .name + '.png '
341+ filename = item .name + f'. { ext } '
330342
331343 filename = str (pathify (filename ))
332344 return filename
@@ -441,10 +453,10 @@ def generate_image_hash(self, item, fig):
441453 compare = get_compare (item )
442454 savefig_kwargs = compare .kwargs .get ('savefig_kwargs' , {})
443455
444- imgdata = io . BytesIO ( )
456+ ext = self . _file_extension ( item )
445457
458+ imgdata = io .BytesIO ()
446459 fig .savefig (imgdata , ** savefig_kwargs )
447-
448460 out = _hash_file (imgdata )
449461 imgdata .close ()
450462
@@ -465,11 +477,17 @@ def compare_image_to_baseline(self, item, fig, result_dir, summary=None):
465477 tolerance = compare .kwargs .get ('tolerance' , 2 )
466478 savefig_kwargs = compare .kwargs .get ('savefig_kwargs' , {})
467479
480+ ext = self ._file_extension (item )
481+
468482 baseline_image_ref = self .obtain_baseline_image (item , result_dir )
469483
470- test_image = (result_dir / "result.png " ).absolute ()
484+ test_image = (result_dir / f "result.{ ext } " ).absolute ()
471485 fig .savefig (str (test_image ), ** savefig_kwargs )
472- summary ['result_image' ] = test_image .relative_to (self .results_dir ).as_posix ()
486+
487+ if ext in ['png' , 'svg' ]: # Use original file
488+ summary ['result_image' ] = test_image .relative_to (self .results_dir ).as_posix ()
489+ else :
490+ summary ['result_image' ] = (result_dir / f"result_{ ext } .png" ).relative_to (self .results_dir ).as_posix ()
473491
474492 if not os .path .exists (baseline_image_ref ):
475493 summary ['status' ] = 'failed'
@@ -484,26 +502,33 @@ def compare_image_to_baseline(self, item, fig, result_dir, summary=None):
484502
485503 # setuptools may put the baseline images in non-accessible places,
486504 # copy to our tmpdir to be sure to keep them in case of failure
487- baseline_image = (result_dir / "baseline.png " ).absolute ()
505+ baseline_image = (result_dir / f "baseline.{ ext } " ).absolute ()
488506 shutil .copyfile (baseline_image_ref , baseline_image )
489- summary ['baseline_image' ] = baseline_image .relative_to (self .results_dir ).as_posix ()
507+
508+ if ext in ['png' , 'svg' ]: # Use original file
509+ summary ['baseline_image' ] = baseline_image .relative_to (self .results_dir ).as_posix ()
510+ else :
511+ summary ['baseline_image' ] = (result_dir / f"baseline_{ ext } .png" ).relative_to (self .results_dir ).as_posix ()
490512
491513 # Compare image size ourselves since the Matplotlib
492514 # exception is a bit cryptic in this case and doesn't show
493- # the filenames
494- expected_shape = imread (str (baseline_image )).shape [:2 ]
495- actual_shape = imread (str (test_image )).shape [:2 ]
496- if expected_shape != actual_shape :
497- summary ['status' ] = 'failed'
498- summary ['image_status' ] = 'diff'
499- error_message = SHAPE_MISMATCH_ERROR .format (expected_path = baseline_image ,
500- expected_shape = expected_shape ,
501- actual_path = test_image ,
502- actual_shape = actual_shape )
503- summary ['status_msg' ] = error_message
504- return error_message
515+ # the filenames. However imread won't work for vector graphics so we
516+ # only do this for raster files.
517+ if ext in RASTER_IMAGE_FORMATS :
518+ expected_shape = imread (str (baseline_image )).shape [:2 ]
519+ actual_shape = imread (str (test_image )).shape [:2 ]
520+ if expected_shape != actual_shape :
521+ summary ['status' ] = 'failed'
522+ summary ['image_status' ] = 'diff'
523+ error_message = SHAPE_MISMATCH_ERROR .format (expected_path = baseline_image ,
524+ expected_shape = expected_shape ,
525+ actual_path = test_image ,
526+ actual_shape = actual_shape )
527+ summary ['status_msg' ] = error_message
528+ return error_message
505529
506530 results = compare_images (str (baseline_image ), str (test_image ), tol = tolerance , in_decorator = True )
531+
507532 summary ['tolerance' ] = tolerance
508533 if results is None :
509534 summary ['status' ] = 'passed'
@@ -514,8 +539,7 @@ def compare_image_to_baseline(self, item, fig, result_dir, summary=None):
514539 summary ['status' ] = 'failed'
515540 summary ['image_status' ] = 'diff'
516541 summary ['rms' ] = results ['rms' ]
517- diff_image = (result_dir / 'result-failed-diff.png' ).absolute ()
518- summary ['diff_image' ] = diff_image .relative_to (self .results_dir ).as_posix ()
542+ summary ['diff_image' ] = Path (results ['diff' ]).relative_to (self .results_dir ).as_posix ()
519543 template = ['Error: Image files did not match.' ,
520544 'RMS Value: {rms}' ,
521545 'Expected: \n {expected}' ,
@@ -538,6 +562,8 @@ def compare_image_to_hash_library(self, item, fig, result_dir, summary=None):
538562 compare = get_compare (item )
539563 savefig_kwargs = compare .kwargs .get ('savefig_kwargs' , {})
540564
565+ ext = self ._file_extension (item )
566+
541567 if not self .results_hash_library_name :
542568 # Use hash library name of current test as results hash library name
543569 self .results_hash_library_name = Path (compare .kwargs .get ("hash_library" , "" )).name
@@ -574,7 +600,7 @@ def compare_image_to_hash_library(self, item, fig, result_dir, summary=None):
574600 f"{ hash_library_filename } for test { hash_name } ." )
575601
576602 # Save the figure for later summary (will be removed later if not needed)
577- test_image = (result_dir / "result.png " ).absolute ()
603+ test_image = (result_dir / f "result.{ ext } " ).absolute ()
578604 fig .savefig (str (test_image ), ** savefig_kwargs )
579605 summary ['result_image' ] = test_image .relative_to (self .results_dir ).as_posix ()
580606
@@ -627,6 +653,8 @@ def pytest_runtest_call(self, item): # noqa
627653 remove_text = compare .kwargs .get ('remove_text' , False )
628654 backend = compare .kwargs .get ('backend' , 'agg' )
629655
656+ ext = self ._file_extension (item )
657+
630658 with plt .style .context (style , after_reset = True ), switch_backend (backend ):
631659
632660 # Run test and get figure object
@@ -665,7 +693,7 @@ def pytest_runtest_call(self, item): # noqa
665693 summary ['status_msg' ] = 'Skipped test, since generating image.'
666694 generate_image = self .generate_baseline_image (item , fig )
667695 if self .results_always : # Make baseline image available in HTML
668- result_image = (result_dir / "baseline.png " ).absolute ()
696+ result_image = (result_dir / f "baseline.{ ext } " ).absolute ()
669697 shutil .copy (generate_image , result_image )
670698 summary ['baseline_image' ] = \
671699 result_image .relative_to (self .results_dir ).as_posix ()
0 commit comments