def yield_subgraph_nodes(node, visited_nodes=None):
    """Yield all nodes in subgraph.

    Works by recursively yielding nodes connected with
    the given one.

    Parameters
    ==========
    node (graphman.callablenode.CallableNode instance)
        a node from the subgraph; start from it, we yield
        all nodes in the subgraph.
    visited_nodes (None or set)
        set used to keep track of nodes already visited,
        so we avoid revisiting them. If it is None, a new
        set is created.
    """
    ### create a "visited nodes" set if it doesn't exist
    ### already
    if visited_nodes is None:
        visited_nodes = set()

    ### since we are visiting the given node, mark it
    ### as visited by adding it to the corresponding set
    visited_nodes.add(node)

    ### let's start the visit by yielding the node
    yield node

    ### now let's visit each upstream node recursively,
    ### that is, the ones we didn't visit yet

    for input_socket in node.input_sockets:

        ## try retrieving the value of the socket's
        ## 'parent' attribute, which, if exists,
        ## should contain a reference to an output
        ## socket which is the parent of the socket
        ## (the output socket is from another node)
        try:
            parent_output_socket = input_socket.parent

        ## if such attribute doesn't exits, just pass
        except AttributeError:
            pass

        ## otherwise, reference the node of such
        ## parent socket and visit it if not visited
        ## already, by passing it to this same
        ## function and yielding from it
        ##
        ## you must also pass along the set of visited
        ## nodes, so that the function knows whether
        ## a node has already been visited or not

        else:

            parent_node = parent_output_socket.node

            if parent_node not in visited_nodes:

                yield from yield_subgraph_nodes(parent_node, visited_nodes)

    ### now let's visit each downstream node recursively,
    ### that is, the ones we didn't visit yet
    ###
    ### note that some nodes also have a map where they store references
    ### to their output sockets; however, we don't worry about output
    ### sockets from such map (if it exists) here, because even the nodes
    ### which have such map still store references to their output sockets
    ### in the attribute used here; the difference is that nodes that have
    ### such map, when in collapsed signature mode, only reference the
    ### connected output sockets in this attribute (if any); this is fine,
    ### because we are only interested in the connected output sockets
    ### anyway, since we are traversing the graph

    for output_socket in node.output_sockets:

        ## try retrieving the value of the socket's
        ## 'children' attribute, which, if exists, should
        ## contain a reference to a list which contains
        ## references to input sockets considered
        ## children of this socket (the input sockets are
        ## from other nodes)
        try:
            children = output_socket.children

        ## if such attribute doesn't exits, just pass
        except AttributeError:
            pass

        ## otherwise, iterate over each input socket
        ## reference, referencing its node and visiting
        ## such node, if not visited already, by passing
        ## it to this same function and yielding from it
        ##
        ## you must also pass along the set of visited
        ## nodes, so that the function knows whether a
        ## node has already been visited or not

        else:

            for child_input_socket in children:

                child_node = child_input_socket.node

                if child_node not in visited_nodes:

                    yield from yield_subgraph_nodes(
                        child_node,
                        visited_nodes,
                    )
Yield all nodes in subgraph.

    Works by recursively yielding nodes connected with
    the given one.

    Parameters
    ==========
    node (graphman.callablenode.CallableNode instance)
        a node from the subgraph; start from it, we yield
        all nodes in the subgraph.
    visited_nodes (None or set)
        set used to keep track of nodes already visited,
        so we avoid revisiting them. If it is None, a new
        set is created.
    
nodezator/graphman/utils.py