def get_execution_plan(self) -> list[list["PoeTask"]]:
        """
        Derive an execution plan from the DAG in terms of stages consisting of tasks
        that could theoretically be parallelized.
        """
        # TODO: if we parallelize tasks then this should be modified to support lazy
        #       scheduling

        stages: list[list[TaskExecutionNode]] = [self.sources]
        visited = {source.identifier for source in self.sources}

        while True:
            next_stage = []
            for node in stages[-1]:
                for dep_node in node.direct_dependants:
                    if (
                        dep_node.identifier in visited
                        or not dep_node.direct_dependencies.issubset(visited)
                    ):
                        # We've already added this node OR some dependencies of dep_node
                        # have not been added so we can't add it yet
                        continue

                    next_stage.append(dep_node)
                    visited.add(dep_node.identifier)

            if not next_stage:
                break

            stages.append(next_stage)

        return [[node.task for node in stage] for stage in stages]

        Derive an execution plan from the DAG in terms of stages consisting of tasks
        that could theoretically be parallelized.
        
poethepoet/task/graph.py