def test_topological_queue_two_dependent_nodes(): graph = basic.DependencyGraph(initial_dependencies={ "A": set(), "B": {"A"} }) queue = basic.TopologicalQueue(graph) assert not queue.empty() assert len(queue) == 2 assert queue.ready_set() == {"A"} now_ready = queue.completed("A") # There was a bug that resulted in the LHS of the following actually # being equal to an empty set assert graph.dependency_dict["B"] == {"A"} assert len(queue) == 1 assert queue.ready_set() == {"B"} assert now_ready == {"B"} now_ready = queue.completed("B") assert len(queue) == 0 assert queue.ready_set() == set() assert queue.empty() assert now_ready == set() assert graph.dependency_dict["A"] == set() # There was a bug that resulted in the LHS of the following actually # being equal to an empty set assert graph.dependency_dict["B"] == {"A"}
async def async_compute_concurrent_simple(graph): logger.debug("enter, graph.name=%s", graph.name) task_graph = graph.decorate(ensure_coroutine) queue = basic.TopologicalQueue(task_graph) ready_tasks = create_tasks(queue.ready_set()) while len(ready_tasks): assert not queue.empty() # 'pending' could be replaced with 'ready_tasks' here # and the line after (ready_tasks -= completed) could be removed completed, pending = await asyncio.wait( ready_tasks, return_when=asyncio.FIRST_COMPLETED) raise_task_exceptions(completed) ready_tasks -= completed for completed_task in completed: now_ready = queue.completed(completed_task.get_coro()) logger.debug("now_ready=%s", now_ready) ready_tasks |= create_tasks(now_ready) logger.debug("ready_tasks=%s", now_ready) assert len(ready_tasks) == 0 assert queue.empty(), f"queue.dependency_dict: {queue.dependency_dict}" logger.debug("exit, graph.name=%s", graph.name)
def test_topological_queue_two_independent_nodes(): graph = basic.DependencyGraph(initial_dependencies={"A": {}, "B": {}}) queue = basic.TopologicalQueue(graph) assert not queue.empty() assert queue.ready_set() == {"A", "B"} now_ready = queue.completed("B") assert queue.ready_set() == {"A"} # Nothing depends on "A" so its completion does not activate any # nodes assert now_ready == set()
def test_topological_queue_diamond(): queue = basic.TopologicalQueue( basic.DependencyGraph(initial_dependencies={ "A": {}, "B": {"A"}, "C": {"A"}, "D": {"B", "C"} })) assert not queue.empty() assert len(queue) == 4 ready_set_a = queue.ready_set() assert ready_set_a == {"A"} now_ready_a = queue.completed("A") assert ready_set_a == {"A"} ready_set_bc = queue.ready_set() assert ready_set_bc == {"B", "C"} assert now_ready_a == {"B", "C"} assert len(queue) == 3 assert not queue.empty() now_ready_b = queue.completed("B") assert queue.ready_set() == {"C"} assert now_ready_b == set() assert len(queue) == 2 assert not queue.empty() # Make sure this didn't change under our feet assert now_ready_a == {"B", "C"} now_ready = queue.completed("C") assert queue.ready_set() == {"D"} assert now_ready == {"D"} assert len(queue) == 1 assert not queue.empty() with pytest.raises(KeyError): queue.completed("C") now_ready = queue.completed("D") assert queue.ready_set() == set() assert now_ready == set() assert len(queue) == 0 assert queue.empty()
async def async_compute_concurrent(graph): logger.debug("enter, graph.name=%s", graph.name) queue = basic.TopologicalQueue(graph) ready_set = queue.ready_set() logger.debug("ready_set: %s", ready_set) callables, running_tasks = prepare_ready_set(ready_set) while not queue.empty(): while len(callables): the_callable = callables.pop() the_callable() now_ready = queue.completed(the_callable) new_callables, new_tasks = prepare_ready_set(now_ready) callables |= new_callables running_tasks |= new_tasks while len(running_tasks) and len(callables) == 0: completed_tasks, running_tasks = await asyncio.wait( running_tasks, return_when=asyncio.FIRST_COMPLETED) raise_task_exceptions(completed_tasks) for completed_task in completed_tasks: completed_coro_function = completed_task.aio_coroutine_function now_ready = queue.completed(completed_coro_function) logger.debug("now_ready=%s", now_ready) new_callables, new_tasks = prepare_ready_set(now_ready) callables |= new_callables logger.debug("callables=%s", callables) running_tasks |= new_tasks logger.debug("running_tasks=%s", running_tasks) assert len(running_tasks) == 0 assert queue.empty() logger.debug("exit, graph.name=%s", graph.name)
def test_topological_queue_bug(): graph = basic.DependencyGraph() graph.add_node("A") graph.add_node("B") queue = basic.TopologicalQueue(graph) assert queue.ready_set() == {"A", "B"}
def test_topological_queue_cycle(): with pytest.raises(basic.CircularDependency) as e: queue = basic.TopologicalQueue( basic.DependencyGraph(initial_dependencies={"A": {"A"}})) assert str(e.value) == "Circular dependency detected in graph"
def test_topological_queue_singleton(): queue = basic.TopologicalQueue( basic.DependencyGraph(initial_dependencies={"A": {}})) assert not queue.empty() assert queue.ready_set() == {"A"}
def test_topological_queue_empty(): queue = basic.TopologicalQueue( basic.DependencyGraph(initial_dependencies={})) assert queue.empty()