We populate a custom working set and compute its dependency graph, arranging for one subtree to appear more than once in the graph:
>>> anton_1 = make_dist("anton-1.egg", depends="""berta
... charlie[extra]""")
>>> berta_2 = make_dist("berta-2.egg", depends="charlie[artxe, extra]")
>>> charlie_1_4 = make_dist("charlie-1.4.egg", depends="""[extra]
... dora
... [artxe]
... dora
... emil""")
>>> dora_0_5 = make_dist("dora-0.5.egg")
>>> emil_1 = make_dist("emil-1.egg")
>>> ws = make_working_set(anton_1, berta_2, charlie_1_4, dora_0_5, emil_1)
>>> from tl.eggdeps.graph import Graph
>>> graph = Graph(working_set=ws)
>>> graph.from_working_set()
>>> sprint(graph)
{'anton': {'berta': {None: set([])},
'charlie': {'extra': set([])}},
'berta': {'charlie': {'artxe': set([]), 'extra': set([])}},
'charlie': {'dora': {None: set(['artxe', 'extra'])},
'emil': {None: set(['artxe'])}},
'dora': {},
'emil': {}}
Full trees are still somewhat abbreviated representations of the complete dependency structure but include enough information to reconstruct the latter: they spell out recurring subtrees only once but print the subtree root distributions in all other places and add ellipses to hint at omissions.
>>> from tl.eggdeps.plaintext import print_graph
>>> print_graph(graph, Options())
anton
berta
charlie [artxe, extra] ...
charlie [extra]
[artxe]
dora
emil
[extra]
dora
Version numbers may be printed next to the distribution names:
>>> print_graph(graph, Options(version_numbers=True))
anton 1
berta 2
charlie 1.4 [artxe, extra] ...
charlie 1.4 [extra]
[artxe]
dora 0.5
emil 1
[extra]
dora 0.5
The representation can be shortened in several ways. The terse option omits ellipses for left-out subtrees:
>>> print_graph(graph, Options(terse=True))
anton
berta
charlie [artxe, extra]
charlie [extra]
[artxe]
dora
emil
[extra]
dora
Alternatively, the once option hides omitted subtrees completely so that even the names of root distributions of subtrees are printed in only one place. Which extras of each distribution are required is then not shown anymore. This means that the full information cannot be reconstructed from the output anymore. Still, an ellipsis indicates where one or more subtrees have been left out:
>>> print_graph(graph, Options(once=True))
anton
berta
...
charlie
[artxe]
dora
emil
[extra]
...
These two options may be combined to remove even those ellipses:
>>> print_graph(graph, Options(once=True, terse=True))
anton
berta
charlie
[artxe]
dora
emil
[extra]
If a subgraph of the dependency structure occurs multiple times, a deterministic algorithm is employed to decide at which point in the printed tree the subgraph is to be rendered.
A subgraph will be rendered as close to the root as possible in order to avoid printing a deep tree:
>>> anton = make_dist("anton-1.egg", depends="""berta
... charlie""")
>>> berta = make_dist("berta-2.egg", depends="charlie")
>>> charlie = make_dist("charlie-1.4.egg", depends="dora")
>>> dora = make_dist("dora-0.5.egg")
>>> ws = make_working_set(anton, berta, charlie, dora)
>>> graph = Graph(working_set=ws)
>>> graph.from_specifications("anton")
>>> print_graph(graph, Options())
anton
berta
charlie ...
charlie
dora
In particular, this prevents infinite recursion with cyclic dependency graphs:
>>> anton = make_dist("anton-1.egg", depends="anton")
>>> ws = make_working_set(anton)
>>> graph = Graph(working_set=ws)
>>> graph.from_specifications("anton")
>>> print_graph(graph, Options())
anton
anton ...
If a subgraph can be reached from a root node both by a route consisting only of mandatory dependency edges and by a route including extra dependencies, the subgraph will be rendered at the point reached without considering extras:
>>> anton = make_dist("anton-1.egg", depends="""berta
... [extra]
... charlie""")
>>> ws = make_working_set(anton, berta, charlie, dora)
>>> graph = Graph(working_set=ws)
>>> graph.from_specifications("anton[extra]")
>>> print_graph(graph, Options())
anton
berta
charlie
dora
[extra]
charlie ...
However, if a distribution is required more than once with different sets of extras, the dependencies of all extras involved will be rendered at the same occurrence of that distribution:
>>> anton = make_dist("anton-1.egg", depends="""berta
... charlie""")
>>> berta = make_dist("berta-2.egg", depends="charlie[foo]")
>>> charlie = make_dist("charlie-1.4.egg", depends="""dora
... [foo]
... emil""")
>>> dora = make_dist("dora-0.5.egg")
>>> emil = make_dist("emil-1.egg")
>>> ws = make_working_set(anton, berta, charlie, dora, emil)
>>> graph = Graph(working_set=ws)
>>> graph.from_specifications("anton")
>>> print_graph(graph, Options())
anton
berta
charlie [foo] ...
charlie
dora
[foo]
emil