diff options
author | Jason R. Coombs <jaraco@jaraco.com> | 2015-11-28 14:14:11 -0500 |
---|---|---|
committer | Jason R. Coombs <jaraco@jaraco.com> | 2015-11-28 14:14:11 -0500 |
commit | bfe37ff89c87132870d2d64609e58dfe2cafdd7d (patch) | |
tree | 4ead3d5abb60acbd4df81038c6b17e4b2d52968b | |
parent | e99e20ceb50b6292be0d383ec67f2ca6692a6d70 (diff) | |
parent | df5516526d165a13c50ef51a392b73955025e7fe (diff) | |
download | external_python_setuptools-bfe37ff89c87132870d2d64609e58dfe2cafdd7d.tar.gz external_python_setuptools-bfe37ff89c87132870d2d64609e58dfe2cafdd7d.tar.bz2 external_python_setuptools-bfe37ff89c87132870d2d64609e58dfe2cafdd7d.zip |
Merge Pull Request #144
-rw-r--r-- | pkg_resources/__init__.py | 61 | ||||
-rw-r--r-- | pkg_resources/tests/test_pkg_resources.py | 52 | ||||
-rw-r--r-- | setuptools/tests/test_egg_info.py | 11 |
3 files changed, 109 insertions, 15 deletions
diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 0c024f1b..46f09a2d 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -2473,6 +2473,18 @@ def _remove_md5_fragment(location): return location +def _version_from_file(lines): + """ + Given an iterable of lines from a Metadata file, return + the value of the Version field, if present, or None otherwise. + """ + is_version_line = lambda line: line.lower().startswith('version:') + version_lines = filter(is_version_line, lines) + line = next(iter(version_lines), '') + _, _, value = line.partition(':') + return safe_version(value.strip()) or None + + class Distribution(object): """Wrap an actual or potential sys.path entry w/metadata""" PKG_INFO = 'PKG-INFO' @@ -2490,22 +2502,29 @@ class Distribution(object): self._provider = metadata or empty_provider @classmethod - def from_location(cls, location, basename, metadata=None,**kw): + def from_location(cls, location, basename, metadata=None, **kw): project_name, version, py_version, platform = [None]*4 + dist_path = os.path.join(location, basename) basename, ext = os.path.splitext(basename) if ext.lower() in _distributionImpl: - # .dist-info gets much metadata differently + cls = _distributionImpl[ext.lower()] + match = EGG_NAME(basename) if match: project_name, version, py_version, platform = match.group( - 'name','ver','pyver','plat' + 'name', 'ver', 'pyver', 'plat' ) - cls = _distributionImpl[ext.lower()] + + version = cls._version_from_metadata(dist_path) or version return cls( location, metadata, project_name=project_name, version=version, py_version=py_version, platform=platform, **kw ) + @staticmethod + def _version_from_metadata(dist_path): + pass + @property def hashcmp(self): return ( @@ -2591,13 +2610,11 @@ class Distribution(object): try: return self._version except AttributeError: - for line in self._get_metadata(self.PKG_INFO): - if line.lower().startswith('version:'): - self._version = safe_version(line.split(':',1)[1].strip()) - return self._version - else: + version = _version_from_file(self._get_metadata(self.PKG_INFO)) + if version is None: tmpl = "Missing 'Version:' header and/or %s file" raise ValueError(tmpl % self.PKG_INFO, self) + return version @property def _dep_map(self): @@ -2802,6 +2819,30 @@ class Distribution(object): return [dep for dep in self._dep_map if dep] +class EggInfoDistribution(Distribution): + + @staticmethod + def _version_from_metadata(dist_path): + """ + Packages installed by distutils (e.g. numpy or scipy), + which uses an old safe_version, and so + their version numbers can get mangled when + converted to filenames (e.g., 1.11.0.dev0+2329eae to + 1.11.0.dev0_2329eae). These distributions will not be + parsed properly + downstream by Distribution and safe_version, so + take an extra step and try to get the version number from + the metadata file itself instead of the filename. + """ + if not os.path.isfile(dist_path): + return + try: + with open(dist_path) as strm: + return _version_from_file(strm) + except IOError: + pass + + class DistInfoDistribution(Distribution): """Wrap an actual or potential sys.path entry w/metadata, .dist-info style""" PKG_INFO = 'METADATA' @@ -2867,7 +2908,7 @@ class DistInfoDistribution(Distribution): _distributionImpl = { '.egg': Distribution, - '.egg-info': Distribution, + '.egg-info': EggInfoDistribution, '.dist-info': DistInfoDistribution, } diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index 564d7cec..0a03dd93 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -5,9 +5,15 @@ import zipfile import datetime import time import subprocess +import stat +import distutils.dist +import distutils.command.install_egg_info + +import pytest import pkg_resources + try: unicode except NameError: @@ -109,3 +115,49 @@ class TestIndependence: ) cmd = [sys.executable, '-c', '; '.join(lines)] subprocess.check_call(cmd) + + + +class TestDeepVersionLookupDistutils(object): + + @pytest.fixture + def env(self, tmpdir): + """ + Create a package environment, similar to a virtualenv, + in which packages are installed. + """ + class Environment(str): + pass + + env = Environment(tmpdir) + tmpdir.chmod(stat.S_IRWXU) + subs = 'home', 'lib', 'scripts', 'data', 'egg-base' + env.paths = dict( + (dirname, str(tmpdir / dirname)) + for dirname in subs + ) + list(map(os.mkdir, env.paths.values())) + return env + + def create_foo_pkg(self, env, version): + """ + Create a foo package installed (distutils-style) to env.paths['lib'] + as version. + """ + attrs = dict(name='foo', version=version) + dist = distutils.dist.Distribution(attrs) + iei_cmd = distutils.command.install_egg_info.install_egg_info(dist) + iei_cmd.initialize_options() + iei_cmd.install_dir = env.paths['lib'] + iei_cmd.finalize_options() + iei_cmd.run() + + def test_version_resolved_from_egg_info(self, env): + version = '1.11.0.dev0+2329eae' + self.create_foo_pkg(env, version) + + # this requirement parsing will raise a VersionConflict unless the + # .egg-info file is parsed (see #419 on BitBucket) + req = pkg_resources.Requirement.parse('foo>=1.9') + dist = pkg_resources.WorkingSet([env.paths['lib']]).find(req) + assert dist.version == version diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index a1caf9fd..645c379c 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -8,7 +8,11 @@ from .textwrap import DALS from . import contexts -class TestEggInfo: +class Environment(str): + pass + + +class TestEggInfo(object): setup_script = DALS(""" from setuptools import setup @@ -33,8 +37,6 @@ class TestEggInfo: @pytest.yield_fixture def env(self): - class Environment(str): pass - with contexts.tempdir(prefix='setuptools-test.') as env_dir: env = Environment(env_dir) os.chmod(env_dir, stat.S_IRWXU) @@ -49,8 +51,7 @@ class TestEggInfo: f.write(DALS(""" [egg_info] egg-base = %(egg-base)s - """ % env.paths - )) + """ % env.paths)) yield env def test_egg_base_installed_egg_info(self, tmpdir_cwd, env): |