Beispiel #1
0
def detect_cycles(iterable):
    result = []
    i = iter(iterable)
    try:
        # Point to the tortoise
        tortoise = 0
        result.append(i.next())
        # Point to the hare
        hare = 1
        result.append(i.next())
        # Start looking for cycles
        power = 1
        while True:
            # Use Richard P. Brent's algorithm to find an element that
            # repeats.
            while result[tortoise] != result[hare]:
                if power == (hare - tortoise):
                    tortoise = hare
                    power *= 2
                hare += 1
                result.append(i.next())
            # Brent assumes the sequence is stateless, but since we're
            # dealing with a DFS tree, we need to make sure that all
            # the items between `tortoise` and `hare` are identical.
            cycle = True
            for j in xrange(0, hare - tortoise + 1):
                tortoise += 1
                hare += 1
                result.append(i.next())
                if result[tortoise] != result[hare]:
                    # False alarm: no cycle here.
                    cycle = False
                    power = 1
                    tortoise = hare
                    hare += 1
                    result.append(i.next())
                    break
            # Both loops are done, so we must have a cycle
            if cycle:
                raise exceptions.CircularDependency(result[tortoise:hare + 1])
    except StopIteration:
        # Return when `iterable` is exhausted. Obviously, there are no cycles.
        return result
Beispiel #2
0
def _dfs(start, get_children, path):
    if (start, get_children) in dependency_cache:
        return dependency_cache[(start, get_children)]

    results = []
    if start in path:
        raise exceptions.CircularDependency(path[path.index(start):] + [start])
    path.append(start)
    results.append(start)
    children = sorted(get_children(start), key=lambda x: str(x))

    # We need to apply all the migrations this one depends on
    for n in children:
        results = _dfs(n, get_children, path) + results

    path.pop()

    results = list(SortedSet(results))
    dependency_cache[(start, get_children)] = results
    return results