def nested_equal(a, b):
if a is b:<EOL><INDENT>return True<EOL><DEDENT>if a is None or b is None:<EOL><INDENT>return False<EOL><DEDENT>a_sparse = spsp.isspmatrix(a)<EOL>b_sparse = spsp.isspmatrix(b)<EOL>if a_sparse != b_sparse:<EOL><INDENT>return False<EOL><DEDENT>if a_sparse:<EOL><INDENT>if a.nnz == <NUM_LIT:0>:<EOL><INDENT>return b.nnz == <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>return not np.any((a != b).data)<EOL><DEDENT><DEDENT>a_series = isinstance(a, pd.Series)<EOL>b_series = isinstance(b, pd.Series)<EOL>if a_series != b_series:<EOL><INDENT>return False<EOL><DEDENT>if a_series:<EOL><INDENT>try:<EOL><INDENT>eq = (a == b).all()<EOL>return eq<EOL><DEDENT>except (TypeError, ValueError):<EOL><INDENT>if not len(a) == len(b):<EOL><INDENT>return False<EOL><DEDENT>for idx, itema in enumerate(a):<EOL><INDENT>itemb = b[idx]<EOL>if not nested_equal(itema, itemb):<EOL><INDENT>return False<EOL><DEDENT><DEDENT>return True<EOL><DEDENT><DEDENT>a_frame = isinstance(a, pd.DataFrame)<EOL>b_frame = isinstance(b, pd.DataFrame)<EOL>if a_frame != b_frame:<EOL><INDENT>return False<EOL><DEDENT>if a_frame:<EOL><INDENT>try:<EOL><INDENT>if a.empty and b.empty:<EOL><INDENT>return True<EOL><DEDENT>new_frame = a == b<EOL>new_frame = new_frame | (pd.isnull(a) & pd.isnull(b))<EOL>if isinstance(new_frame, pd.DataFrame):<EOL><INDENT>return np.all(new_frame.as_matrix())<EOL><DEDENT><DEDENT>except (ValueError, TypeError):<EOL><INDENT>for name in a:<EOL><INDENT>cola = a[name]<EOL>if not name in b:<EOL><INDENT>return False<EOL><DEDENT>colb = b[name]<EOL>if not len(cola) == len(colb):<EOL><INDENT>return False<EOL><DEDENT>for idx, itema in enumerate(cola):<EOL><INDENT>itemb = colb[idx]<EOL>if not nested_equal(itema, itemb):<EOL><INDENT>return False<EOL><DEDENT><DEDENT><DEDENT>return True<EOL><DEDENT><DEDENT>a_array = isinstance(a, np.ndarray)<EOL>b_array = isinstance(b, np.ndarray)<EOL>if a_array != b_array:<EOL><INDENT>return False<EOL><DEDENT>if a_array:<EOL><INDENT>if a.shape != b.shape:<EOL><INDENT>return False<EOL><DEDENT>return np.all(a == b)<EOL><DEDENT>a_list = isinstance(a, (Sequence, list, tuple))<EOL>b_list = isinstance(b, (Sequence, list, tuple))<EOL>if a_list != b_list:<EOL><INDENT>return False<EOL><DEDENT>if a_list:<EOL><INDENT>return all(nested_equal(x, y) for x, y in zip(a, b))<EOL><DEDENT>a_mapping = isinstance(a, (Mapping, dict))<EOL>b_mapping = isinstance(b, (Mapping, dict))<EOL>if a_mapping != b_mapping:<EOL><INDENT>return False<EOL><DEDENT>if a_mapping:<EOL><INDENT>keys_a = a.keys()<EOL>if set(keys_a) != set(b.keys()):<EOL><INDENT>return False<EOL><DEDENT>return all(nested_equal(a[k], b[k]) for k in keys_a)<EOL><DEDENT>equality = NotImplemented<EOL>try:<EOL><INDENT>equality = a.__eq__(b)<EOL><DEDENT>except (AttributeError, NotImplementedError, TypeError, ValueError):<EOL><INDENT>pass<EOL><DEDENT>if equality is NotImplemented:<EOL><INDENT>try:<EOL><INDENT>equality = b.__eq__(a)<EOL><DEDENT>except (AttributeError, NotImplementedError, TypeError, ValueError):<EOL><INDENT>pass<EOL><DEDENT><DEDENT>if equality is NotImplemented:<EOL><INDENT>try:<EOL><INDENT>cmp = a.__cmp__(b)<EOL>if cmp is not NotImplemented:<EOL><INDENT>equality = cmp == <NUM_LIT:0><EOL><DEDENT><DEDENT>except (AttributeError, NotImplementedError, TypeError, ValueError):<EOL><INDENT>pass<EOL><DEDENT><DEDENT>if equality is NotImplemented:<EOL><INDENT>try:<EOL><INDENT>cmp = b.__cmp__(a)<EOL>if cmp is not NotImplemented:<EOL><INDENT>equality = cmp == <NUM_LIT:0><EOL><DEDENT><DEDENT>except (AttributeError, NotImplementedError, TypeError, ValueError):<EOL><INDENT>pass<EOL><DEDENT><DEDENT>if equality is not NotImplemented:<EOL><INDENT>try:<EOL><INDENT>return bool(equality)<EOL><DEDENT>except (AttributeError, NotImplementedError, TypeError, ValueError):<EOL><INDENT>pass<EOL><DEDENT><DEDENT>attributes_a = get_all_attributes(a)<EOL>attributes_b = get_all_attributes(b)<EOL>if len(attributes_a) != len(attributes_b):<EOL><INDENT>return False<EOL><DEDENT>if len(attributes_a) > <NUM_LIT:0>:<EOL><INDENT>keys_a = list(attributes_a.keys())<EOL>if set(keys_a) != set(attributes_b.keys()):<EOL><INDENT>return False<EOL><DEDENT>return all(nested_equal(attributes_a[k], attributes_b[k]) for k in keys_a)<EOL><DEDENT>return False<EOL>
Compares two objects recursively by their elements.

    Also handles numpy arrays, pandas data and sparse matrices.

    First checks if the data falls into the above categories.
    If not, it is checked if a or b are some type of sequence or mapping and
    the contained elements are compared.
    If this is not the case, it is checked if a or b do provide a custom `__eq__` that
    evaluates to a single boolean value.
    If this is not the case, the attributes of a and b are compared.
    If this does not help either, normal `==` is used.

    Assumes hashable items are not mutable in a way that affects equality.
    Based on the suggestion from HERE_, thanks again Lauritz V. Thaulow :-)

    .. _HERE: http://stackoverflow.com/questions/18376935/best-practice-for-equality-in-python