Skip to content

Commit 6a50d95

Browse files
committed
Implement always compare mode for hash library
1 parent 7bb5d44 commit 6a50d95

File tree

1 file changed

+56
-19
lines changed

1 file changed

+56
-19
lines changed

pytest_mpl/plugin.py

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ def pytest_addoption(parser):
155155
results_path_help = "directory for test results, relative to location where py.test is run"
156156
group.addoption('--mpl-results-path', help=results_path_help, action='store')
157157
parser.addini('mpl-results-path', help=results_path_help)
158+
159+
results_always_help = "Always generate result images, not just for failed tests."
160+
group.addoption('--mpl-results-always', action='store_true',
161+
help=results_always_help)
162+
parser.addini('mpl-results-always', help=results_always_help)
163+
158164
parser.addini('mpl-use-full-test-name', help="use fully qualified test name as the filename.",
159165
type='bool')
160166

@@ -175,6 +181,8 @@ def pytest_configure(config):
175181
results_dir = config.getoption("--mpl-results-path") or config.getini("mpl-results-path")
176182
hash_library = config.getoption("--mpl-hash-library")
177183
generate_summary = config.getoption("--mpl-generate-summary")
184+
results_always = config.getoption("--mpl-results-always") or config.getini("mpl-results-always")
185+
178186

179187
if config.getoption("--mpl-baseline-relative"):
180188
baseline_relative_dir = config.getoption("--mpl-baseline-path")
@@ -205,7 +213,8 @@ def pytest_configure(config):
205213
results_dir=results_dir,
206214
hash_library=hash_library,
207215
generate_hash_library=generate_hash_lib,
208-
generate_summary=generate_summary))
216+
generate_summary=generate_summary,
217+
results_always=results_always))
209218

210219
else:
211220

@@ -262,7 +271,8 @@ def __init__(self,
262271
results_dir=None,
263272
hash_library=None,
264273
generate_hash_library=None,
265-
generate_summary=None
274+
generate_summary=None,
275+
results_always=False
266276
):
267277
self.config = config
268278
self.baseline_dir = baseline_dir
@@ -274,6 +284,7 @@ def __init__(self,
274284
if generate_summary and generate_summary.lower() not in ("html",):
275285
raise ValueError(f"The mpl summary type '{generate_summary}' is not supported.")
276286
self.generate_summary = generate_summary
287+
self.results_always = results_always
277288

278289
# Generate the containing dir for all test results
279290
if not self.results_dir:
@@ -389,7 +400,6 @@ def generate_baseline_image(self, item, fig):
389400
**savefig_kwargs)
390401

391402
close_mpl_figure(fig)
392-
pytest.skip("Skipping test, since generating image")
393403

394404
def generate_image_hash(self, item, fig):
395405
"""
@@ -455,6 +465,10 @@ def load_hash_library(self, library_path):
455465
return json.load(fp)
456466

457467
def compare_image_to_hash_library(self, item, fig, result_dir):
468+
new_test = False
469+
hash_comparison_pass = False
470+
baseline_image_path = None
471+
458472
compare = self.get_compare(item)
459473
savefig_kwargs = compare.kwargs.get('savefig_kwargs', {})
460474

@@ -470,41 +484,60 @@ def compare_image_to_hash_library(self, item, fig, result_dir):
470484
test_hash = self.generate_image_hash(item, fig)
471485

472486
if hash_name not in hash_library:
473-
return (f"Hash for test '{hash_name}' not found in {hash_library_filename}. "
474-
f"Generated hash is {test_hash}.")
487+
new_test = True
488+
error_message = (f"Hash for test '{hash_name}' not found in {hash_library_filename}. "
489+
f"Generated hash is {test_hash}.")
475490

476-
if test_hash == hash_library[hash_name]:
477-
return
478491

479-
error_message = (f"Hash {test_hash} doesn't match hash "
480-
f"{hash_library[hash_name]} in library "
481-
f"{hash_library_filename} for test {hash_name}.")
492+
# Save the figure for later summary (will be removed later if not needed)
493+
test_image = (result_dir / "result.png").absolute()
494+
fig.savefig(str(test_image), **savefig_kwargs)
495+
496+
if not new_test:
497+
if test_hash == hash_library[hash_name]:
498+
hash_comparison_pass = True
499+
else:
500+
error_message = (f"Hash {test_hash} doesn't match hash "
501+
f"{hash_library[hash_name]} in library "
502+
f"{hash_library_filename} for test {hash_name}.")
482503

483504
# If the compare has only been specified with hash and not baseline
484505
# dir, don't attempt to find a baseline image at the default path.
485-
if not self.baseline_directory_specified(item):
486-
# Save the figure for later summary
487-
test_image = (result_dir / "result.png").absolute()
488-
fig.savefig(str(test_image), **savefig_kwargs)
506+
if not hash_comparison_pass and not self.baseline_directory_specified(item) or new_test:
489507
return error_message
490508

491-
baseline_image_path = self.obtain_baseline_image(item, result_dir)
509+
# Get the baseline and generate a diff image, always so that
510+
# --mpl-results-always can be respected.
511+
# Ignore Errors here as it's possible the reference image dosen't exist yet.
512+
try:
513+
baseline_comparison = self.compare_image_to_baseline(item, fig, result_dir)
514+
except Exception as e:
515+
pass
516+
517+
# If the hash comparison passes then return
518+
if hash_comparison_pass:
519+
return
520+
521+
# If this is not a new test try and get the baseline image.
522+
if not new_test:
523+
baseline_image_path = self.obtain_baseline_image(item, result_dir)
524+
492525
try:
493526
baseline_image = baseline_image_path
494-
baseline_image = None if not baseline_image.exists() else baseline_image
527+
baseline_image = None if (baseline_image and not baseline_image.exists()) else baseline_image
495528
except Exception:
496529
baseline_image = None
497530

498531
if baseline_image is None:
499-
error_message += f"\nUnable to find baseline image {baseline_image_path}."
532+
error_message += f"\nUnable to find baseline image {baseline_image_path or ''}."
500533
return error_message
501534

502535
# Override the tolerance (if not explicitly set) to 0 as the hashes are not forgiving
503536
tolerance = compare.kwargs.get('tolerance', None)
504537
if not tolerance:
505538
compare.kwargs['tolerance'] = 0
506539

507-
comparison_error = (self.compare_image_to_baseline(item, fig, result_dir) or
540+
comparison_error = (baseline_comparison or
508541
"\nHowever, the comparison to the baseline image succeeded.")
509542

510543
return f"{error_message}\n{comparison_error}"
@@ -552,10 +585,13 @@ def item_function_wrapper(*args, **kwargs):
552585
# reference images or simply running the test.
553586
if self.generate_dir is not None:
554587
self.generate_baseline_image(item, fig)
588+
if self.generate_hash_library is None:
589+
pytest.skip("Skipping test, since generating image.")
555590

556591
if self.generate_hash_library is not None:
557592
hash_name = self.generate_test_name(item)
558593
self._generated_hash_library[hash_name] = self.generate_image_hash(item, fig)
594+
pytest.skip("Skipping test as generating hash library.")
559595

560596
# Only test figures if we are not generating hashes or images
561597
if self.generate_dir is None and self.generate_hash_library is None:
@@ -572,7 +608,8 @@ def item_function_wrapper(*args, **kwargs):
572608
close_mpl_figure(fig)
573609

574610
if msg is None:
575-
shutil.rmtree(result_dir)
611+
if not self.results_always:
612+
shutil.rmtree(result_dir)
576613
else:
577614
pytest.fail(msg, pytrace=False)
578615

0 commit comments

Comments
 (0)