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 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=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_filter(self): # Test we filter the distributions the right way, using version # predicate match method releases = ReleasesList('FooBar', ( ReleaseInfo("FooBar", "1.1"), ReleaseInfo("FooBar", "1.1.1"), ReleaseInfo("FooBar", "1.2"), ReleaseInfo("FooBar", "1.2.1"), )) filtered = releases.filter(VersionPredicate("FooBar (<1.2)")) self.assertNotIn(releases[2], filtered) self.assertNotIn(releases[3], filtered) self.assertIn(releases[0], filtered) self.assertIn(releases[1], filtered)
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 test_predicate_name(self): # Test that names are parsed the right way self.assertEqual('Hey', VersionPredicate('Hey (<1.1)').name) self.assertEqual('Foo-Bar', VersionPredicate('Foo-Bar (1.1)').name) self.assertEqual('Foo Bar', VersionPredicate('Foo Bar (1.1)').name)
def test_predicate(self): # VersionPredicate knows how to parse stuff like: # # Project (>=version, ver2) predicates = ('zope.interface (>3.5.0)', 'AnotherProject (3.4)', 'OtherProject (<3.0)', 'NoVersion', 'Hey (>=2.5,<2.7)') for predicate in predicates: VersionPredicate(predicate) self.assertTrue(VersionPredicate('Hey (>=2.5,<2.7)').match('2.6')) self.assertTrue(VersionPredicate('Ho').match('2.6')) self.assertFalse(VersionPredicate('Hey (>=2.5,!=2.6,<2.7)').match('2.6')) self.assertTrue(VersionPredicate('Ho (<3.0)').match('2.6')) self.assertTrue(VersionPredicate('Ho (<3.0,!=2.5)').match('2.6.0')) self.assertFalse(VersionPredicate('Ho (<3.0,!=2.6)').match('2.6.0')) self.assertTrue(VersionPredicate('Ho (2.5)').match('2.5.4')) self.assertFalse(VersionPredicate('Ho (!=2.5)').match('2.5.2')) self.assertTrue(VersionPredicate('Hey (<=2.5)').match('2.5.9')) self.assertFalse(VersionPredicate('Hey (<=2.5)').match('2.6.0')) self.assertTrue(VersionPredicate('Hey (>=2.5)').match('2.5.1')) self.assertRaises(ValueError, VersionPredicate, '') self.assertTrue(VersionPredicate('Hey 2.5').match('2.5.1')) # XXX need to silent the micro version in this case self.assertFalse(VersionPredicate('Ho (<3.0,!=2.6)').match('2.6.3')) # Make sure a predicate that ends with a number works self.assertTrue(VersionPredicate('virtualenv5 (1.0)').match('1.0')) self.assertTrue(VersionPredicate('virtualenv5').match('1.0')) self.assertTrue(VersionPredicate('vi5two').match('1.0')) self.assertTrue(VersionPredicate('5two').match('1.0')) self.assertTrue(VersionPredicate('vi5two 1.0').match('1.0')) self.assertTrue(VersionPredicate('5two 1.0').match('1.0')) # test repr for predicate in predicates: self.assertEqual(str(VersionPredicate(predicate)), predicate)
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