def generate_graph(dists): """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 in future # first, build the graph and find out the provides for dist in dists: graph.add_distribution(dist) provides = dist.metadata['Provides-Dist'] + dist.metadata['Provides'] for p in provides: comps = p.strip().rsplit(" ", 1) name = comps[0] version = None if len(comps) == 2: version = comps[1] if len(version) < 3 or version[0] != '(' or version[-1] != ')': raise DistutilsError('Distribution %s has ill formed' \ 'provides field: %s' % (dist.name, p)) version = version[1:-1] # trim off parenthesis if not name in provided: provided[name] = [] provided[name].append((version, dist)) # now make the edges for dist in dists: requires = dist.metadata['Requires-Dist'] + dist.metadata['Requires'] for req in requires: predicate = VersionPredicate(req) name = predicate.name if not name in provided: graph.add_missing(dist, req) else: matched = False for version, provider in provided[name]: try: match = predicate.match(version) except IrrationalVersionError: # XXX small compat-mode if version.split(' ' ) == 1: match = True else: match = False if match: graph.add_edge(dist, provider, req) matched = True break if not matched: graph.add_missing(dist, req) return graph
def obsoletes_distribution(name, version=None, use_egg_info=False): """ Iterates over all distributions to find which distributions obsolete *name*. If a *version* is provided, it will be used to filter the results. If the argument *use_egg_info* is set to ``True``, then ``.egg-info`` distributions will be considered as well. :type name: string :type version: string :parameter name: """ for dist in get_distributions(use_egg_info): obsoleted = (dist.metadata['Obsoletes-Dist'] + dist.metadata['Obsoletes']) for obs in obsoleted: o_components = obs.split(' ', 1) if len(o_components) == 1 or version is None: if name == o_components[0]: yield dist break else: try: predicate = VersionPredicate(obs) except ValueError: raise DistutilsError(('Distribution %s has ill formed' + ' obsoletes field') % (dist.name,)) if name == o_components[0] and predicate.match(version): yield dist break
def obsoletes_distribution(name, version=None, use_egg_info=True): """ Iterates over all distributions to find which distributions obsolete *name*. If a *version* is provided, it will be used to filter the results. If the argument *use_egg_info* is set to ``True``, then ``.egg-info`` distributions will be considered as well. :type name: string :type version: string :parameter name: """ for dist in get_distributions(use_egg_info): obsoleted = (dist.metadata['Obsoletes-Dist'] + dist.metadata['Obsoletes']) for obs in obsoleted: o_components = obs.split(' ', 1) if len(o_components) == 1 or version is None: if name == o_components[0]: yield dist break else: try: predicate = VersionPredicate(obs) except ValueError: raise PackagingError( 'distribution %r has ill-formed obsoletes field: ' '%r' % (dist.name, obs)) if name == o_components[0] and predicate.match(version): yield dist break
def provides_distribution(name, version=None, use_egg_info=True): """ Iterates over all distributions to find which distributions provide *name*. If a *version* is provided, it will be used to filter the results. Scans all elements in ``sys.path`` and looks for all directories ending with ``.dist-info``. Returns a :class:`Distribution` corresponding to the ``.dist-info`` directory that contains a ``METADATA`` that matches *name* for the name metadata. If the argument *use_egg_info* is set to ``True``, then all files and directories ending with ``.egg-info`` are considered as well and returns an :class:`EggInfoDistribution` instance. This function only returns the first result found, since no more than one values are expected. If the directory is not found, returns ``None``. :parameter version: a version specifier that indicates the version required, conforming to the format in ``PEP-345`` :type name: string :type version: string """ predicate = None if not version is None: try: predicate = VersionPredicate(name + ' (' + version + ')') except ValueError: raise PackagingError('invalid name or version: %r, %r' % (name, version)) for dist in get_distributions(use_egg_info): provided = dist.metadata['Provides-Dist'] + dist.metadata['Provides'] for p in provided: p_components = p.rsplit(' ', 1) if len(p_components) == 1 or predicate is None: if name == p_components[0]: yield dist break else: p_name, p_ver = p_components if len(p_ver) < 2 or p_ver[0] != '(' or p_ver[-1] != ')': raise PackagingError( 'distribution %r has invalid Provides field: %r' % (dist.name, p)) p_ver = p_ver[1:-1] # trim off the parenthesis if p_name == name and predicate.match(p_ver): yield dist break
def test_micro_predicate(self): self.assertNotEqual(V('3.4.0'), V('3.4')) predicate = VersionPredicate('zope.event (3.4.0)') self.assertTrue(predicate.match('3.4.0')) self.assertFalse(predicate.match('3.4.1'))
def generate_graph(dists): """Generates a dependency graph from the given distributions. :parameter dists: a list of distributions :type dists: list of :class:`distutils2.database.Distribution` and :class:`distutils2.database.EggInfoDistribution` instances :rtype: a :class:`DependencyGraph` instance """ graph = DependencyGraph() provided = {} # maps names to lists of (version, dist) tuples # first, build the graph and find out the provides for dist in dists: graph.add_distribution(dist) provides = (dist.metadata['Provides-Dist'] + dist.metadata['Provides'] + ['%s (%s)' % (dist.name, dist.version)]) for p in provides: comps = p.strip().rsplit(" ", 1) name = comps[0] version = None if len(comps) == 2: version = comps[1] if len(version) < 3 or version[0] != '(' or version[-1] != ')': raise PackagingError('distribution %r has ill-formed' 'provides field: %r' % (dist.name, p)) version = version[1:-1] # trim off parenthesis if name not in provided: provided[name] = [] provided[name].append((version, dist)) # now make the edges for dist in dists: requires = dist.metadata['Requires-Dist'] + dist.metadata['Requires'] for req in requires: try: predicate = VersionPredicate(req) except IrrationalVersionError: # XXX compat-mode if cannot read the version name = req.split()[0] predicate = VersionPredicate(name) name = predicate.name if name not in provided: graph.add_missing(dist, req) else: matched = False for version, provider in provided[name]: try: match = predicate.match(version) except IrrationalVersionError: # XXX small compat-mode if version.split(' ') == 1: match = True else: match = False if match: graph.add_edge(dist, provider, req) matched = True break if not matched: graph.add_missing(dist, req) return graph