Пример #1
0
 def test_to_digraph_retains_metadata(self):
     root = tree.Node("chickens", alive=True)
     dead_chicken = tree.Node("chicken.1", alive=False)
     root.add(dead_chicken)
     g = root.to_digraph()
     self.assertEqual(g.node['chickens'], {'alive': True})
     self.assertEqual(g.node['chicken.1'], {'alive': False})
Пример #2
0
    def test_pformat_flat(self):
        root = tree.Node("josh")
        root.add(tree.Node("josh.1"))
        expected = """
josh
|__josh.1
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[0].add(tree.Node("josh.1.1"))
        expected = """
josh
|__josh.1
   |__josh.1.1
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[0][0].add(tree.Node("josh.1.1.1"))
        expected = """
josh
|__josh.1
   |__josh.1.1
      |__josh.1.1.1
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[0][0][0].add(tree.Node("josh.1.1.1.1"))
        expected = """
josh
|__josh.1
   |__josh.1.1
      |__josh.1.1.1
         |__josh.1.1.1.1
"""
        self.assertEqual(expected.strip(), root.pformat())
Пример #3
0
 def test_after_frozen(self):
     root = tree.Node("josh")
     root.add(tree.Node("josh.1"))
     root.freeze()
     self.assertTrue(all(n.frozen
                         for n in root.dfs_iter(include_self=True)))
     self.assertRaises(tree.FrozenNode, root.remove, "josh.1")
     self.assertRaises(tree.FrozenNode, root.disassociate)
     self.assertRaises(tree.FrozenNode, root.add, tree.Node("josh.2"))
Пример #4
0
 def compile(self, task, parent=None):
     graph = gr.DiGraph(name=task.name)
     graph.add_node(task, kind=TASK)
     node = tr.Node(task, kind=TASK)
     if parent is not None:
         parent.add(node)
     return graph, node
Пример #5
0
def _fetch_predecessor_tree(graph, atom):
    """Creates a tree of predecessors, rooted at given atom."""
    root = tree.Node(atom)
    stack = [(root, atom)]
    while stack:
        parent, node = stack.pop()
        for pred_node in graph.predecessors_iter(node):
            pred_node_data = graph.node[pred_node]
            if pred_node_data['kind'] == compiler.FLOW_END:
                # Jump over and/or don't show flow end nodes...
                for pred_pred_node in graph.predecessors_iter(pred_node):
                    stack.append((parent, pred_pred_node))
            else:
                child = tree.Node(pred_node, **pred_node_data)
                parent.add(child)
                # And go further backwards...
                stack.append((child, pred_node))
    return root
Пример #6
0
 def _make_species(self):
     # This is the following tree:
     #
     # animal
     # |__mammal
     # |  |__horse
     # |  |__primate
     # |     |__monkey
     # |     |__human
     # |__reptile
     a = tree.Node("animal")
     m = tree.Node("mammal")
     r = tree.Node("reptile")
     a.add(m)
     a.add(r)
     m.add(tree.Node("horse"))
     p = tree.Node("primate")
     m.add(p)
     p.add(tree.Node("monkey"))
     p.add(tree.Node("human"))
     return a
Пример #7
0
 def test_empty(self):
     root = tree.Node("josh")
     self.assertTrue(root.empty())
Пример #8
0
    def test_pformat(self):

        root = tree.Node("CEO")

        expected = """
CEO
"""

        self.assertEqual(expected.strip(), root.pformat())

        root.add(tree.Node("Infra"))

        expected = """
CEO
|__Infra
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[0].add(tree.Node("Infra.1"))
        expected = """
CEO
|__Infra
   |__Infra.1
"""
        self.assertEqual(expected.strip(), root.pformat())

        root.add(tree.Node("Mail"))
        expected = """
CEO
|__Infra
|  |__Infra.1
|__Mail
"""
        self.assertEqual(expected.strip(), root.pformat())

        root.add(tree.Node("Search"))
        expected = """
CEO
|__Infra
|  |__Infra.1
|__Mail
|__Search
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[-1].add(tree.Node("Search.1"))
        expected = """
CEO
|__Infra
|  |__Infra.1
|__Mail
|__Search
   |__Search.1
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[-1].add(tree.Node("Search.2"))
        expected = """
CEO
|__Infra
|  |__Infra.1
|__Mail
|__Search
   |__Search.1
   |__Search.2
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[0].add(tree.Node("Infra.2"))
        expected = """
CEO
|__Infra
|  |__Infra.1
|  |__Infra.2
|__Mail
|__Search
   |__Search.1
   |__Search.2
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[0].add(tree.Node("Infra.3"))
        expected = """
CEO
|__Infra
|  |__Infra.1
|  |__Infra.2
|  |__Infra.3
|__Mail
|__Search
   |__Search.1
   |__Search.2
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[0][-1].add(tree.Node("Infra.3.1"))
        expected = """
