@@ -444,7 +444,7 @@ def test_op_different__attribute_value(self, op_leniency):
444444        lmetadata  =  self .cls (** self .lvalues )
445445        rmetadata  =  self .cls (** self .rvalues )
446446
447-         # Result contains  entirely EMPTY attributes (either  strict or lenient). 
447+         # Result has  entirely EMPTY attributes (whether  strict or lenient). 
448448        # TODO: is this maybe a mistake of the existing implementation ? 
449449        expected  =  self .lvalues .copy ()
450450        expected ["attributes" ] =  None 
@@ -457,30 +457,31 @@ def test_op_different__attribute_value(self, op_leniency):
457457            assert  rmetadata .combine (lmetadata )._asdict () ==  expected 
458458
459459
460- class  Test_difference (tests .IrisTest ):
461-     def  setUp (self ):
462-         self .values  =  dict (
460+ class  Test_difference :
461+     @pytest .fixture (autouse = True ) 
462+     def  setup (self ):
463+         self .lvalues  =  dict (
463464            standard_name = sentinel .standard_name ,
464465            long_name = sentinel .long_name ,
465466            var_name = sentinel .var_name ,
466467            units = sentinel .units ,
467-             attributes = sentinel . attributes , 
468+             attributes = dict (),   # MUST be a dict 
468469            cell_methods = sentinel .cell_methods ,
469470        )
471+         # Make a copy with all-different objects in it. 
472+         self .rvalues  =  deepcopy (self .lvalues )
470473        self .dummy  =  sentinel .dummy 
471474        self .cls  =  CubeMetadata 
472475        self .none  =  self .cls (* (None ,) *  len (self .cls ._fields ))
473476
474477    def  test_wraps_docstring (self ):
475-         self .assertEqual (
476-             BaseMetadata .difference .__doc__ , self .cls .difference .__doc__ 
477-         )
478+         assert  self .cls .difference .__doc__  ==  BaseMetadata .difference .__doc__ 
478479
479480    def  test_lenient_service (self ):
480481        qualname_difference  =  _qualname (self .cls .difference )
481-         self . assertIn ( qualname_difference ,  _LENIENT ) 
482-         self . assertTrue ( _LENIENT [qualname_difference ]) 
483-         self . assertTrue ( _LENIENT [self .cls .difference ]) 
482+         assert   qualname_difference   in   _LENIENT 
483+         assert   _LENIENT [qualname_difference ]
484+         assert   _LENIENT [self .cls .difference ]
484485
485486    def  test_lenient_default (self ):
486487        other  =  sentinel .other 
@@ -490,11 +491,8 @@ def test_lenient_default(self):
490491        ) as  mocker :
491492            result  =  self .none .difference (other )
492493
493-         self .assertEqual (return_value , result )
494-         self .assertEqual (1 , mocker .call_count )
495-         (arg ,), kwargs  =  mocker .call_args 
496-         self .assertEqual (other , arg )
497-         self .assertEqual (dict (lenient = None ), kwargs )
494+         assert  return_value  ==  result 
495+         assert  mocker .call_args_list  ==  [mock .call (other , lenient = None )]
498496
499497    def  test_lenient (self ):
500498        other  =  sentinel .other 
@@ -505,178 +503,124 @@ def test_lenient(self):
505503        ) as  mocker :
506504            result  =  self .none .difference (other , lenient = lenient )
507505
508-         self .assertEqual (return_value , result )
509-         self .assertEqual (1 , mocker .call_count )
510-         (arg ,), kwargs  =  mocker .call_args 
511-         self .assertEqual (other , arg )
512-         self .assertEqual (dict (lenient = lenient ), kwargs )
506+         assert  return_value  ==  result 
507+         assert  mocker .call_args_list  ==  [mock .call (other , lenient = lenient )]
513508
514-     def  test_op_lenient_same (self ):
515-         lmetadata  =  self .cls (** self .values )
516-         rmetadata  =  self .cls (** self .values )
517- 
518-         with  mock .patch ("iris.common.metadata._LENIENT" , return_value = True ):
519-             self .assertIsNone (lmetadata .difference (rmetadata ))
520-             self .assertIsNone (rmetadata .difference (lmetadata ))
521- 
522-     def  test_op_lenient_same_none (self ):
523-         lmetadata  =  self .cls (** self .values )
524-         right  =  self .values .copy ()
525-         right ["var_name" ] =  None 
526-         rmetadata  =  self .cls (** right )
527- 
528-         with  mock .patch ("iris.common.metadata._LENIENT" , return_value = True ):
529-             self .assertIsNone (lmetadata .difference (rmetadata ))
530-             self .assertIsNone (rmetadata .difference (lmetadata ))
531- 
532-     def  test_op_lenient_same_cell_methods_none (self ):
533-         lmetadata  =  self .cls (** self .values )
534-         right  =  self .values .copy ()
535-         right ["cell_methods" ] =  None 
536-         rmetadata  =  self .cls (** right )
537-         lexpected  =  deepcopy (self .none )._asdict ()
538-         lexpected ["cell_methods" ] =  (sentinel .cell_methods , None )
539-         rexpected  =  deepcopy (self .none )._asdict ()
540-         rexpected ["cell_methods" ] =  (None , sentinel .cell_methods )
541- 
542-         with  mock .patch ("iris.common.metadata._LENIENT" , return_value = True ):
543-             self .assertEqual (
544-                 lexpected , lmetadata .difference (rmetadata )._asdict ()
545-             )
546-             self .assertEqual (
547-                 rexpected , rmetadata .difference (lmetadata )._asdict ()
548-             )
509+     def  test_op_same (self , op_leniency ):
510+         is_lenient  =  op_leniency  ==  "lenient" 
511+         lmetadata  =  self .cls (** self .lvalues )
512+         rmetadata  =  self .cls (** self .rvalues )
549513
550-     def  test_op_lenient_different (self ):
551-         left  =  self .values .copy ()
552-         lmetadata  =  self .cls (** left )
553-         right  =  self .values .copy ()
554-         right ["units" ] =  self .dummy 
555-         rmetadata  =  self .cls (** right )
556-         lexpected  =  deepcopy (self .none )._asdict ()
557-         lexpected ["units" ] =  (left ["units" ], right ["units" ])
558-         rexpected  =  deepcopy (self .none )._asdict ()
559-         rexpected ["units" ] =  lexpected ["units" ][::- 1 ]
560- 
561-         with  mock .patch ("iris.common.metadata._LENIENT" , return_value = True ):
562-             self .assertEqual (
563-                 lexpected , lmetadata .difference (rmetadata )._asdict ()
564-             )
565-             self .assertEqual (
566-                 rexpected , rmetadata .difference (lmetadata )._asdict ()
567-             )
514+         with  mock .patch (
515+             "iris.common.metadata._LENIENT" , return_value = is_lenient 
516+         ):
517+             assert  lmetadata .difference (rmetadata ) is  None 
518+             assert  rmetadata .difference (lmetadata ) is  None 
568519
569-     def  test_op_lenient_different_cell_methods (self ):
570-         left  =  self .values .copy ()
571-         lmetadata  =  self .cls (** left )
572-         right  =  self .values .copy ()
573-         right ["cell_methods" ] =  self .dummy 
574-         rmetadata  =  self .cls (** right )
575-         lexpected  =  deepcopy (self .none )._asdict ()
576-         lexpected ["cell_methods" ] =  (
577-             left ["cell_methods" ],
578-             right ["cell_methods" ],
579-         )
580-         rexpected  =  deepcopy (self .none )._asdict ()
581-         rexpected ["cell_methods" ] =  lexpected ["cell_methods" ][::- 1 ]
520+     def  test_op_different__none (self , fieldname , op_leniency ):
521+         if  fieldname  in  ("attributes" ,):  # 'units'): 
522+             # These cannot properly be set to 'None'.  Tested elsewhere. 
523+             pytest .skip ()
582524
583-         with  mock .patch ("iris.common.metadata._LENIENT" , return_value = True ):
584-             self .assertEqual (
585-                 lexpected , lmetadata .difference (rmetadata )._asdict ()
586-             )
587-             self .assertEqual (
588-                 rexpected , rmetadata .difference (lmetadata )._asdict ()
589-             )
525+         is_lenient  =  op_leniency  ==  "lenient" 
526+ 
527+         lmetadata  =  self .cls (** self .lvalues )
528+         self .rvalues [fieldname ] =  None 
529+         rmetadata  =  self .cls (** self .rvalues )
590530
591-     def  test_op_strict_same (self ):
592-         lmetadata  =  self .cls (** self .values )
593-         rmetadata  =  self .cls (** self .values )
594- 
595-         with  mock .patch ("iris.common.metadata._LENIENT" , return_value = False ):
596-             self .assertIsNone (lmetadata .difference (rmetadata ))
597-             self .assertIsNone (rmetadata .difference (lmetadata ))
598- 
599-     def  test_op_strict_different (self ):
600-         left  =  self .values .copy ()
601-         lmetadata  =  self .cls (** left )
602-         right  =  self .values .copy ()
603-         right ["long_name" ] =  self .dummy 
604-         rmetadata  =  self .cls (** right )
605-         lexpected  =  deepcopy (self .none )._asdict ()
606-         lexpected ["long_name" ] =  (left ["long_name" ], right ["long_name" ])
607-         rexpected  =  deepcopy (self .none )._asdict ()
608-         rexpected ["long_name" ] =  lexpected ["long_name" ][::- 1 ]
609- 
610-         with  mock .patch ("iris.common.metadata._LENIENT" , return_value = False ):
611-             self .assertEqual (
612-                 lexpected , lmetadata .difference (rmetadata )._asdict ()
531+         if  fieldname  in  ("units" , "cell_methods" ):
532+             # These ones are always "strict" 
533+             strict_result  =  True 
534+         elif  fieldname  in  ("standard_name" , "long_name" , "var_name" ):
535+             strict_result  =  not  is_lenient 
536+         else :
537+             # Ensure we are handling all the different field cases 
538+             raise  ValueError (
539+                 f"{ self .__name__ } { fieldname }  
613540            )
614-             self .assertEqual (
615-                 rexpected , rmetadata .difference (lmetadata )._asdict ()
541+ 
542+         if  strict_result :
543+             diffentry  =  tuple (
544+                 [getattr (mm , fieldname ) for  mm  in  (lmetadata , rmetadata )]
616545            )
546+             lexpected  =  self .none ._asdict ()
547+             lexpected [fieldname ] =  diffentry 
548+             rexpected  =  lexpected .copy ()
549+             rexpected [fieldname ] =  diffentry [::- 1 ]
550+             # NOTE: in these cases, the difference metadata will fail an == operation, 
551+             # because of the 'None' entries. 
552+             # But we can use metadata._asdict() and test that. 
617553
618-     def  test_op_strict_different_cell_methods (self ):
619-         left  =  self .values .copy ()
620-         lmetadata  =  self .cls (** left )
621-         right  =  self .values .copy ()
622-         right ["cell_methods" ] =  self .dummy 
623-         rmetadata  =  self .cls (** right )
624-         lexpected  =  deepcopy (self .none )._asdict ()
625-         lexpected ["cell_methods" ] =  (
626-             left ["cell_methods" ],
627-             right ["cell_methods" ],
628-         )
629-         rexpected  =  deepcopy (self .none )._asdict ()
630-         rexpected ["cell_methods" ] =  lexpected ["cell_methods" ][::- 1 ]
554+         with  mock .patch (
555+             "iris.common.metadata._LENIENT" , return_value = is_lenient 
556+         ):
557+             if  strict_result :
558+                 assert  lmetadata .difference (rmetadata )._asdict () ==  lexpected 
559+                 assert  rmetadata .difference (lmetadata )._asdict () ==  rexpected 
560+             else :
561+                 # Expect NO differences 
562+                 assert  lmetadata .difference (rmetadata ) is  None 
563+                 assert  rmetadata .difference (lmetadata ) is  None 
631564
632-         with  mock .patch ("iris.common.metadata._LENIENT" , return_value = False ):
633-             self .assertEqual (
634-                 lexpected , lmetadata .difference (rmetadata )._asdict ()
635-             )
636-             self .assertEqual (
637-                 rexpected , rmetadata .difference (lmetadata )._asdict ()
638-             )
565+     def  test_op_different__attribute_extra (self , op_leniency ):
566+         is_lenient  =  op_leniency  ==  "lenient" 
567+         self .lvalues ["attributes" ] =  {"_a_common_" : self .dummy }
568+         lmetadata  =  self .cls (** self .lvalues )
569+         rvalues  =  deepcopy (self .lvalues )
570+         rvalues ["attributes" ]["_b_extra_" ] =  mock .sentinel .extra 
571+         rmetadata  =  self .cls (** rvalues )
572+ 
573+         if  not  is_lenient :
574+             # In this case, attributes returns a "difference dictionary" 
575+             diffentry  =  tuple ([{}, {"_b_extra_" : mock .sentinel .extra }])
576+             lexpected  =  self .none ._asdict ()
577+             lexpected ["attributes" ] =  diffentry 
578+             rexpected  =  lexpected .copy ()
579+             rexpected ["attributes" ] =  diffentry [::- 1 ]
639580
640-     def  test_op_strict_different_none (self ):
641-         left  =  self .values .copy ()
642-         lmetadata  =  self .cls (** left )
643-         right  =  self .values .copy ()
644-         right ["long_name" ] =  None 
645-         rmetadata  =  self .cls (** right )
646-         lexpected  =  deepcopy (self .none )._asdict ()
647-         lexpected ["long_name" ] =  (left ["long_name" ], right ["long_name" ])
648-         rexpected  =  deepcopy (self .none )._asdict ()
649-         rexpected ["long_name" ] =  lexpected ["long_name" ][::- 1 ]
650- 
651-         with  mock .patch ("iris.common.metadata._LENIENT" , return_value = False ):
652-             self .assertEqual (
653-                 lexpected , lmetadata .difference (rmetadata )._asdict ()
654-             )
655-             self .assertEqual (
656-                 rexpected , rmetadata .difference (lmetadata )._asdict ()
657-             )
581+         with  mock .patch (
582+             "iris.common.metadata._LENIENT" , return_value = is_lenient 
583+         ):
584+             if  is_lenient :
585+                 # It recognises no difference 
586+                 assert  lmetadata .difference (rmetadata ) is  None 
587+                 assert  rmetadata .difference (lmetadata ) is  None 
588+             else :
589+                 # As calculated above 
590+                 assert  lmetadata .difference (rmetadata )._asdict () ==  lexpected 
591+                 assert  rmetadata .difference (lmetadata )._asdict () ==  rexpected 
592+ 
593+     def  test_op_different__attribute_value (self , op_leniency ):
594+         is_lenient  =  op_leniency  ==  "lenient" 
595+         self .lvalues ["attributes" ] =  {
596+             "_a_common_" : self .dummy ,
597+             "_b_extra_" : mock .sentinel .value1 ,
598+         }
599+         lmetadata  =  self .cls (** self .lvalues )
600+         self .rvalues ["attributes" ] =  {
601+             "_a_common_" : self .dummy ,
602+             "_b_extra_" : mock .sentinel .value2 ,
603+         }
604+         rmetadata  =  self .cls (** self .rvalues )
658605
659-     def  test_op_strict_different_measure_none (self ):
660-         left  =  self .values .copy ()
661-         lmetadata  =  self .cls (** left )
662-         right  =  self .values .copy ()
663-         right ["cell_methods" ] =  None 
664-         rmetadata  =  self .cls (** right )
665-         lexpected  =  deepcopy (self .none )._asdict ()
666-         lexpected ["cell_methods" ] =  (
667-             left ["cell_methods" ],
668-             right ["cell_methods" ],
606+         # In this case, attributes returns a "difference dictionary" 
607+         diffentry  =  tuple (
608+             [
609+                 {"_b_extra_" : mock .sentinel .value1 },
610+                 {"_b_extra_" : mock .sentinel .value2 },
611+             ]
669612        )
670-         rexpected  =  deepcopy (self .none )._asdict ()
671-         rexpected ["cell_methods" ] =  lexpected ["cell_methods" ][::- 1 ]
613+         lexpected  =  self .none ._asdict ()
614+         lexpected ["attributes" ] =  diffentry 
615+         rexpected  =  lexpected .copy ()
616+         rexpected ["attributes" ] =  diffentry [::- 1 ]
672617
673-         with  mock .patch ("iris.common.metadata._LENIENT" , return_value = False ):
674-             self .assertEqual (
675-                 lexpected , lmetadata .difference (rmetadata )._asdict ()
676-             )
677-             self .assertEqual (
678-                 rexpected , rmetadata .difference (lmetadata )._asdict ()
679-             )
618+         with  mock .patch (
619+             "iris.common.metadata._LENIENT" , return_value = is_lenient 
620+         ):
621+             # As calculated above -- same for both strict + lenient 
622+             assert  lmetadata .difference (rmetadata )._asdict () ==  lexpected 
623+             assert  rmetadata .difference (lmetadata )._asdict () ==  rexpected 
680624
681625
682626class  Test_equal (tests .IrisTest ):
0 commit comments