Skip to content

Commit 03cf9e4

Browse files
committed
Added support for EPS, PDF, and SVG image comparison
1 parent dfe07f9 commit 03cf9e4

File tree

6 files changed

+1297
-20
lines changed

6 files changed

+1297
-20
lines changed

pytest_mpl/plugin.py

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@
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

5662
def _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
@@ -465,9 +477,11 @@ 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)
472486
summary['result_image'] = test_image.relative_to(self.results_dir).as_posix()
473487

@@ -484,24 +498,26 @@ def compare_image_to_baseline(self, item, fig, result_dir, summary=None):
484498

485499
# setuptools may put the baseline images in non-accessible places,
486500
# copy to our tmpdir to be sure to keep them in case of failure
487-
baseline_image = (result_dir / "baseline.png").absolute()
501+
baseline_image = (result_dir / f"baseline.{ext}").absolute()
488502
shutil.copyfile(baseline_image_ref, baseline_image)
489503
summary['baseline_image'] = baseline_image.relative_to(self.results_dir).as_posix()
490504

491505
# Compare image size ourselves since the Matplotlib
492506
# 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
507+
# the filenames. However imread won't work for vector graphics so we
508+
# only do this for raster files.
509+
if ext in RASTER_IMAGE_FORMATS:
510+
expected_shape = imread(str(baseline_image)).shape[:2]
511+
actual_shape = imread(str(test_image)).shape[:2]
512+
if expected_shape != actual_shape:
513+
summary['status'] = 'failed'
514+
summary['image_status'] = 'diff'
515+
error_message = SHAPE_MISMATCH_ERROR.format(expected_path=baseline_image,
516+
expected_shape=expected_shape,
517+
actual_path=test_image,
518+
actual_shape=actual_shape)
519+
summary['status_msg'] = error_message
520+
return error_message
505521

506522
results = compare_images(str(baseline_image), str(test_image), tol=tolerance, in_decorator=True)
507523
summary['tolerance'] = tolerance
@@ -538,6 +554,8 @@ def compare_image_to_hash_library(self, item, fig, result_dir, summary=None):
538554
compare = get_compare(item)
539555
savefig_kwargs = compare.kwargs.get('savefig_kwargs', {})
540556

557+
ext = self._file_extension(item)
558+
541559
if not self.results_hash_library_name:
542560
# Use hash library name of current test as results hash library name
543561
self.results_hash_library_name = Path(compare.kwargs.get("hash_library", "")).name
@@ -574,7 +592,7 @@ def compare_image_to_hash_library(self, item, fig, result_dir, summary=None):
574592
f"{hash_library_filename} for test {hash_name}.")
575593

576594
# Save the figure for later summary (will be removed later if not needed)
577-
test_image = (result_dir / "result.png").absolute()
595+
test_image = (result_dir / f"result.{ext}").absolute()
578596
fig.savefig(str(test_image), **savefig_kwargs)
579597
summary['result_image'] = test_image.relative_to(self.results_dir).as_posix()
580598

@@ -627,6 +645,8 @@ def pytest_runtest_call(self, item): # noqa
627645
remove_text = compare.kwargs.get('remove_text', False)
628646
backend = compare.kwargs.get('backend', 'agg')
629647

648+
ext = self._file_extension(item)
649+
630650
with plt.style.context(style, after_reset=True), switch_backend(backend):
631651

632652
# Run test and get figure object
@@ -665,7 +685,7 @@ def pytest_runtest_call(self, item): # noqa
665685
summary['status_msg'] = 'Skipped test, since generating image.'
666686
generate_image = self.generate_baseline_image(item, fig)
667687
if self.results_always: # Make baseline image available in HTML
668-
result_image = (result_dir / "baseline.png").absolute()
688+
result_image = (result_dir / f"baseline.{ext}").absolute()
669689
shutil.copy(generate_image, result_image)
670690
summary['baseline_image'] = \
671691
result_image.relative_to(self.results_dir).as_posix()

0 commit comments

Comments
 (0)