Source code for giant.utilities.mixin_classes.attribute_equality_comparison

"""
This module provides a mixin whch adds a default equality comparison where each attribute is checked for equality.
"""

import numpy as np

from typing import Self, Any


[docs] class AttributeEqualityComparison: """ A base class that implements equality comparison based on attributes. This class provides methods to compare two objects of the same class based on their attributes. It handles comparison of numeric array-like attributes using numpy's allclose functionality. Usage: Inherit from this class to add attribute-based equality comparison to your custom classes. For example: .. code-block:: class MyClass(AttributeEqualityComparison): def __init__(self, x, y): self.x = x self.y = y obj1 = MyClass(1, [2, 3]) obj2 = MyClass(1, [2, 3]) obj3 = MyClass(1, [2, 4]) print(obj1 == obj2) # True print(obj1 == obj3) # False """ def __eq__(self, other: Any) -> bool: """ Compare this object with another for equality by checking equality of all attributes. :param other: The object to compare with :return: True if the objects are equal, False otherwise """ if not isinstance(other, self.__class__): return False if not set(self.__dict__.keys()) == set(other.__dict__.keys()): return False comp_dict = self.comparison_dictionary(other) if all(comp_dict.values()): return True else: print(f"Not equal in some attributes: {comp_dict}") return False @staticmethod def _value_comparison(val1: Any, val2: Any) -> bool: """ Compare two values, handling array-like objects. This can be overriden if need be. :param val1: First value to compare :param val2: Second value to compare :return: True if values are equal, False otherwise """ if isinstance(val1, (np.ndarray, list, tuple)) and isinstance(val2, (np.ndarray, list, tuple)): try: return np.allclose(val1, val2) except TypeError: # Fall back to regular equality for non-numeric arrays return bool(np.all(val1 == val2)) return val1 == val2
[docs] def comparison_dictionary(self, other: Self) -> dict[str, bool]: """ Compares each attribute of self to other and stores the result in a dict mapping the attribute to the comparison result. Each attribute is compared with a call to the internal :meth:`._value_comparison` which by default uses numpy's allclose functionality for arraylike objects and standard equality checks for all others. Therefore, if more detailed handling is needed, this :meth:`._value_comparison` method can be overridden while maintaining the functionality in this method and the class's equality comparison check. This assumes that other and self are the same type and have the same attributes. :param other: The other instance to compare with :return: A dictionary mapping attribute names to comparison results """ return { key: self._value_comparison(getattr(self, key), getattr(other, key)) for key in self.__dict__.keys() }