Extending recursive_diff/recursive_eq

Without any changes, recursive_diff() and recursive_eq() can compare arbitrary objects using the == operator. Take for example this custom class:

>>> class Rectangle:
...    def __init__(self, w, h):
...        self.w = w
...        self.h = h
...
...    def __eq__(self, other):
...        return self.w == other.w and self.h == other.h
...
...    def __repr__(self):
...        return 'Rectangle(%f, %f)' % (self.w, self.h)

The above can be processed by recursive_diff, because it supports the == operator against objects of the same type, and when converted to string it conveys meaningful information:

>>> list(recursive_diff(Rectangle(1, 2), Rectangle(3, 4)))
['Rectangle(1.000000, 2.000000) != Rectangle(2.000000, 3.000000)']

However, it doesn’t support the more powerful features of recursive_diff, namely recursion and tolerance:

>>> list(recursive_diff(
...     Rectangle(1, 2), Rectangle(1.1, 2.2), abs_tol=.5))
['Rectangle(1.0000000, 2.0000000) != Rectangle(1.100000, 2.200000)']

This can be fixed by registering a custom cast() function:

>>> from recursive_diff import cast
>>> @cast.register(Rectangle)
... def _(obj, brief_dims):
...     return {'w': obj.w, 'h': obj.h}

After doing so, w and h will be compared with tolerance and, if they are collections, will be recursively descended into:

>>> list(recursive_diff(
...     Rectangle(1, 2), Rectangle(1.1, 2.7), abs_tol=.5))
['[h]: 2.0 != 2.7 (abs: 7.0e-01, rel: 3.5e-01)']