@Steven D'Aprano All good ideas ☺ I'm in agreement that we should be building solutions which are generalizable.

Are there more concerns people would like to bring up when considering the problem of object equality?

On Sun, Jul 26, 2020 at 9:25 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Sun, Jul 26, 2020 at 11:12:39PM +0200, Alex Hall wrote:

> There's another reason people might find this useful - if the objects have
> differing attributes, the assertion can show exactly which ones, instead of
> just saying that the objects are not equal.

That's a good point.

I sat down to start an implementation, when a fundamental issue with
this came to mind. This proposed comparison is effectively something
close to:

    vars(actual) == vars(expected)

only recursively and with provision for objects with `__slots__` and/or
no `__dict__`. And that observation lead me to the insight that as tests
go, this is a risky, unreliable test.

A built-in example:

    actual = lambda: 1  # simulate some complex object
    expected = lambda: 2  # another complex object
    vars(actual) == vars(expected)  # returns True

So this is a comparison that needs to be used with care. It is easy for
the test to pass while the objects are nevertheless not what you expect.

Having said that, another perspective is that unittest already has a
smart test for comparing dicts, assertDictEqual, which is automatically
called by assertEqual.


So it may be sufficient to have a utility function that copies
an instance's slots and dict into a dict, and then compare dicts. Here's
a sketch:

    d1 = vars(actual).copy()
    d1.update({key: value for key in actual.__slots__})
    # Likewise for d2 from expected
    self.assertEqual(d1, d2)

Make that handle the corner cases where objects have no instance dict or
slots, and we're done.

Thinking aloud here.... I see this as a kind of copy operation, and
think this would be useful outside of testing. I've written code to copy
attributes from instances on multiple occasions. So how about a new
function in the `copy` module to do so:

    copy.getattrs(obj, deep=False)

that returns a dict. Then the desired comparison could be a thin

    def assertEqualAttrs(self, actual, expected, msg=None):
        self.assertEqual(getattrs(actual), getattrs(expected))

I'm not keen on a specialist test function, but I'm warming to the idea
of exposing this functionality in a more general, and hence more useful,

Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/MLRFS6RO7WF2UAEOS4YMH2FXRQHJUGWU/
Code of Conduct: http://python.org/psf/codeofconduct/