def test_usage_example(self): from depdag import DepDag # Create the DAG structure and get a reference to the vertices collection: vert = DepDag().vertices # Connect vertices with directed dependency relationships (i.e. the edges): vert.a.depends_on('b') vert.b.depends_on('d') vert.c.depends_on('d', 'e') assert not vert.dag.is_cyclic() # Explore who depends on whom, recursively; prints: # - vert a -> all supporters: ['b', 'd'] # - vert b -> all supporters: ['d'] # - vert d -> all supporters: [] # - vert c -> all supporters: ['d', 'e'] # - vert e -> all supporters: [] for v in vert.all(): print("- vert", v.name, "-> all supporters:", v.supporters(recurse=True)) # Set some payload and see which vertices are 'resolved', that is, # all supporters, recursively, also have payload and the vertex # itself has a payload vert.a.payload = "vert-a payload (can be anything)" vert.d.payload = "vert-d payload (can be anything)" assert not vert.a.is_resolved() assert vert.d.is_resolved() assert not vert.c.is_resolved() vert.c.payload = "vert-c payload (can be anything)" vert.e.payload = "vert-d payload (can be anything)" assert vert.c.is_resolved()
def test_usage_example(self): from depdag import DepDag # Create the DAG structure: dag = DepDag() # Connect vertices with directed dependency relationships (i.e. the edges): dag.a.depends_on('b') dag.b.depends_on('d') dag.c.depends_on('d', 'e') assert not dag.is_cyclic() # Explore who depends on whom, recursively; prints: # - vert a -> all supporters: ['b', 'd'] # - vert b -> all supporters: ['d'] # - vert d -> all supporters: [] # - vert c -> all supporters: ['d', 'e'] # - vert e -> all supporters: [] for v in dag.all_vertices(): print("- vert", v.name, "-> all supporters:", names_list(v.all_supporters())) # Set some payload and see which vertices are 'resolved', that is, # all supporters, recursively, also have payload and the vertex # itself has payload dag.a.payload = "vert-a payload (can be anything)" dag.d.payload = "vert-d payload (can be anything)" assert not dag.a.is_resolved() assert dag.d.is_resolved() assert not dag.c.is_resolved() dag.c.payload = "vert-c payload (can be anything)" dag.e.payload = "vert-d payload (can be anything)" assert dag.c.is_resolved()
def test_is_cyclic__positive_three_vertices(self): dag = DepDag() vert = dag.vertices vert.a.depends_on('b') vert.b.depends_on('c') vert.c.depends_on('a') self.assertTrue(dag.is_cyclic())
def create_large_dag(nodes=1000, fail_on_cycle=False): dag = DepDag(fail_on_cycle=fail_on_cycle) for idx in range(nodes // 3): name = f'node-{idx}' dag.new_vertex(name) dag[name].depends_on(name + '-one') dag[name].depends_on(name + '-two')
def test_is_cyclic__diamond_relationship(self): dag = DepDag() dag.a.depends_on('b') dag.b.depends_on('c', 'd') dag.c.depends_on('e') dag.d.depends_on('e') dag.e.depends_on('f') self.assertFalse(dag.is_cyclic())
def test_clone__case_diamond(self): dag = DepDag() dag.new_vertex('a', 'payload-a') dag.new_vertex('b', 'payload-b') dag.new_vertex('c', 'payload-c') dag.new_vertex('d', 'payload-d') dag.new_vertex('e', 'payload-e') dag.new_vertex('f', 'payload-f') dag.a.depends_on('b') dag.b.depends_on('c', 'd') dag.c.depends_on('e') dag.d.depends_on('e') dag.e.depends_on('f') new_dag = dag.clone() self.assertEqual([new_dag.b], list(new_dag.a.direct_supporters())) self.assertEqual([new_dag.c, new_dag.d], list(new_dag.b.direct_supporters())) self.assertEqual([new_dag.e], list(new_dag.c.direct_supporters())) self.assertEqual([new_dag.e], list(new_dag.d.direct_supporters())) self.assertEqual([new_dag.f], list(new_dag.e.direct_supporters())) self.assertEqual('payload-a', new_dag.a.payload) self.assertEqual('payload-b', new_dag.b.payload) self.assertEqual('payload-c', new_dag.c.payload) self.assertEqual('payload-d', new_dag.d.payload) self.assertEqual('payload-e', new_dag.e.payload) self.assertEqual('payload-f', new_dag.f.payload)
def test_case_1(self): dag = DepDag() dag.a.depends_on('b', 'c') dag.c.depends_on('e') dag.d.depends_on('e') dag.e.depends_on('b') for v in [dag.a, dag.b, dag.c, dag.d, dag.e]: self.assertFalse(v.has_payload()) self.assertFalse(v.is_resolved()) self.assertFalse(dag.is_cyclic()) dag.b.payload = 'some_payload' dag.d.payload = 'some_payload' self.assertFalse(dag.a.has_payload()) self.assertFalse(dag.a.is_resolved()) self.assertTrue(dag.b.has_payload()) self.assertTrue(dag.b.is_resolved()) self.assertFalse(dag.c.has_payload()) self.assertFalse(dag.c.is_resolved()) self.assertTrue(dag.d.has_payload()) self.assertFalse(dag.d.is_resolved()) self.assertFalse(dag.e.has_payload()) self.assertFalse(dag.e.is_resolved()) dag.a.payload = 'some_payload' dag.e.payload = 'some_payload' self.assertTrue(dag.a.has_payload()) self.assertFalse(dag.a.is_resolved()) self.assertTrue(dag.b.has_payload()) self.assertTrue(dag.b.is_resolved()) self.assertFalse(dag.c.has_payload()) self.assertFalse(dag.c.is_resolved()) self.assertTrue(dag.d.has_payload()) self.assertTrue(dag.d.is_resolved()) self.assertTrue(dag.e.has_payload()) self.assertTrue(dag.e.is_resolved()) dag.c.payload = 'some_payload' self.assertTrue(dag.a.has_payload()) self.assertTrue(dag.a.is_resolved()) self.assertTrue(dag.b.has_payload()) self.assertTrue(dag.b.is_resolved()) self.assertTrue(dag.c.has_payload()) self.assertTrue(dag.c.is_resolved()) self.assertTrue(dag.d.has_payload()) self.assertTrue(dag.d.is_resolved()) self.assertTrue(dag.e.has_payload()) self.assertTrue(dag.e.is_resolved())
def test_all_supporters(self): dag = DepDag() a = Vertex('a', dag) a.depends_on('b') b = dag['b'] b.depends_on('c') self.assertEqual(['b', 'c'], names_list(a.all_supporters()))
def test_depends_on__test_supporters(self): vertex = Vertex('vertex_0', DepDag()) vertex.depends_on('vertex_1', 'vertex_2') expected = ['vertex_1', 'vertex_2'] self.assertEqual(expected, names_list(vertex.direct_supporters())) vertex.depends_on('vertex_2', 'vertex_3') expected = ['vertex_1', 'vertex_2', 'vertex_3'] self.assertEqual(expected, names_list(vertex.direct_supporters()))
def test_vertex_name_is_tuple(self): # exercising any hashable to be used as a vertex name (PR #2) dag = DepDag() dag[('vertex_a',)].depends_on(('vertex_b',)) self.assertEqual( [('vertex_b',)], names_list(dag[('vertex_a',)].all_supporters()) ) self.assertEqual([], names_list(dag[('vertex_b',)].all_supporters()))
def test_is_resolved__simplest_case(self): dag = DepDag() a = Vertex('a', dag) a.depends_on('b') self.assertFalse(a.is_resolved()) b = dag['b'] self.assertFalse(b.is_resolved()) b.payload = 'payload for vert-b' self.assertFalse(a.is_resolved()) self.assertTrue(b.is_resolved()) a.payload = 'payload for vert-a' self.assertTrue(a.is_resolved()) self.assertTrue(b.is_resolved())
def test_has_payload__for_callable(self): vertex = Vertex('vertex_44', DepDag()) self.assertFalse(vertex.has_payload()) call_log = list() def has_payload_callback(): call_log.append('CALLED') return True vertex.payload = has_payload_callback self.assertTrue(vertex.has_payload()) self.assertEqual(['CALLED'], call_log)
def test_clone__case_simple(self): dag = DepDag() dag.new_vertex('a', 'payload-a') dag.new_vertex('b', 'payload-b') dag.new_vertex('c', 'payload-c') dag.a.depends_on('b') dag.b.depends_on('c') new_dag = dag.clone() self.assertEqual('payload-a', new_dag.a.payload) self.assertEqual('payload-b', new_dag.b.payload) self.assertEqual('payload-c', new_dag.c.payload) self.assertEqual([new_dag.b], list(new_dag.a.direct_supporters())) self.assertEqual([new_dag.c], list(new_dag.b.direct_supporters()))
def test_case_1(self): vert = DepDag().vertices vert.a.depends_on('b', 'c') vert.c.depends_on('e') vert.d.depends_on('e') vert.e.depends_on('b') for v in [vert.a, vert.b, vert.c, vert.d, vert.e]: self.assertFalse(v.provided) self.assertFalse(v.is_resolved()) vert.b.payload = 'some_payload' vert.d.payload = 'some_payload' self.assertFalse(vert.a.provided) self.assertFalse(vert.a.is_resolved()) self.assertTrue(vert.b.provided) self.assertTrue(vert.b.is_resolved()) self.assertFalse(vert.c.provided) self.assertFalse(vert.c.is_resolved()) self.assertTrue(vert.d.provided) self.assertFalse(vert.d.is_resolved()) self.assertFalse(vert.e.provided) self.assertFalse(vert.e.is_resolved()) vert.a.payload = 'some_payload' vert.e.payload = 'some_payload' self.assertTrue(vert.a.provided) self.assertFalse(vert.a.is_resolved()) self.assertTrue(vert.b.provided) self.assertTrue(vert.b.is_resolved()) self.assertFalse(vert.c.provided) self.assertFalse(vert.c.is_resolved()) self.assertTrue(vert.d.provided) self.assertTrue(vert.d.is_resolved()) self.assertTrue(vert.e.provided) self.assertTrue(vert.e.is_resolved()) vert.c.payload = 'some_payload' self.assertTrue(vert.a.provided) self.assertTrue(vert.a.is_resolved()) self.assertTrue(vert.b.provided) self.assertTrue(vert.b.is_resolved()) self.assertTrue(vert.c.provided) self.assertTrue(vert.c.is_resolved()) self.assertTrue(vert.d.provided) self.assertTrue(vert.d.is_resolved()) self.assertTrue(vert.e.provided) self.assertTrue(vert.e.is_resolved())
def test_clone__cyclic(self): dag = DepDag() dag.new_vertex('a', 'payload-a') dag.new_vertex('b', 'payload-b') dag.new_vertex('c', 'payload-c') dag.new_vertex('d', 'payload-d') dag.a.depends_on('b') dag.b.depends_on('c') dag.c.depends_on('d') dag.d.depends_on('a') self.assertTrue(dag.is_cyclic()) new_dag = dag.clone() self.assertEqual([new_dag.b], list(new_dag.a.direct_supporters())) self.assertEqual([new_dag.c], list(new_dag.b.direct_supporters())) self.assertEqual([new_dag.d], list(new_dag.c.direct_supporters())) self.assertEqual([new_dag.a], list(new_dag.d.direct_supporters())) self.assertEqual('payload-a', new_dag.a.payload) self.assertEqual('payload-b', new_dag.b.payload) self.assertEqual('payload-c', new_dag.c.payload) self.assertEqual('payload-d', new_dag.d.payload) self.assertTrue(new_dag.is_cyclic())
def test_creation(self): dag = DepDag()
def test__contains__(self): dag = DepDag() dag.one.depends_on('two') self.assertTrue('one' in dag) self.assertTrue('two' in dag)
def test_is_cyclic__positive__one_vertex(self): dag = DepDag() vert = dag.vertices vert.a.depends_on('a') self.assertTrue(dag.is_cyclic())
def test_is_cyclic__negative_three_vertices(self): dag = DepDag() vert = dag.vertices vert.a.depends_on('b') vert.b.depends_on('c') self.assertFalse(dag.is_cyclic())
def test_is_cyclic__negative__one_vertex(self): dag = DepDag() vert = dag.vertices vert.create('a') self.assertEqual(1, len(vert)) self.assertFalse(dag.is_cyclic())
def test_depends_on__test_supporters(self): vert = DepDag().vertices vert.a.depends_on('b') self.assertEqual(['b'], vert.a.supporters(recurse=False)) vert.a.depends_on('c', 'd') self.assertEqual(['b', 'c', 'd'], vert.a.supporters(recurse=False))
def test_creation(self): dag = DepDag() self.assertEqual(0, len(dag))
def test_ensure_not_cyclic__passes(self): dag = DepDag() dag.a.depends_on('b') dag.b.depends_on('c', 'd') dag.ensure_not_cyclic()
def test_ensure_not_cyclic__raises(self): dag = DepDag() dag.a.depends_on('b') dag.b.depends_on('a') with self.assertRaisesRegex(CycleDetected, 'graph is cyclic'): dag.ensure_not_cyclic()
def test__iter__(self): dag = DepDag() dag.aa.depends_on('bb') dag.aa.depends_on('cc') expected = [('aa', dag.aa), ('bb', dag.bb), ('cc', dag.cc)] self.assertEqual(expected, list(dag))
def test_case_2(self): vert = DepDag().vertices vert.a.depends_on('b') vert.b.depends_on('c') vert.c.depends_on('d') vert.d.depends_on('e', 'f') vert.g.depends_on('b') vert.h.depends_on('g') vert.i.depends_on('d') for v in [ vert.a, vert.b, vert.c, vert.d, vert.e, vert.f, vert.g, vert.h, vert.i ]: self.assertFalse(v.provided) self.assertFalse(v.is_resolved()) vert.d.payload = 'some_payload' vert.e.payload = 'some_payload' vert.g.payload = 'some_payload' self.assertFalse(vert.a.provided) self.assertFalse(vert.a.is_resolved()) self.assertFalse(vert.b.provided) self.assertFalse(vert.b.is_resolved()) self.assertFalse(vert.c.provided) self.assertFalse(vert.c.is_resolved()) self.assertTrue(vert.d.provided) self.assertFalse(vert.d.is_resolved()) self.assertTrue(vert.e.provided) self.assertTrue(vert.e.is_resolved()) self.assertFalse(vert.f.provided) self.assertFalse(vert.f.is_resolved()) self.assertTrue(vert.g.provided) self.assertFalse(vert.g.is_resolved()) self.assertFalse(vert.h.provided) self.assertFalse(vert.h.is_resolved()) self.assertFalse(vert.i.provided) self.assertFalse(vert.i.is_resolved()) vert.b.payload = 'some_payload' vert.c.payload = 'some_payload' vert.f.payload = 'some_payload' self.assertFalse(vert.a.provided) self.assertFalse(vert.a.is_resolved()) self.assertTrue(vert.b.provided) self.assertTrue(vert.b.is_resolved()) self.assertTrue(vert.c.provided) self.assertTrue(vert.c.is_resolved()) self.assertTrue(vert.d.provided) self.assertTrue(vert.d.is_resolved()) self.assertTrue(vert.e.provided) self.assertTrue(vert.e.is_resolved()) self.assertTrue(vert.f.provided) self.assertTrue(vert.f.is_resolved()) self.assertTrue(vert.g.provided) self.assertTrue(vert.g.is_resolved()) self.assertFalse(vert.h.provided) self.assertFalse(vert.h.is_resolved()) self.assertFalse(vert.i.provided) self.assertFalse(vert.i.is_resolved()) vert.a.payload = 'some_payload' vert.h.payload = 'some_payload' vert.i.payload = 'some_payload' self.assertTrue(vert.a.provided) self.assertTrue(vert.a.is_resolved()) self.assertTrue(vert.b.provided) self.assertTrue(vert.b.is_resolved()) self.assertTrue(vert.c.provided) self.assertTrue(vert.c.is_resolved()) self.assertTrue(vert.d.provided) self.assertTrue(vert.d.is_resolved()) self.assertTrue(vert.e.provided) self.assertTrue(vert.e.is_resolved()) self.assertTrue(vert.f.provided) self.assertTrue(vert.f.is_resolved()) self.assertTrue(vert.g.provided) self.assertTrue(vert.g.is_resolved()) self.assertTrue(vert.h.provided) self.assertTrue(vert.h.is_resolved()) self.assertTrue(vert.i.provided) self.assertTrue(vert.i.is_resolved())
def test_all_supporters(self): vert = DepDag().vertices vert.a.depends_on('b') vert.b.depends_on('c') self.assertEqual(['b', 'c'], vert.a.supporters(recurse=True))
def test_is_cyclic__negative__empty_dag(self): dag = DepDag() self.assertFalse(dag.is_cyclic())
def test_is_cyclic__negative__one_vertex(self): dag = DepDag() dag.new_vertex('a') self.assertEqual(1, len(dag)) self.assertFalse(dag.is_cyclic())
def test_has_payload__for_object(self): vertex = Vertex('vertex_33', DepDag()) self.assertFalse(vertex.has_payload()) vertex.payload = "any payload would do" self.assertTrue(vertex.has_payload())