@@ -181,8 +181,6 @@ def pytest_configure(config):
181181 if generate_dir is not None :
182182 if baseline_dir is not None :
183183 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" )
186184
187185 if baseline_dir is not None and not baseline_dir .startswith (("https" , "http" )):
188186 baseline_dir = os .path .abspath (baseline_dir )
@@ -283,6 +281,12 @@ def __init__(self,
283281 self .results_dir = Path (tempfile .mkdtemp (dir = self .results_dir ))
284282 self .results_dir .mkdir (parents = True , exist_ok = True )
285283
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+
286290 # We need global state to store all the hashes generated over the run
287291 self ._generated_hash_library = {}
288292 self ._test_results = {}
@@ -390,11 +394,14 @@ def generate_baseline_image(self, item, fig):
390394 if not os .path .exists (self .generate_dir ):
391395 os .makedirs (self .generate_dir )
392396
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 )
395400
396401 close_mpl_figure (fig )
397402
403+ return baseline_path
404+
398405 def generate_image_hash (self , item , fig ):
399406 """
400407 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):
435442
436443 if not os .path .exists (baseline_image_ref ):
437444 summary ['status' ] = 'failed'
445+ summary ['image_status' ] = 'missing'
438446 error_message = ("Image file not found for comparison test in: \n \t "
439447 f"{ self .get_baseline_directory (item )} \n "
440448 "(This is expected for new tests.)\n "
@@ -456,6 +464,7 @@ def compare_image_to_baseline(self, item, fig, result_dir, summary=None):
456464 actual_shape = imread (str (test_image )).shape [:2 ]
457465 if expected_shape != actual_shape :
458466 summary ['status' ] = 'failed'
467+ summary ['image_status' ] = 'diff'
459468 error_message = SHAPE_MISMATCH_ERROR .format (expected_path = baseline_image ,
460469 expected_shape = expected_shape ,
461470 actual_path = test_image ,
@@ -467,10 +476,12 @@ def compare_image_to_baseline(self, item, fig, result_dir, summary=None):
467476 summary ['tolerance' ] = tolerance
468477 if results is None :
469478 summary ['status' ] = 'passed'
479+ summary ['image_status' ] = 'match'
470480 summary ['status_msg' ] = 'Image comparison passed.'
471481 return None
472482 else :
473483 summary ['status' ] = 'failed'
484+ summary ['image_status' ] = 'diff'
474485 summary ['rms' ] = results ['rms' ]
475486 diff_image = (result_dir / 'result-failed-diff.png' ).absolute ()
476487 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):
496507 compare = self .get_compare (item )
497508 savefig_kwargs = compare .kwargs .get ('savefig_kwargs' , {})
498509
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+
499514 hash_library_filename = self .hash_library or compare .kwargs .get ('hash_library' , None )
500515 hash_library_filename = (Path (item .fspath ).parent / hash_library_filename ).absolute ()
501516
@@ -512,14 +527,17 @@ def compare_image_to_hash_library(self, item, fig, result_dir, summary=None):
512527
513528 if baseline_hash is None : # hash-missing
514529 summary ['status' ] = 'failed'
530+ summary ['hash_status' ] = 'missing'
515531 summary ['status_msg' ] = (f"Hash for test '{ hash_name } ' not found in { hash_library_filename } . "
516532 f"Generated hash is { test_hash } ." )
517533 elif test_hash == baseline_hash : # hash-match
518534 hash_comparison_pass = True
519535 summary ['status' ] = 'passed'
536+ summary ['hash_status' ] = 'match'
520537 summary ['status_msg' ] = 'Test hash matches baseline hash.'
521538 else : # hash-diff
522539 summary ['status' ] = 'failed'
540+ summary ['hash_status' ] = 'diff'
523541 summary ['status_msg' ] = (f"Hash { test_hash } doesn't match hash "
524542 f"{ baseline_hash } in library "
525543 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):
544562 except Exception as baseline_error : # Append to test error later
545563 baseline_comparison = str (baseline_error )
546564 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' ]:
548567 summary [k ] = summary [k ] or baseline_summary .get (k )
549568
550569 # Append the log from image comparison
@@ -597,9 +616,12 @@ def item_function_wrapper(*args, **kwargs):
597616 remove_ticks_and_titles (fig )
598617
599618 test_name = self .generate_test_name (item )
619+ result_dir = self .make_test_results_dir (item )
600620
601621 summary = {
602622 'status' : None ,
623+ 'image_status' : None ,
624+ 'hash_status' : None ,
603625 'status_msg' : None ,
604626 'baseline_image' : None ,
605627 'diff_image' : None ,
@@ -614,21 +636,23 @@ def item_function_wrapper(*args, **kwargs):
614636 # reference images or simply running the test.
615637 if self .generate_dir is not None :
616638 summary ['status' ] = 'skipped'
639+ summary ['image_status' ] = 'generated'
617640 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 ()
622647
623648 if self .generate_hash_library is not None :
649+ summary ['hash_status' ] = 'generated'
624650 image_hash = self .generate_image_hash (item , fig )
625651 self ._generated_hash_library [test_name ] = image_hash
626- summary ['result_hash ' ] = image_hash
652+ summary ['baseline_hash ' ] = image_hash
627653
628654 # Only test figures if not generating images
629655 if self .generate_dir is None :
630- result_dir = self .make_test_results_dir (item )
631-
632656 # Compare to hash library
633657 if self .hash_library or compare .kwargs .get ('hash_library' , None ):
634658 msg = self .compare_image_to_hash_library (item , fig , result_dir , summary = summary )
@@ -645,12 +669,15 @@ def item_function_wrapper(*args, **kwargs):
645669 for image_type in ['baseline_image' , 'diff_image' , 'result_image' ]:
646670 summary [image_type ] = None # image no longer exists
647671 else :
648- self ._test_results [str ( pathify ( test_name )) ] = summary
672+ self ._test_results [test_name ] = summary
649673 pytest .fail (msg , pytrace = False )
650674
651675 close_mpl_figure (fig )
652676
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' ])
654681
655682 if item .cls is not None :
656683 setattr (item .cls , item .function .__name__ , item_function_wrapper )
@@ -667,21 +694,36 @@ def pytest_unconfigure(self, config):
667694 """
668695 Save out the hash library at the end of the run.
669696 """
697+ result_hash_library = self .results_dir / (self .results_hash_library_name or "temp.json" )
670698 if self .generate_hash_library is not None :
671699 hash_library_path = Path (config .rootdir ) / self .generate_hash_library
672700 hash_library_path .parent .mkdir (parents = True , exist_ok = True )
673701 with open (hash_library_path , "w" ) as fp :
674702 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 )
675713
676714 if self .generate_summary :
715+ kwargs = {}
677716 if 'json' in self .generate_summary :
678717 summary = self .generate_summary_json ()
679718 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
680721 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 )
682723 print (f"A summary of the failed tests can be found at: { summary } " )
683724 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 )
685727 print (f"A summary of the failed tests can be found at: { summary } " )
686728
687729
0 commit comments