[Python-checkins] distutils2: added documentation
tarek.ziade
python-checkins at python.org
Mon May 31 01:56:09 CEST 2010
tarek.ziade pushed 15bce7d7578b to distutils2:
http://hg.python.org/distutils2/rev/15bce7d7578b
changeset: 185:15bce7d7578b
user: Josip Djolonga
date: Mon May 31 00:17:50 2010 +0200
summary: added documentation
files: src/distutils2/depgraph.py
diff --git a/src/distutils2/depgraph.py b/src/distutils2/depgraph.py
--- a/src/distutils2/depgraph.py
+++ b/src/distutils2/depgraph.py
@@ -1,33 +1,77 @@
"""
A dependency graph generator. The graph is represented as an instance of
-:class:`Graph`, and DOT output is possible as well.
+:class:`DependencyGraph`, and DOT output is possible as well.
"""
from distutils2._backport import pkgutil
from distutils2.errors import DistutilsError
from distutils2.version import VersionPredicate
-class Graph:
- nodes = []
+__all__ = ['DependencyGraph', 'generate_graph']
+
+
+class DependencyGraph:
+ """
+ Represents a dependency graph between distributions.
+
+ The depedency relationships are stored in an *adjacency_list* that maps
+ distributions to a list of ``(other, label)`` tuples where ``other``
+ is a distribution and the edge is labelled with ``label`` (i.e. the version
+ specifier, if such was provided). If any missing depencies are found,
+ they are stored in ``missing``. It maps distributions to a list of
+ requirements that were not provided by any other distributions.
+ """
+
adjacency_list = {}
+ missing = {} # maps distributions to a list of unfulfilled requirements
def __init__(self):
- self.nodes = []
self.adjacency_list = {}
+ self.missing = {}
- def add_node(self, x):
- self.nodes.append(x)
- self.adjacency_list[x] = list()
+ def add_distribution(self, distribution):
+ """
+ Add distribution *x* to the graph.
+
+ :type distribution: :class:`pkgutil.Distribution` or
+ :class:`pkgutil.EggInfoDistribution`
+ """
+ self.adjacency_list[distribution] = list()
+ self.missing[distribution] = list()
def add_edge(self, x, y, label=None):
+ """
+ Add an edge from distribution *x* to distribution *y* with the given
+ *label*.
+
+
+ :type x: :class:`pkgutil.Distribution` or
+ :class:`pkgutil.EggInfoDistribution`
+ :type y: :class:`pkgutil.Distribution` or
+ :class:`pkgutil.EggInfoDistribution`
+ :type label: ``str`` or ``None``
+ """
self.adjacency_list[x].append((y, label))
+ def add_missing(self, distribution, requirement):
+ """
+ Add a missing *requirement* for the given *distribution*.
+
+ :type distribution: :class:`pkgutil.Distribution` or
+ :class:`pkgutil.EggInfoDistribution`
+ :type requirement: ``str``
+ """
+ self.missing[distribution].append(requirement)
+
def to_dot(self, f, skip_disconnected = True):
- """ Writes a DOT output for the graph to the provided *file* """
+ """
+ Writes a DOT output for the graph to the provided *file*.
+ If *skip_disconnected* is set to ``True``, then all distributions
+ that are not dependent on any other distributions are skipped.
- def dot_escape(x):
- return x
-
+ :type f: ``file``
+ ;type skip_disconnected: ``bool``
+ """
if not isinstance(f, file):
raise TypeError('the argument has to be of type file')
@@ -55,14 +99,24 @@
f.write('}\n')
def generate_graph(dists):
- graph = Graph()
+ """
+ Generates a dependency graph from the given distributions.
+
+ :parameter dists: a list of distributions
+ :type dists: list of :class:`pkgutil.Distribution` and
+ :class:`pkgutil.EggInfoDistribution` instances
+ :rtype: an :class:`DependencyGraph` instance
+ """
+ graph = DependencyGraph()
provided = {} # maps names to lists of (version, dist) tuples
dists = list(dists) # maybe use generator_tools to copy generators in future
+ missing = [] # a list of (instance, requirement) tuples
+
# first, build the graph and find out the provides
for dist in dists:
- graph.add_node(dist)
+ graph.add_distribution(dist)
provides = dist.metadata['Provides-Dist'] + dist.metadata['Provides']
for p in provides:
@@ -79,7 +133,6 @@
provided[name] = []
provided[name].append((version, dist))
- print provided.keys()
# now make the edges
for dist in dists:
requires = dist.metadata['Requires-Dist'] + dist.metadata['Requires']
@@ -87,23 +140,47 @@
predicate = VersionPredicate(req)
comps = req.split(" ", 1)
name = comps[0]
- label = None # the label for the possible edge
- if len(comps) == 2:
- label = comps[1]
if not name in provided:
- print('Requirement %s for distribution %s is missing' % \
- (req, dist.name))
+ graph.add_missing(dist, req)
else:
for (version, provider) in provided[name]:
if predicate.match(version):
- graph.add_edge(dist, provider, label)
+ graph.add_edge(dist, provider, req)
return graph
+def dependent_dists(dists, dist):
+ """
+ Recursively generate a list of distributions from *dists* that are dependent
+ on *dist*.
+
+ :param dists: a list of distributions
+ :param dist: a distribution, member of *dists* for which we are interested
+ """
+ if not dist in dists:
+ raise ValueError('The given distribution is not a member of the list')
+ graph = generate_graph(dists)
+
+ dep = [dist]
+ fringe = [dist] # list of nodes we should expand
+ while not len(fringe) == 0:
+ next = graph.adjacency_list[fringe.pop()]
+ for (dist, label) in next:
+ if not dist in dep: # avoid infinite loops
+ dep.append(dist)
+ fringe.append(dist)
+
+ dep.pop()
+ return dep
+
if __name__ == '__main__':
- dists = pkgutil.get_distributions(use_egg_info=True)
+ dists = list(pkgutil.get_distributions(use_egg_info=True))
graph = generate_graph(dists)
+ for dist, reqs in graph.missing.iteritems():
+ if len(reqs) > 0:
+ print("Missing dependencies for %s: %s" % (dist.name,
+ ", ".join(reqs)))
f = open('output.dot', 'w')
- graph.to_dot(f, False)
+ graph.to_dot(f, True)
--
Repository URL: http://hg.python.org/distutils2
More information about the Python-checkins
mailing list