Welcome, guest | Sign In | My Account | Store | Cart
import itertools
import collections

def nth(iterable, n, default=None):
    "Returns the nth item or a default value"
    return next(itertools.islice(iterable, n, None), default)

def find(item, source, depth=1, queue_limit=1000000, found_limit=1000000):
    "Tries to find a pathway to access item from source."
    assert depth > 0, 'Cannot find item in source!'
    candidates = collections.deque([(source, 'source', 1)])
    locations = {id(source)}
    while candidates:
        if len(candidates) > queue_limit or len(locations) > found_limit:
            break
        source, path, level = candidates.pop()
        # Search container.
        try:
            iterator = iter(source)
        except TypeError:
            pass
        else:
            for key, value in enumerate(iterator):
                if isinstance(source, dict):
                    key, value = value, source[value]
                addr = id(value)
                if addr not in locations:
                    try:
                        assert source[key] is value
                    except (AssertionError, KeyError, TypeError):
                        attr_path = 'nth({}, {})'.format(path, key)
                    else:
                        attr_path = '{}[{!r}]'.format(path, key)
                    if value is item:
                        return attr_path
                    if level < depth:
                        candidates.appendleft((value, attr_path, level + 1))
                        locations.add(addr)
        # Search attributes.
        for name in dir(source):
            try:
                attr = getattr(source, name)
            except AttributeError:
                pass
            else:
                addr = id(attr)
                if addr not in locations:
                    attr_path = '{}.{}'.format(path, name)
                    if attr is item:
                        return attr_path
                    if level < depth:
                        candidates.appendleft((attr, attr_path, level + 1))
                        locations.add(addr)

History