Source code for mixins.attrequals

import json
from typing import Sequence, Any, Tuple


[docs]class EqOnAttrsMixin: """ Allows class equality to be compared on the equality of the attribute names listed in equal_attrs. """ equal_attrs = None def __eq__(self, other): if self.equal_attrs is None: return super().__eq__(other) for equal_attr in self.equal_attrs: if not hasattr(other, equal_attr): # other object doesn't have this property, must not be equal return False if getattr(self, equal_attr) != getattr(other, equal_attr): return False # passed all checks, must be equal return True
[docs]class EqOnAttrsWithConversionMixin(EqOnAttrsMixin): """ Allows class equality to be compared on the equality of the attribute names listed in equal_attrs, converting all attributes to convert_type before comparing. """ convert_type = str def __eq__(self, other): if self.equal_attrs is None: return self == other for equal_attr in self.equal_attrs: if not hasattr(other, equal_attr): # other object doesn't have this property, must not be equal return False if self.convert_type(getattr(self, equal_attr)) != self.convert_type(getattr(other, equal_attr)): return False # passed all checks, must be equal return True
[docs]class EqHashMixin: """ Sets __hash__ based on attributes named in equal_attrs only. """ equal_attrs = None _recursive_hash_convert = False def __hash__(self): if self.equal_attrs is None: return super().__hash__() contents = [getattr(self, attr) for attr in self.equal_attrs] if self._recursive_hash_convert: tup_contents = _convert_nested_builtins_to_hashable(contents) else: tup_contents = tuple(contents) return hash(tup_contents)
def _convert_nested_builtins_to_hashable(seq: Sequence) -> Tuple[Any, ...]: items = [] new_item: Any for item in seq: if isinstance(item, (list, tuple)): new_item = _convert_nested_builtins_to_hashable(item) elif isinstance(item, dict): new_item = json.dumps(item) else: new_item = item items.append(new_item) items_tup = tuple(items) return items_tup