pip/tests/functional/test_install_upgrade.py

427 lines
14 KiB
Python

import os
import sys
import textwrap
import pytest
from tests.lib import assert_all_changes, pyversion
from tests.lib.local_repos import local_checkout
def test_no_upgrade_unless_requested(script):
"""
No upgrade if not specifically requested.
"""
script.pip('install', 'INITools==0.1', expect_error=True)
result = script.pip('install', 'INITools', expect_error=True)
assert not result.files_created, (
'pip install INITools upgraded when it should not have'
)
def test_invalid_upgrade_strategy_causes_error(script):
"""
It errors out when the upgrade-strategy is an invalid/unrecognised one
"""
result = script.pip_install_local(
'--upgrade', '--upgrade-strategy=bazinga', 'simple',
expect_error=True
)
assert result.returncode
assert "invalid choice" in result.stderr
def test_only_if_needed_does_not_upgrade_deps_when_satisfied(script):
"""
It doesn't upgrade a dependency if it already satisfies the requirements.
"""
script.pip_install_local('simple==2.0', expect_error=True)
result = script.pip_install_local(
'--upgrade', '--upgrade-strategy=only-if-needed', 'require_simple',
expect_error=True
)
assert (
(script.site_packages / 'require_simple-1.0-py%s.egg-info' % pyversion)
not in result.files_deleted
), "should have installed require_simple==1.0"
assert (
(script.site_packages / 'simple-2.0-py%s.egg-info' % pyversion)
not in result.files_deleted
), "should not have uninstalled simple==2.0"
assert (
"Requirement already satisfied, skipping upgrade: simple"
in result.stdout
), "did not print correct message for not-upgraded requirement"
def test_only_if_needed_does_upgrade_deps_when_no_longer_satisfied(script):
"""
It does upgrade a dependency if it no longer satisfies the requirements.
"""
script.pip_install_local('simple==1.0', expect_error=True)
result = script.pip_install_local(
'--upgrade', '--upgrade-strategy=only-if-needed', 'require_simple',
expect_error=True
)
assert (
(script.site_packages / 'require_simple-1.0-py%s.egg-info' % pyversion)
not in result.files_deleted
), "should have installed require_simple==1.0"
assert (
script.site_packages / 'simple-3.0-py%s.egg-info' %
pyversion in result.files_created
), "should have installed simple==3.0"
assert (
script.site_packages / 'simple-1.0-py%s.egg-info' %
pyversion in result.files_deleted
), "should have uninstalled simple==1.0"
def test_eager_does_upgrade_dependecies_when_currently_satisfied(script):
"""
It does upgrade a dependency even if it already satisfies the requirements.
"""
script.pip_install_local('simple==2.0', expect_error=True)
result = script.pip_install_local(
'--upgrade', '--upgrade-strategy=eager', 'require_simple',
expect_error=True
)
assert (
(script.site_packages / 'require_simple-1.0-py%s.egg-info' % pyversion)
not in result.files_deleted
), "should have installed require_simple==1.0"
assert (
(script.site_packages / 'simple-2.0-py%s.egg-info' % pyversion)
in result.files_deleted
), "should have uninstalled simple==2.0"
def test_eager_does_upgrade_dependecies_when_no_longer_satisfied(script):
"""
It does upgrade a dependency if it no longer satisfies the requirements.
"""
script.pip_install_local('simple==1.0', expect_error=True)
result = script.pip_install_local(
'--upgrade', '--upgrade-strategy=eager', 'require_simple',
expect_error=True
)
assert (
(script.site_packages / 'require_simple-1.0-py%s.egg-info' % pyversion)
not in result.files_deleted
), "should have installed require_simple==1.0"
assert (
script.site_packages / 'simple-3.0-py%s.egg-info' %
pyversion in result.files_created
), "should have installed simple==3.0"
assert (
script.site_packages / 'simple-1.0-py%s.egg-info' %
pyversion in result.files_deleted
), "should have uninstalled simple==1.0"
@pytest.mark.network
def test_upgrade_to_specific_version(script):
"""
It does upgrade to specific version requested.
"""
script.pip('install', 'INITools==0.1', expect_error=True)
result = script.pip('install', 'INITools==0.2', expect_error=True)
assert result.files_created, (
'pip install with specific version did not upgrade'
)
assert (
script.site_packages / 'INITools-0.1-py%s.egg-info' %
pyversion in result.files_deleted
)
assert (
script.site_packages / 'INITools-0.2-py%s.egg-info' %
pyversion in result.files_created
)
@pytest.mark.network
def test_upgrade_if_requested(script):
"""
And it does upgrade if requested.
"""
script.pip('install', 'INITools==0.1', expect_error=True)
result = script.pip('install', '--upgrade', 'INITools', expect_error=True)
assert result.files_created, 'pip install --upgrade did not upgrade'
assert (
script.site_packages / 'INITools-0.1-py%s.egg-info' %
pyversion not in result.files_created
)
def test_upgrade_with_newest_already_installed(script, data):
"""
If the newest version of a package is already installed, the package should
not be reinstalled and the user should be informed.
"""
script.pip('install', '-f', data.find_links, '--no-index', 'simple')
result = script.pip(
'install', '--upgrade', '-f', data.find_links, '--no-index', 'simple'
)
assert not result.files_created, 'simple upgraded when it should not have'
assert 'already up-to-date' in result.stdout, result.stdout
@pytest.mark.network
def test_upgrade_force_reinstall_newest(script):
"""
Force reinstallation of a package even if it is already at its newest
version if --force-reinstall is supplied.
"""
result = script.pip('install', 'INITools')
assert script.site_packages / 'initools' in result.files_created, (
sorted(result.files_created.keys())
)
result2 = script.pip(
'install', '--upgrade', '--force-reinstall', 'INITools'
)
assert result2.files_updated, 'upgrade to INITools 0.3 failed'
result3 = script.pip('uninstall', 'initools', '-y', expect_error=True)
assert_all_changes(result, result3, [script.venv / 'build', 'cache'])
@pytest.mark.network
def test_uninstall_before_upgrade(script):
"""
Automatic uninstall-before-upgrade.
"""
result = script.pip('install', 'INITools==0.2', expect_error=True)
assert script.site_packages / 'initools' in result.files_created, (
sorted(result.files_created.keys())
)
result2 = script.pip('install', 'INITools==0.3', expect_error=True)
assert result2.files_created, 'upgrade to INITools 0.3 failed'
result3 = script.pip('uninstall', 'initools', '-y', expect_error=True)
assert_all_changes(result, result3, [script.venv / 'build', 'cache'])
@pytest.mark.network
def test_uninstall_before_upgrade_from_url(script):
"""
Automatic uninstall-before-upgrade from URL.
"""
result = script.pip('install', 'INITools==0.2', expect_error=True)
assert script.site_packages / 'initools' in result.files_created, (
sorted(result.files_created.keys())
)
result2 = script.pip(
'install',
'https://files.pythonhosted.org/packages/source/I/INITools/INITools-'
'0.3.tar.gz',
expect_error=True,
)
assert result2.files_created, 'upgrade to INITools 0.3 failed'
result3 = script.pip('uninstall', 'initools', '-y', expect_error=True)
assert_all_changes(result, result3, [script.venv / 'build', 'cache'])
@pytest.mark.network
def test_upgrade_to_same_version_from_url(script):
"""
When installing from a URL the same version that is already installed, no
need to uninstall and reinstall if --upgrade is not specified.
"""
result = script.pip('install', 'INITools==0.3', expect_error=True)
assert script.site_packages / 'initools' in result.files_created, (
sorted(result.files_created.keys())
)
result2 = script.pip(
'install',
'https://files.pythonhosted.org/packages/source/I/INITools/INITools-'
'0.3.tar.gz',
expect_error=True,
)
assert not result2.files_updated, 'INITools 0.3 reinstalled same version'
result3 = script.pip('uninstall', 'initools', '-y', expect_error=True)
assert_all_changes(result, result3, [script.venv / 'build', 'cache'])
@pytest.mark.network
def test_upgrade_from_reqs_file(script):
"""
Upgrade from a requirements file.
"""
script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent("""\
PyLogo<0.4
# and something else to test out:
INITools==0.3
"""))
install_result = script.pip(
'install', '-r', script.scratch_path / 'test-req.txt'
)
script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent("""\
PyLogo
# and something else to test out:
INITools
"""))
script.pip(
'install', '--upgrade', '-r', script.scratch_path / 'test-req.txt'
)
uninstall_result = script.pip(
'uninstall', '-r', script.scratch_path / 'test-req.txt', '-y'
)
assert_all_changes(
install_result,
uninstall_result,
[script.venv / 'build', 'cache', script.scratch / 'test-req.txt'],
)
def test_uninstall_rollback(script, data):
"""
Test uninstall-rollback (using test package with a setup.py
crafted to fail on install).
"""
result = script.pip(
'install', '-f', data.find_links, '--no-index', 'broken==0.1'
)
assert script.site_packages / 'broken.py' in result.files_created, list(
result.files_created.keys()
)
result2 = script.pip(
'install', '-f', data.find_links, '--no-index', 'broken===0.2broken',
expect_error=True,
)
assert result2.returncode == 1, str(result2)
assert script.run(
'python', '-c', "import broken; print(broken.VERSION)"
).stdout == '0.1\n'
assert_all_changes(
result.files_after,
result2,
[script.venv / 'build'],
)
@pytest.mark.network
def test_should_not_install_always_from_cache(script):
"""
If there is an old cached package, pip should download the newer version
Related to issue #175
"""
script.pip('install', 'INITools==0.2', expect_error=True)
script.pip('uninstall', '-y', 'INITools')
result = script.pip('install', 'INITools==0.1', expect_error=True)
assert (
script.site_packages / 'INITools-0.2-py%s.egg-info' %
pyversion not in result.files_created
)
assert (
script.site_packages / 'INITools-0.1-py%s.egg-info' %
pyversion in result.files_created
)
@pytest.mark.network
def test_install_with_ignoreinstalled_requested(script):
"""
Test old conflicting package is completely ignored
"""
script.pip('install', 'INITools==0.1', expect_error=True)
result = script.pip('install', '-I', 'INITools==0.3', expect_error=True)
assert result.files_created, 'pip install -I did not install'
# both the old and new metadata should be present.
assert os.path.exists(
script.site_packages_path / 'INITools-0.1-py%s.egg-info' % pyversion
)
assert os.path.exists(
script.site_packages_path / 'INITools-0.3-py%s.egg-info' % pyversion
)
@pytest.mark.network
def test_upgrade_vcs_req_with_no_dists_found(script, tmpdir):
"""It can upgrade a VCS requirement that has no distributions otherwise."""
req = "%s#egg=pip-test-package" % local_checkout(
"git+https://github.com/pypa/pip-test-package.git",
tmpdir.joinpath("cache"),
)
script.pip("install", req)
result = script.pip("install", "-U", req)
assert not result.returncode
@pytest.mark.network
def test_upgrade_vcs_req_with_dist_found(script):
"""It can upgrade a VCS requirement that has distributions on the index."""
# TODO(pnasrat) Using local_checkout fails on windows - oddness with the
# test path urls/git.
req = (
"%s#egg=pretend" %
(
"git+git://github.com/alex/pretend@e7f26ad7dbcb4a02a4995aade4"
"743aad47656b27"
)
)
script.pip("install", req, expect_stderr=True)
result = script.pip("install", "-U", req, expect_stderr=True)
assert "pypi.org" not in result.stdout, result.stdout
class TestUpgradeDistributeToSetuptools(object):
"""
From pip1.4 to pip6, pip supported a set of "hacks" (see Issue #1122) to
allow distribute to conflict with setuptools, so that the following would
work to upgrade distribute:
``pip install -U setuptools``
In pip7, the hacks were removed. This test remains to at least confirm pip
can upgrade distribute to setuptools using:
``pip install -U distribute``
The reason this works is that a final version of distribute (v0.7.3) was
released that is simple wrapper with:
install_requires=['setuptools>=0.7']
The test use a fixed set of packages from our test packages dir. Note that
virtualenv-1.9.1 contains distribute-0.6.34 and virtualenv-1.10 contains
setuptools-0.9.7
"""
def prep_ve(self, script, version, pip_src, distribute=False):
self.script = script
self.script.pip_install_local('virtualenv==%s' % version)
args = ['virtualenv', self.script.scratch_path / 'VE']
if distribute:
args.insert(1, '--distribute')
if version == "1.9.1" and not distribute:
# setuptools 0.6 didn't support PYTHONDONTWRITEBYTECODE
del self.script.environ["PYTHONDONTWRITEBYTECODE"]
self.script.run(*args)
if sys.platform == 'win32':
bindir = "Scripts"
else:
bindir = "bin"
self.ve_bin = self.script.scratch_path / 'VE' / bindir
self.script.run(self.ve_bin / 'pip', 'uninstall', '-y', 'pip')
self.script.run(
self.ve_bin / 'python', 'setup.py', 'install',
cwd=pip_src,
expect_stderr=True,
)