Search code examples
pythonassertpython-unittest

assertEqual fails for objects that are byte-for-byte identical?


I have a unittest that compares two 1-element dictionaries like this one:

{SomeClass(): SomeOtherClass()}

The dicts look completely similar to the naked eye, and the types of both the keys and the values are the same as well. Nonetheless, the test fails.

I have of course tried all kinds of tricks to produce some diff output between them, but none ever showed any difference between these objects or any of it's nested attributes. The objects are quite large, so the unittest diff is of no help.

As a last desperate attempt I tried pickling these dicts and then making a Unix diff, but that too showed no difference whatsoever. Call me naive, but to me that would mean that these objects are byte for byte identical and the test should pass. What is going on here?


Solution

  • Identical pickles don't imply byte-for-byte identical objects, and byte-for-byte identical objects aren't necessarily equal.

    You might think it's easy to make byte-for-byte identical objects automatically equal, but that runs into a lot of problems. For example, consider the following:

    class Foo(object):
        __slots__ = ['x']
    
    x = Foo()
    y = Foo()
    x.x = y.x = x
    

    Aside from GC metadata, x and y are probably byte-for-byte identical. Should x and y be automatically equal? x is the only one whose x attribute points to itself; that seems like a big enough difference that they shouldn't be automatically equal.

    This is only one of the problems with trying to do what you want by default. It turns out the least confusing default is to have == work by identity; unless an __eq__ override comes into play, objects will only be equal to themselves.