On Sun, Jul 26, 2020 at 12:31:17PM -0500, Henry Lin wrote:
You're right, declaring `__eq__` for the class we want to compare would solve this issue. However, we have the tradeoff that
- All classes need to implement the `__eq__` method to compare two
One argument in favour of a standard solution would be to avoid duplicated implementations. Perhaps we should add something, not as a unittest method, but in functools:
def compare(a, b): if a is b: return True # Simplified version. return vars(a) == vars(b)
The actual implementation would be more complex, of course. Then classes could optionally implement equality:
def __eq__(self, other): if isinstance(other, type(self): return functools.compare(self, other) return NotImplemented
or if you prefer, you could call the function directly in your unit tests:
- Any class implementing the `__eq__` operator is no longer hashable
Easy enough to add back in:
def __hash__(self): return super().__hash__()
- Developers might not want to leak the `__eq__` function to other
developers; I wouldn't want to invade the implementation of my class just for testing.
That seems odd to me. You are *literally* comparing two instances for equality, just calling it something different from `==`. Why would you not be happy to expose it?
In terms of the "popularity" of this potential feature, from what I understand (and through my own development), there are testing libraries built with this feature. For example, testfixtures.compare https://testfixtures.readthedocs.io/en/latest/api.html#testfixtures.compare can compare two objects recursively, and I am using it in my development for this purpose.
That's a good example of what we should *not* do, and why trying to create a single standard solution for every imaginable scenario can only end up with an over-engineered, complex, complicated, confusing API:
testfixtures.compare( x, y, prefix=None, suffix=None, raises=True, recursive=True, strict=False, comparers=None, **kw)
Not shown in the function signature are additional keyword arguments:
actual, expected # alternative spelling for x, y x_label, y_label, ignore_eq
That is literally thirteen optional parameters, plus arbitrary keyword parameters, for something that just compares two objects.
But a simple comparison function, possibly in functools, that simply compares attributes, might be worthwhile.