aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2015-11-28 14:14:11 -0500
committerJason R. Coombs <jaraco@jaraco.com>2015-11-28 14:14:11 -0500
commitbfe37ff89c87132870d2d64609e58dfe2cafdd7d (patch)
tree4ead3d5abb60acbd4df81038c6b17e4b2d52968b
parente99e20ceb50b6292be0d383ec67f2ca6692a6d70 (diff)
parentdf5516526d165a13c50ef51a392b73955025e7fe (diff)
downloadexternal_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__.py61
-rw-r--r--pkg_resources/tests/test_pkg_resources.py52
-rw-r--r--setuptools/tests/test_egg_info.py11
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):