1
1
Fork 0
mirror of https://github.com/pypa/pip synced 2023-12-13 21:30:23 +01:00

Ensure wheel-Version is compatible with pip

This commit is contained in:
Matthew Iversen 2014-02-15 17:21:22 +11:00 committed by Donald Stufft
parent 3333f5def6
commit b26d91c880
8 changed files with 130 additions and 2 deletions

View file

@ -661,6 +661,9 @@ exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\\r\\n',
self.install_editable(install_options, global_options)
return
if self.is_wheel:
version = pip.wheel.wheel_version(self.source_dir)
pip.wheel.check_compatibility(version, self.name)
self.move_wheel_files(self.source_dir, root=root)
self.install_succeeded = True
return

View file

@ -13,18 +13,23 @@ import shutil
import sys
from base64 import urlsafe_b64encode
from email.parser import Parser
from pip.backwardcompat import ConfigParser, StringIO
from pip.exceptions import InvalidWheelFilename
from pip.exceptions import InvalidWheelFilename, UnsupportedWheel
from pip.locations import distutils_scheme
from pip.log import logger
from pip import pep425tags
from pip.util import call_subprocess, normalize_path, make_path_relative
from pip._vendor import pkg_resources
from pip._vendor.distlib.scripts import ScriptMaker
from pip._vendor import pkg_resources
wheel_ext = '.whl'
VERSION_COMPATIBLE = (1, 0)
def rehash(path, algo='sha256', blocksize=1<<20):
"""Return (hash, length) for path using hashlib.new(algo)"""
@ -388,6 +393,52 @@ def uninstallation_paths(dist):
yield path
def wheel_version(source_dir):
"""
Return the Wheel-Version of an extracted wheel, if possible.
Otherwise, return False if we couldn't parse / extract it.
"""
try:
dist = [d for d in pkg_resources.find_on_path(None, source_dir)][0]
wheel_data = dist.get_metadata('WHEEL')
wheel_data = Parser().parsestr(wheel_data)
version = wheel_data['Wheel-Version'].strip()
version = tuple(map(int, version.split('.')))
return version
except:
return False
def check_compatibility(version, name):
"""
Raises errors or warns if called with an incompatible Wheel-Version.
Pip should refuse to install a Wheel-Version that's a major series
ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when
installing a version only minor version ahead (e.g 1.2 > 1.1).
version: a 2-tuple representing a Wheel-Version (Major, Minor)
name: name of wheel or package to raise exception about
:raises UnsupportedWheel: when an incompatible Wheel-Version is given
"""
if not version:
raise UnsupportedWheel(
"%s is in an unsupported or invalid wheel" % name
)
if version[0] > VERSION_COMPATIBLE[0]:
raise UnsupportedWheel(
"%s's Wheel-Version (%s) is not compatible with this version "
"of pip" % (name, '.'.join(map(str, version)))
)
elif version > VERSION_COMPATIBLE:
logger.warn('Installing from a newer Wheel-Version (%s)'
% '.'.join(map(str, version)))
class Wheel(object):
"""A wheel file"""

View file

@ -29,6 +29,11 @@ FSPkg
-----
for installing from the file system
futurewheel
-----------
Wheels of a Wheel-Version that is newer in minor and major series.
Their version coincides with the apparent Wheel-Version they indicate.
gmpy-1.15.tar.gz
----------------
hash testing (although this pkg isn't needed explicitly)

View file

@ -3,6 +3,34 @@ import pytest
import glob
from tests.lib.path import Path
from tests.lib import TestFailure
def test_install_from_future_wheel_version(script, data):
"""
Test installing a future wheel
"""
package = data.packages.join("futurewheel-3.0-py2.py3-none-any.whl")
result = script.pip('install', package, '--no-index', expect_error=True)
with pytest.raises(TestFailure):
result.assert_installed('futurewheel', without_egg_link=True,
editable=False)
package = data.packages.join("futurewheel-1.9-py2.py3-none-any.whl")
result = script.pip('install', package, '--no-index', expect_error=False)
result.assert_installed('futurewheel', without_egg_link=True,
editable=False)
def test_install_from_broken_wheel(script, data):
"""
Test that installing a broken wheel fails properly
"""
package = data.packages.join("brokenwheel-1.0-py2.py3-none-any.whl")
result = script.pip('install', package, '--no-index', expect_error=True)
with pytest.raises(TestFailure):
result.assert_installed('futurewheel', without_egg_link=True,
editable=False)
def test_install_from_wheel(script, data):

View file

@ -6,8 +6,11 @@ import pytest
import pkg_resources
from mock import patch, Mock
from pip import wheel
from pip.exceptions import InstallationError, InvalidWheelFilename
from pip.exceptions import (
InstallationError, InvalidWheelFilename, UnsupportedWheel,
)
from pip.index import PackageFinder
from pip.util import unpack_file
from tests.lib import assert_raises_regexp
@ -51,6 +54,44 @@ def test_uninstallation_paths():
assert paths2 == paths
def test_wheel_version(tmpdir, data):
future_wheel = 'futurewheel-1.9-py2.py3-none-any.whl'
broken_wheel = 'brokenwheel-1.0-py2.py3-none-any.whl'
future_version = (1, 9)
unpack_file(data.packages.join(future_wheel),
tmpdir + 'future', None, None)
unpack_file(data.packages.join(broken_wheel),
tmpdir + 'broken', None, None)
assert wheel.wheel_version(tmpdir + 'future') == future_version
assert not wheel.wheel_version(tmpdir + 'broken')
def test_check_compatibility():
name = 'test'
vc = wheel.VERSION_COMPATIBLE
# Major version is higher - should be incompatible
higher_v = (vc[0] + 1, vc[1])
# test raises with correct error
with pytest.raises(UnsupportedWheel) as e:
wheel.check_compatibility(higher_v, name)
assert 'is not compatible' in str(e)
# Should only log.warn - minor version is greator
higher_v = (vc[0], vc[1] + 1)
wheel.check_compatibility(higher_v, name)
# These should work fine
wheel.check_compatibility(wheel.VERSION_COMPATIBLE, name)
# E.g if wheel to install is 1.0 and we support up to 1.2
lower_v = (vc[0], max(0, vc[1] - 1))
wheel.check_compatibility(lower_v, name)
class TestWheelFile(object):
def test_std_wheel_pattern(self):