This module provides the means to analyse the dependencies between various distributions and to create a graph representing these dependency relationships. In this document, “distribution” refers to an instance of packaging.database.Distribution or packaging.database.EggInfoDistribution.
Represent a dependency graph between releases. The nodes are distribution instances; the edge model dependencies. An edge from a to b means that a depends on b.
Add distribution to the graph.
Add an edge from distribution x to distribution y with the given label (string).
Add a missing requirement (string) for the given distribution.
Print a subgraph starting from dist. level gives the depth of the subgraph.
Direct access to the graph nodes and edges is provided through these attributes:
Dictionary mapping distributions to a list of (other, label) tuples where other is a distribution and the edge is labeled with label (i.e. the version specifier, if such was provided).
Dictionary mapping distributions to a list of predecessors. This allows efficient traversal.
Dictionary mapping distributions to a list of requirements that were not provided by any distribution.
Recursively generate a list of distributions from dists that are dependent on dist.
Generate a DependencyGraph from the given list of distributions.
Write a DOT output for the graph to the file-like object f.
If skip_disconnected is true, all distributions that are not dependent on any other distribution are skipped.
First, we shall generate a graph of all the distributions on the system and then create an image out of it using the tools provided by Graphviz:
from packaging.database import get_distributions
from packaging.depgraph import generate_graph
dists = list(get_distributions())
graph = generate_graph(dists)
It would be interesting to print out the missing requirements. This can be done as follows:
for dist, reqs in graph.missing.items():
if reqs:
reqs = ' ,'.join(repr(req) for req in reqs)
print('Missing dependencies for %r: %s' % (dist.name, reqs))
Example output is:
Missing dependencies for 'TurboCheetah': 'Cheetah'
Missing dependencies for 'TurboGears': 'ConfigObj', 'DecoratorTools', 'RuleDispatch'
Missing dependencies for 'jockey': 'PyKDE4.kdecore', 'PyKDE4.kdeui', 'PyQt4.QtCore', 'PyQt4.QtGui'
Missing dependencies for 'TurboKid': 'kid'
Missing dependencies for 'TurboJson: 'DecoratorTools', 'RuleDispatch'
Now, we proceed with generating a graphical representation of the graph. First we write it to a file, and then we generate a PNG image using the dot command-line tool:
from packaging.depgraph import graph_to_dot
with open('output.dot', 'w') as f:
# only show the interesting distributions, skipping the disconnected ones
graph_to_dot(graph, f, skip_disconnected=True)
We can create the final picture using:
$ dot -Tpng output.dot > output.png
An example result is:
If you want to include egg distributions as well, then the code requires only one change, namely the line:
dists = list(packaging.database.get_distributions())
has to be replaced with:
dists = list(packaging.database.get_distributions(use_egg_info=True))
On many platforms, a richer graph is obtained because at the moment most distributions are provided in the egg rather than the new standard .dist-info format.
We will list all distributions that are dependent on some given distibution. This time, egg distributions will be considered as well:
import sys
from packaging.database import get_distribution, get_distributions
from packaging.depgraph import dependent_dists
dists = list(get_distributions(use_egg_info=True))
dist = get_distribution('bacon', use_egg_info=True)
if dist is None:
sys.exit('No such distribution in the system')
deps = dependent_dists(dists, dist)
deps = ', '.join(repr(x.name) for x in deps)
print('Distributions depending on %r: %s' % (dist.name, deps))
And this is example output:
Distributions depending on 'bacon': 'towel-stuff', 'choxie', 'grammar'