@@ -181,8 +181,6 @@ def pytest_configure(config):
181
181
if generate_dir is not None :
182
182
if baseline_dir is not None :
183
183
warnings .warn ("Ignoring --mpl-baseline-path since --mpl-generate-path is set" )
184
- if results_dir is not None and generate_dir is not None :
185
- warnings .warn ("Ignoring --mpl-result-path since --mpl-generate-path is set" )
186
184
187
185
if baseline_dir is not None and not baseline_dir .startswith (("https" , "http" )):
188
186
baseline_dir = os .path .abspath (baseline_dir )
@@ -283,6 +281,12 @@ def __init__(self,
283
281
self .results_dir = Path (tempfile .mkdtemp (dir = self .results_dir ))
284
282
self .results_dir .mkdir (parents = True , exist_ok = True )
285
283
284
+ # Decide what to call the downloadable results hash library
285
+ if self .hash_library is not None :
286
+ self .results_hash_library_name = self .hash_library .name
287
+ else : # Use the first filename encountered in a `hash_library=` kwarg
288
+ self .results_hash_library_name = None
289
+
286
290
# We need global state to store all the hashes generated over the run
287
291
self ._generated_hash_library = {}
288
292
self ._test_results = {}
@@ -390,11 +394,14 @@ def generate_baseline_image(self, item, fig):
390
394
if not os .path .exists (self .generate_dir ):
391
395
os .makedirs (self .generate_dir )
392
396
393
- fig .savefig (str ((self .generate_dir / self .generate_filename (item )).absolute ()),
394
- ** savefig_kwargs )
397
+ baseline_filename = self .generate_filename (item )
398
+ baseline_path = (self .generate_dir / baseline_filename ).absolute ()
399
+ fig .savefig (str (baseline_path ), ** savefig_kwargs )
395
400
396
401
close_mpl_figure (fig )
397
402
403
+ return baseline_path
404
+
398
405
def generate_image_hash (self , item , fig ):
399
406
"""
400
407
For a `matplotlib.figure.Figure`, returns the SHA256 hash as a hexadecimal
@@ -435,6 +442,7 @@ def compare_image_to_baseline(self, item, fig, result_dir, summary=None):
435
442
436
443
if not os .path .exists (baseline_image_ref ):
437
444
summary ['status' ] = 'failed'
445
+ summary ['image_status' ] = 'missing'
438
446
error_message = ("Image file not found for comparison test in: \n \t "
439
447
f"{ self .get_baseline_directory (item )} \n "
440
448
"(This is expected for new tests.)\n "
@@ -456,6 +464,7 @@ def compare_image_to_baseline(self, item, fig, result_dir, summary=None):
456
464
actual_shape = imread (str (test_image )).shape [:2 ]
457
465
if expected_shape != actual_shape :
458
466
summary ['status' ] = 'failed'
467
+ summary ['image_status' ] = 'diff'
459
468
error_message = SHAPE_MISMATCH_ERROR .format (expected_path = baseline_image ,
460
469
expected_shape = expected_shape ,
461
470
actual_path = test_image ,
@@ -467,10 +476,12 @@ def compare_image_to_baseline(self, item, fig, result_dir, summary=None):
467
476
summary ['tolerance' ] = tolerance
468
477
if results is None :
469
478
summary ['status' ] = 'passed'
479
+ summary ['image_status' ] = 'match'
470
480
summary ['status_msg' ] = 'Image comparison passed.'
471
481
return None
472
482
else :
473
483
summary ['status' ] = 'failed'
484
+ summary ['image_status' ] = 'diff'
474
485
summary ['rms' ] = results ['rms' ]
475
486
diff_image = (result_dir / 'result-failed-diff.png' ).absolute ()
476
487
summary ['diff_image' ] = diff_image .relative_to (self .results_dir ).as_posix ()
@@ -496,6 +507,10 @@ def compare_image_to_hash_library(self, item, fig, result_dir, summary=None):
496
507
compare = self .get_compare (item )
497
508
savefig_kwargs = compare .kwargs .get ('savefig_kwargs' , {})
498
509
510
+ if not self .results_hash_library_name :
511
+ # Use hash library name of current test as results hash library name
512
+ self .results_hash_library_name = Path (compare .kwargs .get ("hash_library" , "" )).name
513
+
499
514
hash_library_filename = self .hash_library or compare .kwargs .get ('hash_library' , None )
500
515
hash_library_filename = (Path (item .fspath ).parent / hash_library_filename ).absolute ()
501
516
@@ -512,14 +527,17 @@ def compare_image_to_hash_library(self, item, fig, result_dir, summary=None):
512
527
513
528
if baseline_hash is None : # hash-missing
514
529
summary ['status' ] = 'failed'
530
+ summary ['hash_status' ] = 'missing'
515
531
summary ['status_msg' ] = (f"Hash for test '{ hash_name } ' not found in { hash_library_filename } . "
516
532
f"Generated hash is { test_hash } ." )
517
533
elif test_hash == baseline_hash : # hash-match
518
534
hash_comparison_pass = True
519
535
summary ['status' ] = 'passed'
536
+ summary ['hash_status' ] = 'match'
520
537
summary ['status_msg' ] = 'Test hash matches baseline hash.'
521
538
else : # hash-diff
522
539
summary ['status' ] = 'failed'
540
+ summary ['hash_status' ] = 'diff'
523
541
summary ['status_msg' ] = (f"Hash { test_hash } doesn't match hash "
524
542
f"{ baseline_hash } in library "
525
543
f"{ hash_library_filename } for test { hash_name } ." )
@@ -544,7 +562,8 @@ def compare_image_to_hash_library(self, item, fig, result_dir, summary=None):
544
562
except Exception as baseline_error : # Append to test error later
545
563
baseline_comparison = str (baseline_error )
546
564
else : # Update main summary
547
- for k in ['baseline_image' , 'diff_image' , 'rms' , 'tolerance' , 'result_image' ]:
565
+ for k in ['image_status' , 'baseline_image' , 'diff_image' ,
566
+ 'rms' , 'tolerance' , 'result_image' ]:
548
567
summary [k ] = summary [k ] or baseline_summary .get (k )
549
568
550
569
# Append the log from image comparison
@@ -597,9 +616,12 @@ def item_function_wrapper(*args, **kwargs):
597
616
remove_ticks_and_titles (fig )
598
617
599
618
test_name = self .generate_test_name (item )
619
+ result_dir = self .make_test_results_dir (item )
600
620
601
621
summary = {
602
622
'status' : None ,
623
+ 'image_status' : None ,
624
+ 'hash_status' : None ,
603
625
'status_msg' : None ,
604
626
'baseline_image' : None ,
605
627
'diff_image' : None ,
@@ -614,21 +636,23 @@ def item_function_wrapper(*args, **kwargs):
614
636
# reference images or simply running the test.
615
637
if self .generate_dir is not None :
616
638
summary ['status' ] = 'skipped'
639
+ summary ['image_status' ] = 'generated'
617
640
summary ['status_msg' ] = 'Skipped test, since generating image.'
618
- self .generate_baseline_image (item , fig )
619
- if self .generate_hash_library is None :
620
- self ._test_results [str (pathify (test_name ))] = summary
621
- pytest .skip ("Skipping test, since generating image." )
641
+ generate_image = self .generate_baseline_image (item , fig )
642
+ if self .results_always : # Make baseline image available in HTML
643
+ result_image = (result_dir / "baseline.png" ).absolute ()
644
+ shutil .copy (generate_image , result_image )
645
+ summary ['baseline_image' ] = \
646
+ result_image .relative_to (self .results_dir ).as_posix ()
622
647
623
648
if self .generate_hash_library is not None :
649
+ summary ['hash_status' ] = 'generated'
624
650
image_hash = self .generate_image_hash (item , fig )
625
651
self ._generated_hash_library [test_name ] = image_hash
626
- summary ['result_hash ' ] = image_hash
652
+ summary ['baseline_hash ' ] = image_hash
627
653
628
654
# Only test figures if not generating images
629
655
if self .generate_dir is None :
630
- result_dir = self .make_test_results_dir (item )
631
-
632
656
# Compare to hash library
633
657
if self .hash_library or compare .kwargs .get ('hash_library' , None ):
634
658
msg = self .compare_image_to_hash_library (item , fig , result_dir , summary = summary )
@@ -645,12 +669,15 @@ def item_function_wrapper(*args, **kwargs):
645
669
for image_type in ['baseline_image' , 'diff_image' , 'result_image' ]:
646
670
summary [image_type ] = None # image no longer exists
647
671
else :
648
- self ._test_results [str ( pathify ( test_name )) ] = summary
672
+ self ._test_results [test_name ] = summary
649
673
pytest .fail (msg , pytrace = False )
650
674
651
675
close_mpl_figure (fig )
652
676
653
- self ._test_results [str (pathify (test_name ))] = summary
677
+ self ._test_results [test_name ] = summary
678
+
679
+ if summary ['status' ] == 'skipped' :
680
+ pytest .skip (summary ['status_msg' ])
654
681
655
682
if item .cls is not None :
656
683
setattr (item .cls , item .function .__name__ , item_function_wrapper )
@@ -667,21 +694,36 @@ def pytest_unconfigure(self, config):
667
694
"""
668
695
Save out the hash library at the end of the run.
669
696
"""
697
+ result_hash_library = self .results_dir / (self .results_hash_library_name or "temp.json" )
670
698
if self .generate_hash_library is not None :
671
699
hash_library_path = Path (config .rootdir ) / self .generate_hash_library
672
700
hash_library_path .parent .mkdir (parents = True , exist_ok = True )
673
701
with open (hash_library_path , "w" ) as fp :
674
702
json .dump (self ._generated_hash_library , fp , indent = 2 )
703
+ if self .results_always : # Make accessible in results directory
704
+ # Use same name as generated
705
+ result_hash_library = self .results_dir / hash_library_path .name
706
+ shutil .copy (hash_library_path , result_hash_library )
707
+ elif self .results_always and self .results_hash_library_name :
708
+ result_hashes = {k : v ['result_hash' ] for k , v in self ._test_results .items ()
709
+ if v ['result_hash' ]}
710
+ if len (result_hashes ) > 0 : # At least one hash comparison test
711
+ with open (result_hash_library , "w" ) as fp :
712
+ json .dump (result_hashes , fp , indent = 2 )
675
713
676
714
if self .generate_summary :
715
+ kwargs = {}
677
716
if 'json' in self .generate_summary :
678
717
summary = self .generate_summary_json ()
679
718
print (f"A JSON report can be found at: { summary } " )
719
+ if result_hash_library .exists (): # link to it in the HTML
720
+ kwargs ["hash_library" ] = result_hash_library .name
680
721
if 'html' in self .generate_summary :
681
- summary = generate_summary_html (self ._test_results , self .results_dir )
722
+ summary = generate_summary_html (self ._test_results , self .results_dir , ** kwargs )
682
723
print (f"A summary of the failed tests can be found at: { summary } " )
683
724
if 'basic-html' in self .generate_summary :
684
- summary = generate_summary_basic_html (self ._test_results , self .results_dir )
725
+ summary = generate_summary_basic_html (self ._test_results , self .results_dir ,
726
+ ** kwargs )
685
727
print (f"A summary of the failed tests can be found at: { summary } " )
686
728
687
729
0 commit comments