Fixes an error where reload causes super(X, self) to raise an exception

    The problem is that reloading causes X to point to the wrong version of the
    class.  This function fixes the problem by searching and returning the
    correct version of the class. See example for proper usage.

    USE `ut.super2` INSTEAD

    Args:
        this_class (class): class passed into super
        self (instance): instance passed into super

    DisableExample:
        >>> # DISABLE_DOCTEST
        >>> import utool as ut
        >>> class Parent(object):
        >>>     def __init__(self):
        >>>         self.parent_attr = 'bar'
        >>> #
        >>> class Foo(Parent):
        >>>     def __init__(self):
        >>>         # Dont do this, it will error if you reload
        >>>         # super(Foo, self).__init__()
        >>>         # Do this instead
        >>>         _Foo = ut.super2(Foo, self)
        >>>         super(_Foo, self).__init__()
        >>> self = Foo()
        >>> assert self.parent_attr == 'bar'

def fix_super_reload(this_class, self):
    """
    Fixes an error where reload causes super(X, self) to raise an exception

    The problem is that reloading causes X to point to the wrong version of the
    class.  This function fixes the problem by searching and returning the
    correct version of the class. See example for proper usage.

    USE `ut.super2` INSTEAD

    Args:
        this_class (class): class passed into super
        self (instance): instance passed into super

    DisableExample:
        >>> # DISABLE_DOCTEST
        >>> import utool as ut
        >>> class Parent(object):
        >>>     def __init__(self):
        >>>         self.parent_attr = 'bar'
        >>> #
        >>> class Foo(Parent):
        >>>     def __init__(self):
        >>>         # Dont do this, it will error if you reload
        >>>         # super(Foo, self).__init__()
        >>>         # Do this instead
        >>>         _Foo = ut.super2(Foo, self)
        >>>         super(_Foo, self).__init__()
        >>> self = Foo()
        >>> assert self.parent_attr == 'bar'
    """

    if isinstance(self, this_class):
        # Case where everything is ok
        this_class_now = this_class
    else:
        # Case where we need to search for the right class
        def find_parent_class(leaf_class, target_name):
            target_class = None
            from collections import deque
            queue = deque()
            queue.append(leaf_class)
            seen_ = set([])
            while len(queue) > 0:
                related_class = queue.pop()
                if related_class.__name__ != target_name:
                    for base in related_class.__bases__:
                        if base not in seen_:
                            queue.append(base)
                            seen_.add(base)
                else:
                    target_class = related_class
                    break
            return target_class
        # Find new version of class
        leaf_class = self.__class__
        target_name = this_class.__name__
        target_class = find_parent_class(leaf_class, target_name)

        this_class_now = target_class
        #print('id(this_class)     = %r' % (id(this_class),))
        #print('id(this_class_now) = %r' % (id(this_class_now),))
    assert isinstance(self, this_class_now), (
        'Failed to fix %r, %r, %r' % (self, this_class, this_class_now))
    return this_class_now