CEO
|__Infra
|  |__Infra.1
|  |__Infra.2
|  |__Infra.3
|     |__Infra.3.1
|__Mail
|__Search
   |__Search.1
   |__Search.2
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[-1][0].add(tree.Node("Search.1.1"))
        expected = """
CEO
|__Infra
|  |__Infra.1
|  |__Infra.2
|  |__Infra.3
|     |__Infra.3.1
|__Mail
|__Search
   |__Search.1
   |  |__Search.1.1
   |__Search.2
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[1].add(tree.Node("Mail.1"))
        expected = """
CEO
|__Infra
|  |__Infra.1
|  |__Infra.2
|  |__Infra.3
|     |__Infra.3.1
|__Mail
|  |__Mail.1
|__Search
   |__Search.1
   |  |__Search.1.1
   |__Search.2
"""
        self.assertEqual(expected.strip(), root.pformat())

        root[1][0].add(tree.Node("Mail.1.1"))
        expected = """
CEO
|__Infra
|  |__Infra.1
|  |__Infra.2
|  |__Infra.3
|     |__Infra.3.1
|__Mail
|  |__Mail.1
|     |__Mail.1.1
|__Search
   |__Search.1
   |  |__Search.1.1
   |__Search.2
"""
        self.assertEqual(expected.strip(), root.pformat())
Пример #9
0
 def compile(self, flow, parent=None):
     """Decomposes a flow into a graph and scope tree hierarchy."""
     graph = gr.DiGraph(name=flow.name)
     graph.add_node(flow, kind=FLOW, noop=True)
     tree_node = tr.Node(flow, kind=FLOW, noop=True)
     if parent is not None:
         parent.add(tree_node)
     if flow.retry is not None:
         tree_node.add(tr.Node(flow.retry, kind=RETRY))
     decomposed = dict(
         (child, self._deep_compiler_func(child, parent=tree_node)[0])
         for child in flow)
     decomposed_graphs = list(six.itervalues(decomposed))
     graph = gr.merge_graphs(graph,
                             *decomposed_graphs,
                             overlap_detector=_overlap_occurrence_detector)
     for u, v, attr_dict in flow.iter_links():
         u_graph = decomposed[u]
         v_graph = decomposed[v]
         _add_update_edges(graph,
                           u_graph.no_successors_iter(),
                           list(v_graph.no_predecessors_iter()),
                           attr_dict=attr_dict)
     # Insert the flow(s) retry if needed, and always make sure it
     # is the **immediate** successor of the flow node itself.
     if flow.retry is not None:
         graph.add_node(flow.retry, kind=RETRY)
         _add_update_edges(graph, [flow], [flow.retry],
                           attr_dict={LINK_INVARIANT: True})
         for node in graph.nodes_iter():
             if node is not flow.retry and node is not flow:
                 graph.node[node].setdefault(RETRY, flow.retry)
         from_nodes = [flow.retry]
         attr_dict = {LINK_INVARIANT: True, LINK_RETRY: True}
     else:
         from_nodes = [flow]
         attr_dict = {LINK_INVARIANT: True}
     # Ensure all nodes with no predecessors are connected to this flow
     # or its retry node (so that the invariant that the flow node is
     # traversed through before its contents is maintained); this allows
     # us to easily know when we have entered a flow (when running) and
     # do special and/or smart things such as only traverse up to the
     # start of a flow when looking for node deciders.
     _add_update_edges(
         graph,
         from_nodes, [
             node
             for node in graph.no_predecessors_iter() if node is not flow
         ],
         attr_dict=attr_dict)
     # Connect all nodes with no successors into a special terminator
     # that is used to identify the end of the flow and ensure that all
     # execution traversals will traverse over this node before executing
     # further work (this is especially useful for nesting and knowing
     # when we have exited a nesting level); it allows us to do special
     # and/or smart things such as applying deciders up to (but not
     # beyond) a flow termination point.
     #
     # Do note that in a empty flow this will just connect itself to
     # the flow node itself... and also note we can not use the flow
     # object itself (primarily because the underlying graph library
     # uses hashing to identify node uniqueness and we can easily create
     # a loop if we don't do this correctly, so avoid that by just
     # creating this special node and tagging it with a special kind); we
     # may be able to make this better in the future with a multidigraph
     # that networkx provides??
     flow_term = Terminator(flow)
     graph.add_node(flow_term, kind=FLOW_END, noop=True)
     _add_update_edges(graph, [
         node
         for node in graph.no_successors_iter() if node is not flow_term
     ], [flow_term],
                       attr_dict={LINK_INVARIANT: True})
     return graph, tree_node