Skip to content

Commit 7fdcce6

Browse files
committed
Implement always compare mode for hash library
1 parent 01c5ec3 commit 7fdcce6

File tree

1 file changed

+54
-18
lines changed

1 file changed

+54
-18
lines changed

pytest_mpl/plugin.py

+54-18
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

@@ -468,42 +482,60 @@ def compare_image_to_hash_library(self, item, fig, result_dir):
468482
hash_name = self.generate_test_name(item)
469483

470484
if hash_name not in hash_library:
471-
return f"Hash for test '{hash_name}' not found in {hash_library_filename}."
485+
new_test = True
486+
error_message = f"Hash for test '{hash_name}' not found in {hash_library_filename}."
472487

473488
test_hash = self.generate_image_hash(item, fig)
474489

475-
if test_hash == hash_library[hash_name]:
476-
return
490+
# Save the figure for later summary (will be removed later if not needed)
491+
test_image = (result_dir / "result.png").absolute()
492+
fig.savefig(str(test_image), **savefig_kwargs)
477493

478-
error_message = (f"Hash {test_hash} doesn't match hash "
479-
f"{hash_library[hash_name]} in library "
480-
f"{hash_library_filename} for test {hash_name}.")
494+
if not new_test:
495+
if test_hash == hash_library[hash_name]:
496+
hash_comparison_pass = True
497+
else:
498+
error_message = (f"Hash {test_hash} doesn't match hash "
499+
f"{hash_library[hash_name]} in library "
500+
f"{hash_library_filename} for test {hash_name}.")
481501

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

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

497529
if baseline_image is None:
498-
error_message += f"\nUnable to find baseline image {baseline_image_path}."
530+
error_message += f"\nUnable to find baseline image {baseline_image_path or ''}."
499531
return error_message
500532

501533
# Override the tolerance (if not explicitly set) to 0 as the hashes are not forgiving
502534
tolerance = compare.kwargs.get('tolerance', None)
503535
if not tolerance:
504536
compare.kwargs['tolerance'] = 0
505537

506-
comparison_error = (self.compare_image_to_baseline(item, fig, result_dir) or
538+
comparison_error = (baseline_comparison or
507539
"\nHowever, the comparison to the baseline image succeeded.")
508540

509541
return f"{error_message}\n{comparison_error}"
@@ -551,10 +583,13 @@ def item_function_wrapper(*args, **kwargs):
551583
# reference images or simply running the test.
552584
if self.generate_dir is not None:
553585
self.generate_baseline_image(item, fig)
586+
if self.generate_hash_library is None:
587+
pytest.skip("Skipping test, since generating image.")
554588

555589
if self.generate_hash_library is not None:
556590
hash_name = self.generate_test_name(item)
557591
self._generated_hash_library[hash_name] = self.generate_image_hash(item, fig)
592+
pytest.skip("Skipping test as generating hash library.")
558593

559594
# Only test figures if we are not generating hashes or images
560595
if self.generate_dir is None and self.generate_hash_library is None:
@@ -571,7 +606,8 @@ def item_function_wrapper(*args, **kwargs):
571606
close_mpl_figure(fig)
572607

573608
if msg is None:
574-
shutil.rmtree(result_dir)
609+
if not self.results_always:
610+
shutil.rmtree(result_dir)
575611
else:
576612
pytest.fail(msg, pytrace=False)
577613

0 commit comments

Comments
 (0)