On Sun, Jul 26, 2020 at 12:31:17PM -0500, Henry Lin wrote:
Hi Steven,
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 instances;
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: self.assertTrue(functools.compare(actual, other))
- 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. -- Steven