Source code for rever.dag

"""Tools for dealing with activity DAGs."""


[docs]def find_path(dag, ends, done=frozenset(), path=None, already_done=None): """Returns a list that includes all end points for a given DAG. Parameters ---------- dag : dict of names to activities A DAG of all possible activities ends : set of str End points to compute. done : set of str, optional The nodes that have already been computed path : list of str, optional This is the return value of which activities to execute in which order. already_done : list of str The return value of the activities that have already been computed that would otherwise need to be computed. Returns ------- path : list of str The path through the DAG. already_done : list of str Activities that have already been computed that would otherwise need to be computed. """ if path is None: path = [] if not isinstance(done, frozenset): done = frozenset(done) if already_done is None: already_done = [] pth = set(path) sofar = pth | done todo = ends - sofar would_do = (ends - pth) & done already_done.extend([x for x in sorted(would_do) if x not in already_done]) if len(todo) == 0: return path, already_done for end in sorted(todo): try: deps = set(dag[end].deps) except KeyError: # we need to do it this way to support defaultdict raise KeyError('{0!r} not found in DAG!'.format(end)) need = deps - sofar already_done.extend([x for x in sorted(deps & done) if x not in already_done]) if len(need) > 0: find_path(dag, need, done=done, path=path, already_done=already_done) sofar.update(path) if end not in sofar: path.append(end) return path, already_done