[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