def walk(node, gen_subnodes, event = enter, reverse_path = False, tree=True):
    """Traverse a tree or a graph based at 'node' and generate a sequence
    of paths in the graph from the initial node to the visited node.
    The arguments are
    
        @ node : an arbitrary python object used as root node.
        @ gen_subnodes : a function defining the graph structure. It must
            have the interface gen_subnodes(node) --> iterable containing
            other nodes. This function will be called with the initial
            node and the descendent nodes that it generates through
            this function.
        @ event: an integral value specifying which paths will be generated
            during the depth-first walk. This is usually a value obtained
            by composing the walk events (see below) with bitwise operators.
            For example passing event = event(enter|leaf|bounce) will
            generate inner nodes the first time they are entered, leaf
            nodes and all the nodes every time they are revisited during
            the walk.
        @ reverse_path: a boolean indicating that the path should be read
            from right to left (defaults to False).
        @ tree: a boolean indicating that the walked graph is a tree,
            which means that applying gen_subnodes() will only generate
            new nodes (defaults to True). Passing True if the graph
            is not a tree will walk multiple subgraphs several times,
            or lead to an infinite walk and a memory error if the graph
            contains cycles. When a False value is given, this function
            stores all the previoulsy visited nodes during the walk.
            When a True value is given, only the nodes in the current
            path are stored.
    
    Typical use:
        
        for path in walk(node, func, event(enter|leaf)):
            # this choice of events results in a preorder traversal
            visited = path[-1]
            if path.event & leaf:
                print(visited, 'is a leaf node!')
                
    The generated 'path' is a read-only sequence of nodes with path[0] being
    the base node of the walk and path[-1] being the visited node. If
    reverse_path is set to True, the path will appear from right to left,
    with the visited node in position 0. During the whole walk, the function
    generates the same path object, each time in a different state.
    Internally, this path is implemented using a collections.deque object,
    which means that indexing an element in the middle of the path (but not
    near both ends) may require a time proportional to its length.
    
    The generated paths have an attribute path.event which value is an
    integer in the range [0,128[ representing a bitwise combination of
    the base events (which are also integers) explained below
    
        enter:  the currently visited node is an inner node of the tree
                generated before this node's subgraph is visited.
        within: the currently visited node is an inner node generated after
                its first subgraph has been visited but before the other
                subgraphs.
        exit:   the currently visited node is an inner node generated after
                all its subgraphs have been visited.
        leaf:   the currently visited node is a leaf node.
        inner:  the currently visited node is an inner node
        cycle:  the currently visited node is an internal node already on
                the path, which means that the graph has a cycle. The subgraph
                based on this node will not be walked.
        bounce: the currently visited node is either an internal node which
                subgraph has already been walked, or a leaf already met.
                Subgraphs are never walked a twice with the argument tree=False.
    The actual events generated are often a combination of these events, for
    exemple, one may have a value of event(leaf & ~bounce). This attribute
    path.event is best tested with bitwise operators. For example to test if
    the walk is on a leaf, use 'if path.event & leaf:'.
    
    The constant events are also attributes of the walk function, namely
    (walk.enter, walk.within, ...)
    """
    mask, selector = parse_event_arg(event)
    isub = selector.index('', 1)
    ileft = selector.index('', isub + 1)
    tcycle = mask & cycle
    tleaf = mask & leaf
    tibounce = mask & bounce & inner
    tfbounce = mask & bounce & leaf
    tffirst = mask & ~bounce & leaf
    todo = deque((iter((node,)),))
    path = deque()
    const_path = ConstSequence(path)
    if reverse_path:
        ppush, ppop, ivisited = path.appendleft, path.popleft, 0
    else:
        ppush, ppop, ivisited = path.append, path.pop, -1
    less, more = todo.pop, todo.extend
    hist = _MockDict() if tree else dict()
    try:
        while True:
            sequence = todo[-1]
            if sequence.__class__ is _Int:
                less()
                if sequence is _pop:
                    # this node's subtree is exhausted, prepare for bounce
                    hist[path[ivisited]] = tibounce
                    ppop()
                else:
                    const_path.event = sequence
                    yield const_path
            else:
                try:
                    node = next(sequence)
                except __HOLE__:
                    less()
                else:
                    ppush(node)
                    # if node in history, generate a bounce event
                    # (actually one of (leaf & bounce, inner & bounce, cycle))
                    if node in hist:
                        const_path.event = hist[node]
                        if const_path.event:
                            yield const_path
                        ppop()
                    else:
                        sub = iter(gen_subnodes(node))
                        try:
                            snode = next(sub)
                        except StopIteration:
                            hist[node] = tfbounce
                            if tleaf:
                                const_path.event = tffirst
                                yield const_path
                            ppop()
                        else:
                            # ajouter node 
                            hist[node] = tcycle
                            selector[ileft] = iter((snode,))
                            selector[isub] = sub
                            more(selector)
    except IndexError:
        if todo: # this allows gen_subnodes() to raise IndexError
            raise
dataset/ETHPy150Open tow/sunburnt/sunburnt/walktree.py/walk