@@ -236,13 +236,7 @@ def test_merge_attrs_drop_conflicts(self):
236
236
assert_identical (actual , expected )
237
237
238
238
def test_merge_attrs_drop_conflicts_non_bool_eq (self ):
239
- """Test drop_conflicts behavior when __eq__ returns non-bool values.
240
-
241
- When comparing attribute values, the _equivalent_drop_conflicts() function
242
- uses == which can return non-bool values. The new behavior treats ambiguous
243
- or falsy equality results as non-equivalent, dropping the attribute rather
244
- than raising an error.
245
- """
239
+ """Test drop_conflicts behavior when __eq__ returns non-bool values."""
246
240
import warnings
247
241
248
242
import numpy as np
@@ -295,14 +289,14 @@ def __repr__(self):
295
289
with warnings .catch_warnings ():
296
290
warnings .filterwarnings ("ignore" , category = DeprecationWarning )
297
291
298
- # With truthiness: objects returning [True] are kept (truthy )
292
+ # Objects returning arrays are dropped (non-boolean return )
299
293
actual = xr .merge ([ds4 , ds5 ], combine_attrs = "drop_conflicts" )
300
- assert "custom" in actual .attrs # Kept - [True] is truthy
294
+ assert "custom" not in actual .attrs # Dropped - returns array, not bool
301
295
assert actual .attrs ["x" ] == 1
302
296
303
- # Objects with different values: equivalent returns False ( bool), dropped
297
+ # Different values also dropped ( returns array, not bool)
304
298
actual = xr .merge ([ds4 , ds6 ], combine_attrs = "drop_conflicts" )
305
- assert "custom" not in actual .attrs # Dropped - different values
299
+ assert "custom" not in actual .attrs # Dropped - returns non-boolean
306
300
assert actual .attrs ["x" ] == 1
307
301
assert actual .attrs ["y" ] == 2
308
302
@@ -426,10 +420,9 @@ def test_merge_attrs_drop_conflicts_pathological_cases(self):
426
420
assert "dataset_attr" not in actual .attrs # Dropped due to TypeError
427
421
assert actual .attrs ["scalar" ] == 42
428
422
429
- # With truthiness: identical datasets are kept
430
- # The comparison returns a truthy Dataset, so they're treated as equal
423
+ # Identical datasets are also dropped (comparison returns Dataset, not bool)
431
424
actual = xr .merge ([ds4 , ds6 ], combine_attrs = "drop_conflicts" )
432
- assert "dataset_attr" in actual .attrs # Kept with truthiness approach
425
+ assert "dataset_attr" not in actual .attrs # Dropped - returns Dataset, not bool
433
426
assert actual .attrs ["other" ] == 99
434
427
435
428
# Test 3: Pandas Series (raises ValueError due to ambiguous truth value)
@@ -457,22 +450,16 @@ def test_merge_attrs_drop_conflicts_pathological_cases(self):
457
450
assert "series" not in actual .attrs # Dropped due to ValueError
458
451
assert actual .attrs ["value" ] == "a"
459
452
460
- def test_merge_attrs_drop_conflicts_truthiness_edge_cases (self ):
461
- """Test edge cases demonstrating the truthiness tradeoff.
462
-
463
- We deliberately use truthiness for consistency with Python's `if a == b:`
464
- behavior. This test documents the implications of this design choice
465
- with objects that have non-standard __eq__ methods.
466
- """
453
+ def test_merge_attrs_drop_conflicts_non_boolean_eq_returns (self ):
454
+ """Test objects with non-boolean __eq__ returns are dropped."""
467
455
468
- # Case 1: Objects whose __eq__ returns truthy non-booleans
469
- # These are kept because we respect truthiness
456
+ # Case 1: Objects whose __eq__ returns non-boolean strings
470
457
class ReturnsString :
471
458
def __init__ (self , value ):
472
459
self .value = value
473
460
474
461
def __eq__ (self , other ):
475
- # Always returns a string (truthy if non-empty )
462
+ # Always returns a string (non-boolean )
476
463
return "comparison result"
477
464
478
465
obj1 = ReturnsString ("A" )
@@ -483,18 +470,16 @@ def __eq__(self, other):
483
470
484
471
actual = xr .merge ([ds1 , ds2 ], combine_attrs = "drop_conflicts" )
485
472
486
- # Truthiness behavior: keeps attribute because "comparison result" is truthy
487
- # This is the expected behavior when respecting truthiness
488
- assert "obj" in actual .attrs
473
+ # Strict behavior: drops attribute because __eq__ returns non-boolean
474
+ assert "obj" not in actual .attrs
489
475
490
- # Case 2: Objects whose __eq__ returns falsy non-booleans
491
- # These are dropped because we respect truthiness
476
+ # Case 2: Objects whose __eq__ returns numbers
492
477
class ReturnsZero :
493
478
def __init__ (self , value ):
494
479
self .value = value
495
480
496
481
def __eq__ (self , other ):
497
- # Always returns 0 (falsy) even if values match
482
+ # Always returns 0 (non-boolean)
498
483
return 0
499
484
500
485
obj3 = ReturnsZero ("same" )
@@ -505,13 +490,9 @@ def __eq__(self, other):
505
490
506
491
actual = xr .merge ([ds3 , ds4 ], combine_attrs = "drop_conflicts" )
507
492
508
- # Truthiness behavior: drops attribute because 0 is falsy
509
- # This is the expected behavior when respecting truthiness
493
+ # Strict behavior: drops attribute because __eq__ returns non-boolean
510
494
assert "zero" not in actual .attrs
511
495
512
- # Note: These edge cases demonstrate the tradeoff of using truthiness.
513
- # Well-behaved __eq__ methods return booleans and work correctly.
514
- # We accept these edge cases for consistency with Python's standard behavior.
515
496
516
497
def test_merge_attrs_no_conflicts_compat_minimal (self ):
517
498
"""make sure compat="minimal" does not silence errors"""
0 commit comments