test_install.py 60.1 KB
Newer Older
1
import distutils
P
Pradyun S. Gedam 已提交
2
import glob
3
import os
4
import shutil
5
import sys
6
import textwrap
P
Pradyun S. Gedam 已提交
7
from os.path import curdir, join, pardir
8

9
import pytest
H
Hugo 已提交
10
from pip._vendor.six import PY2
11

A
Albert Tugushev 已提交
12
from pip import __version__ as pip_current_version
13
from pip._internal import pep425tags
14
from pip._internal.cli.status_codes import ERROR, SUCCESS
15
from pip._internal.models.index import PyPI, TestPyPI
16
from pip._internal.utils.misc import rmtree
P
Pradyun S. Gedam 已提交
17
from tests.lib import (
18 19 20 21 22 23 24 25 26 27
    _create_svn_repo,
    _create_test_package,
    create_basic_wheel_for_package,
    create_test_package_with_setup,
    need_bzr,
    need_mercurial,
    path_to_url,
    pyversion,
    pyversion_tuple,
    requirements_file,
P
Pradyun S. Gedam 已提交
28
)
29
from tests.lib.filesystem import make_socket_file
M
Marcus Smith 已提交
30 31
from tests.lib.local_repos import local_checkout
from tests.lib.path import Path
32

H
Hugo 已提交
33 34
skip_if_python2 = pytest.mark.skipif(PY2, reason="Non-Python 2 only")
skip_if_not_python2 = pytest.mark.skipif(not PY2, reason="Python 2 only")
H
Hugo 已提交
35

36

B
Benoit Pierre 已提交
37 38 39 40
@pytest.mark.parametrize('command', ('install', 'wheel'))
@pytest.mark.parametrize('variant', ('missing_setuptools', 'bad_setuptools'))
def test_pep518_uses_build_env(script, data, common_wheels, command, variant):
    if variant == 'missing_setuptools':
B
Benoit Pierre 已提交
41
        script.pip("uninstall", "-y", "setuptools")
B
Benoit Pierre 已提交
42
    elif variant == 'bad_setuptools':
43
        setuptools_mod = script.site_packages_path.joinpath("setuptools.py")
44
        with open(setuptools_mod, 'a') as f:
B
Benoit Pierre 已提交
45 46
            f.write('\nraise ImportError("toto")')
    else:
B
Benoit Pierre 已提交
47 48 49
        raise ValueError(variant)
    script.pip(
        command, '--no-index', '-f', common_wheels, '-f', data.packages,
50
        data.src.joinpath("pep518-3.0"),
B
Benoit Pierre 已提交
51
    )
52 53


54 55
def test_pep518_build_env_uses_same_pip(
        script, data, pip_src, common_wheels, deprecated_python):
56 57 58 59 60 61 62 63
    """Ensure the subprocess call to pip for installing the
    build dependencies is using the same version of pip.
    """
    with open(script.scratch_path / 'pip.py', 'w') as fp:
        fp.write('raise ImportError')
    script.run(
        'python', pip_src / 'src/pip', 'install', '--no-index',
        '-f', common_wheels, '-f', data.packages,
64
        data.src.joinpath("pep518-3.0"),
65
        expect_stderr=deprecated_python,
66 67 68
    )


B
Benoit Pierre 已提交
69 70 71
def test_pep518_refuses_conflicting_requires(script, data):
    create_basic_wheel_for_package(script, 'setuptools', '1.0')
    create_basic_wheel_for_package(script, 'wheel', '1.0')
72
    project_dir = data.src.joinpath("pep518_conflicting_requires")
B
Benoit Pierre 已提交
73 74 75 76 77 78
    result = script.pip_install_local('-f', script.scratch_path,
                                      project_dir, expect_error=True)
    assert (
        result.returncode != 0 and
        ('Some build dependencies for %s conflict with PEP 517/518 supported '
         'requirements: setuptools==1.0 is incompatible with '
79
         'setuptools>=40.8.0.' % path_to_url(project_dir)) in result.stderr
B
Benoit Pierre 已提交
80 81 82
    ), str(result)


83
def test_pep518_refuses_invalid_requires(script, data, common_wheels):
84
    result = script.pip(
85
        'install', '-f', common_wheels,
86
        data.src.joinpath("pep518_invalid_requires"),
87 88 89 90 91 92
        expect_error=True
    )
    assert result.returncode == 1
    assert "does not comply with PEP 518" in result.stderr


93 94 95
def test_pep518_refuses_invalid_build_system(script, data, common_wheels):
    result = script.pip(
        'install', '-f', common_wheels,
96
        data.src.joinpath("pep518_invalid_build_system"),
97 98 99 100 101 102
        expect_error=True
    )
    assert result.returncode == 1
    assert "does not comply with PEP 518" in result.stderr


103
def test_pep518_allows_missing_requires(script, data, common_wheels):
104 105
    result = script.pip(
        'install', '-f', common_wheels,
106
        data.src.joinpath("pep518_missing_requires"),
107 108
        expect_stderr=True
    )
109 110
    # Make sure we don't warn when this occurs.
    assert "does not comply with PEP 518" not in result.stderr
111 112 113 114

    # We want it to go through isolation for now.
    assert "Installing build dependencies" in result.stdout, result.stdout

115 116 117 118
    assert result.returncode == 0
    assert result.files_created


119
def test_pep518_with_user_pip(script, pip_src, data, common_wheels):
120 121 122 123 124 125 126 127 128
    """
    Check that build dependencies are installed into the build
    environment without using build isolation for the pip invocation.

    To ensure that we're not using build isolation when installing
    the build dependencies, we install a user copy of pip in the
    non-isolated environment, and break pip in the system site-packages,
    so that isolated uses of pip will fail.
    """
B
Benoit Pierre 已提交
129 130
    script.pip("install", "--ignore-installed",
               "-f", common_wheels, "--user", pip_src)
131
    system_pip_dir = script.site_packages_path / 'pip'
132
    assert not system_pip_dir.exists()
133 134 135
    system_pip_dir.mkdir()
    with open(system_pip_dir / '__init__.py', 'w') as fp:
        fp.write('raise ImportError\n')
B
Benoit Pierre 已提交
136 137
    script.pip(
        'wheel', '--no-index', '-f', common_wheels, '-f', data.packages,
138
        data.src.joinpath("pep518-3.0"),
B
Benoit Pierre 已提交
139
    )
140 141


142 143 144 145 146
def test_pep518_with_extra_and_markers(script, data, common_wheels):
    script.pip(
        'wheel', '--no-index',
        '-f', common_wheels,
        '-f', data.find_links,
147
        data.src.joinpath("pep518_with_extra_and_markers-1.0"),
148 149 150
    )


151 152 153 154 155
def test_pep518_with_namespace_package(script, data, common_wheels):
    script.pip(
        'wheel', '--no-index',
        '-f', common_wheels,
        '-f', data.find_links,
156
        data.src.joinpath("pep518_with_namespace_package-1.0"),
157 158 159 160
        use_module=True,
    )


161 162 163 164 165 166 167 168
@pytest.mark.timeout(60)
@pytest.mark.parametrize('command', ('install', 'wheel'))
@pytest.mark.parametrize('package', ('pep518_forkbomb',
                                     'pep518_twin_forkbombs_first',
                                     'pep518_twin_forkbombs_second'))
def test_pep518_forkbombs(script, data, common_wheels, command, package):
    package_source = next(data.packages.glob(package + '-[0-9]*.tar.gz'))
    result = script.pip(
169
        command, '--no-index', '-v',
170 171 172 173 174 175 176
        '-f', common_wheels,
        '-f', data.find_links,
        package,
        expect_error=True,
    )
    assert '{1} is already being built: {0} from {1}'.format(
        package, path_to_url(package_source),
177
    ) in result.stderr, str(result)
178 179


X
Xavier Fernandez 已提交
180
@pytest.mark.network
181 182
def test_pip_second_command_line_interface_works(
        script, pip_src, data, common_wheels, deprecated_python):
183
    """
P
Paul Nasrat 已提交
184
    Check if ``pip<PYVERSION>`` commands behaves equally
185
    """
186
    # Re-install pip so we get the launchers.
B
Benoit Pierre 已提交
187
    script.pip_install_local('-f', common_wheels, pip_src)
188 189
    # On old versions of Python, urllib3/requests will raise a warning about
    # the lack of an SSLContext.
190
    kwargs = {'expect_stderr': deprecated_python}
D
Donald Stufft 已提交
191
    if pyversion_tuple < (2, 7, 9):
192 193
        kwargs['expect_stderr'] = True

P
Paul Nasrat 已提交
194
    args = ['pip%s' % pyversion]
195
    args.extend(['install', 'INITools==0.2'])
196
    args.extend(['-f', data.packages])
197
    result = script.run(*args, **kwargs)
198 199 200
    egg_info_folder = (
        script.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion
    )
D
Donald Stufft 已提交
201
    initools_folder = script.site_packages / 'initools'
202 203 204 205
    assert egg_info_folder in result.files_created, str(result)
    assert initools_folder in result.files_created, str(result)


206 207 208 209 210 211 212 213 214 215 216 217 218
def test_install_exit_status_code_when_no_requirements(script):
    """
    Test install exit status code when no requirements specified
    """
    result = script.pip('install', expect_error=True)
    assert "You must give at least one requirement to install" in result.stderr
    assert result.returncode == ERROR


def test_install_exit_status_code_when_blank_requirements_file(script):
    """
    Test install exit status code when blank requirements file specified
    """
219
    script.scratch_path.joinpath("blank.txt").write_text("\n")
220 221 222
    script.pip('install', '-r', 'blank.txt')


223
@pytest.mark.network
224
def test_basic_install_from_pypi(script):
225 226 227
    """
    Test installing a package from PyPI.
    """
D
Donald Stufft 已提交
228
    result = script.pip('install', '-vvv', 'INITools==0.2')
229 230 231
    egg_info_folder = (
        script.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion
    )
D
Donald Stufft 已提交
232
    initools_folder = script.site_packages / 'initools'
233 234
    assert egg_info_folder in result.files_created, str(result)
    assert initools_folder in result.files_created, str(result)
235

236 237 238 239
    # Should not display where it's looking for files
    assert "Looking in indexes: " not in result.stdout
    assert "Looking in links: " not in result.stdout

240

241
def test_basic_editable_install(script):
242 243 244
    """
    Test editable installation.
    """
D
Donald Stufft 已提交
245
    result = script.pip('install', '-e', 'INITools==0.2', expect_error=True)
246
    assert (
247
        "INITools==0.2 is not a valid editable requirement"
248
        in result.stderr
249
    )
250 251
    assert not result.files_created
    assert not result.files_updated
252

253

X
Xavier Fernandez 已提交
254
@pytest.mark.svn
255
def test_basic_install_editable_from_svn(script):
256 257 258
    """
    Test checking out from svn.
    """
259 260
    checkout_path = _create_test_package(script)
    repo_url = _create_svn_repo(script, checkout_path)
261 262
    result = script.pip(
        'install',
263
        '-e', 'svn+' + repo_url + '#egg=version-pkg'
264
    )
265
    result.assert_installed('version-pkg', with_files=['.svn'])
266

267

268
def _test_install_editable_from_git(script, tmpdir):
269 270 271
    """Test cloning from Git."""
    pkg_path = _create_test_package(script, name='testpackage', vcs='git')
    args = ['install', '-e', 'git+%s#egg=testpackage' % path_to_url(pkg_path)]
C
Chris Hunt 已提交
272
    result = script.pip(*args)
273
    result.assert_installed('testpackage', with_files=['.git'])
274

275

276
def test_basic_install_editable_from_git(script, tmpdir):
277
    _test_install_editable_from_git(script, tmpdir)
278 279


280
def test_install_editable_from_git_autobuild_wheel(
281
        script, tmpdir, with_wheel):
282
    _test_install_editable_from_git(script, tmpdir)
283 284


X
Xavier Fernandez 已提交
285
@pytest.mark.network
286 287 288 289 290 291 292
def test_install_editable_uninstalls_existing(data, script, tmpdir):
    """
    Test that installing an editable uninstalls a previously installed
    non-editable version.
    https://github.com/pypa/pip/issues/1548
    https://github.com/pypa/pip/pull/1552
    """
293
    to_install = data.packages.joinpath("pip-test-package-0.1.tar.gz")
294 295 296 297 298 299 300 301
    result = script.pip_install_local(to_install)
    assert 'Successfully installed pip-test-package' in result.stdout
    result.assert_installed('piptestpackage', editable=False)

    result = script.pip(
        'install', '-e',
        '%s#egg=pip-test-package' %
        local_checkout(
302
            'git+https://github.com/pypa/pip-test-package.git', tmpdir,
303 304 305 306
        ),
    )
    result.assert_installed('pip-test-package', with_files=['.git'])
    assert 'Found existing installation: pip-test-package 0.1' in result.stdout
307
    assert 'Uninstalling pip-test-package-' in result.stdout
308 309 310
    assert 'Successfully uninstalled pip-test-package' in result.stdout


311 312 313 314 315
def test_install_editable_uninstalls_existing_from_path(script, data):
    """
    Test that installing an editable uninstalls a previously installed
    non-editable version from path
    """
316
    to_install = data.src.joinpath('simplewheel-1.0')
317 318
    result = script.pip_install_local(to_install)
    assert 'Successfully installed simplewheel' in result.stdout
319 320
    simple_folder = script.site_packages / 'simplewheel'
    result.assert_installed('simplewheel', editable=False)
321 322 323 324 325 326 327 328 329 330 331 332 333 334
    assert simple_folder in result.files_created, str(result.stdout)

    result = script.pip(
        'install', '-e',
        to_install,
    )
    install_path = script.site_packages / 'simplewheel.egg-link'
    assert install_path in result.files_created, str(result)
    assert 'Found existing installation: simplewheel 1.0' in result.stdout
    assert 'Uninstalling simplewheel-' in result.stdout
    assert 'Successfully uninstalled simplewheel' in result.stdout
    assert simple_folder in result.files_deleted, str(result.stdout)


335
@need_mercurial
336
def test_basic_install_editable_from_hg(script, tmpdir):
337
    """Test cloning and hg+file install from Mercurial."""
338 339
    pkg_path = _create_test_package(script, name='testpackage', vcs='hg')
    args = ['install', '-e', 'hg+%s#egg=testpackage' % path_to_url(pkg_path)]
C
Chris Hunt 已提交
340
    result = script.pip(*args)
341
    result.assert_installed('testpackage', with_files=['.hg'])
342 343
    assert path_to_url(pkg_path).startswith("file://")

344

345

346
@need_mercurial
347
def test_vcs_url_final_slash_normalization(script, tmpdir):
348 349 350
    """
    Test that presence or absence of final slash in VCS URL is normalized.
    """
351 352
    pkg_path = _create_test_package(script, name='testpackage', vcs='hg')
    args = ['install', '-e', 'hg+%s/#egg=testpackage' % path_to_url(pkg_path)]
C
Chris Hunt 已提交
353
    result = script.pip(*args)
354
    result.assert_installed('testpackage', with_files=['.hg'])
355

356

357
@need_bzr
358
def test_install_editable_from_bazaar(script, tmpdir):
359 360 361
    """Test checking out from Bazaar."""
    pkg_path = _create_test_package(script, name='testpackage', vcs='bazaar')
    args = ['install', '-e', 'bzr+%s/#egg=testpackage' % path_to_url(pkg_path)]
C
Chris Hunt 已提交
362
    result = script.pip(*args)
363
    result.assert_installed('testpackage', with_files=['.bzr'])
F
Francesco 已提交
364

365

366
@pytest.mark.network
367
@need_bzr
368
def test_vcs_url_urlquote_normalization(script, tmpdir):
369 370 371
    """
    Test that urlquoted characters are normalized for repo URL comparison.
    """
372
    script.pip(
373 374 375 376 377
        'install', '-e',
        '%s/#egg=django-wikiapp' %
        local_checkout(
            'bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp'
            '/release-0.1',
378
            tmpdir,
379 380
        ),
    )
381

382

383
def test_basic_install_from_local_directory(script, data):
384 385 386
    """
    Test installing from a local directory.
    """
387
    to_install = data.packages.joinpath("FSPkg")
D
Donald Stufft 已提交
388
    result = script.pip('install', to_install, expect_error=False)
D
Donald Stufft 已提交
389
    fspkg_folder = script.site_packages / 'fspkg'
390
    egg_info_folder = (
D
Donald Stufft 已提交
391
        script.site_packages / 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion
392
    )
393 394
    assert fspkg_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)
395

396

397
def test_basic_install_relative_directory(script, data):
398
    """
399
    Test installing a requirement using a relative path.
400
    """
401
    egg_info_file = (
402 403 404 405 406
        script.site_packages / 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion
    )
    egg_link_file = (
        script.site_packages / 'FSPkg.egg-link'
    )
407 408 409
    package_folder = script.site_packages / 'fspkg'

    # Compute relative install path to FSPkg from scratch path.
410
    full_rel_path = data.packages.joinpath('FSPkg') - script.scratch_path
411 412 413
    full_rel_url = (
        'file:' + full_rel_path.replace(os.path.sep, '/') + '#egg=FSPkg'
    )
414
    embedded_rel_path = script.scratch_path.joinpath(full_rel_path)
415 416 417

    # For each relative path, install as either editable or not using either
    # URLs with egg links or not.
418
    for req_path in (full_rel_path, full_rel_url, embedded_rel_path):
419 420 421 422 423
        # Regular install.
        result = script.pip('install', req_path,
                            cwd=script.scratch_path)
        assert egg_info_file in result.files_created, str(result)
        assert package_folder in result.files_created, str(result)
424 425
        script.pip('uninstall', '-y', 'fspkg')

426 427 428 429 430
        # Editable install.
        result = script.pip('install', '-e' + req_path,
                            cwd=script.scratch_path)
        assert egg_link_file in result.files_created, str(result)
        script.pip('uninstall', '-y', 'fspkg')
431 432


433 434 435 436 437 438 439 440
def test_install_quiet(script, data):
    """
    Test that install -q is actually quiet.
    """
    # Apparently if pip install -q is not actually quiet, then it breaks
    # everything. See:
    #   https://github.com/pypa/pip/issues/3418
    #   https://github.com/docker-library/python/issues/83
441
    to_install = data.packages.joinpath("FSPkg")
442
    result = script.pip('install', '-qqq', to_install, expect_error=False)
443 444 445 446
    assert result.stdout == ""
    assert result.stderr == ""


447 448 449 450 451 452 453 454 455 456 457
def test_hashed_install_success(script, data, tmpdir):
    """
    Test that installing various sorts of requirements with correct hashes
    works.

    Test file URLs and index packages (which become HTTP URLs behind the
    scenes).

    """
    file_url = path_to_url(
        (data.packages / 'simple-1.0.tar.gz').abspath)
E
Erik Rose 已提交
458 459 460 461 462 463 464
    with requirements_file(
            'simple2==1.0 --hash=sha256:9336af72ca661e6336eb87bc7de3e8844d853e'
            '3848c2b9bbd2e8bf01db88c2c7\n'
            '{simple} --hash=sha256:393043e672415891885c9a2a0929b1af95fb866d6c'
            'a016b42d2e6ce53619b653'.format(simple=file_url),
            tmpdir) as reqs_file:
        script.pip_install_local('-r', reqs_file.abspath, expect_error=False)
465 466


467
def test_hashed_install_failure(script, tmpdir):
468 469 470 471 472 473 474
    """Test that wrong hashes stop installation.

    This makes sure prepare_files() is called in the course of installation
    and so has the opportunity to halt if hashes are wrong. Checks on various
    kinds of hashes are in test_req.py.

    """
E
Erik Rose 已提交
475 476
    with requirements_file('simple2==1.0 --hash=sha256:9336af72ca661e6336eb87b'
                           'c7de3e8844d853e3848c2b9bbd2e8bf01db88c2c\n',
477 478 479 480 481 482 483
                           tmpdir) as reqs_file:
        result = script.pip_install_local('-r',
                                          reqs_file.abspath,
                                          expect_error=True)
    assert len(result.files_created) == 0


484 485
def test_install_from_local_directory_with_symlinks_to_directories(
        script, data):
486 487 488
    """
    Test installing from a local directory containing symlinks to directories.
    """
489
    to_install = data.packages.joinpath("symlinks")
490
    result = script.pip('install', to_install, expect_error=False)
D
Donald Stufft 已提交
491
    pkg_folder = script.site_packages / 'symlinks'
492
    egg_info_folder = (
D
Donald Stufft 已提交
493
        script.site_packages / 'symlinks-0.1.dev0-py%s.egg-info' % pyversion
494
    )
495 496 497 498
    assert pkg_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)


499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
@pytest.mark.skipif("sys.platform == 'win32' or sys.version_info < (3,)")
def test_install_from_local_directory_with_socket_file(script, data, tmpdir):
    """
    Test installing from a local directory containing a socket file.
    """
    egg_info_file = (
        script.site_packages / "FSPkg-0.1.dev0-py%s.egg-info" % pyversion
    )
    package_folder = script.site_packages / "fspkg"
    to_copy = data.packages.joinpath("FSPkg")
    to_install = tmpdir.joinpath("src")

    shutil.copytree(to_copy, to_install)
    # Socket file, should be ignored.
    socket_file_path = os.path.join(to_install, "example")
    make_socket_file(socket_file_path)

    result = script.pip("install", "--verbose", to_install, expect_error=False)
    assert package_folder in result.files_created, str(result.stdout)
    assert egg_info_file in result.files_created, str(result)
    assert str(socket_file_path) in result.stderr


522
def test_install_from_local_directory_with_no_setup_py(script, data):
523 524 525
    """
    Test installing from a local directory with no 'setup.py'.
    """
526
    result = script.pip('install', data.root, expect_error=True)
527
    assert not result.files_created
528 529
    assert "is not installable." in result.stderr
    assert "Neither 'setup.py' nor 'pyproject.toml' found." in result.stderr
530

531

532 533
def test_editable_install__local_dir_no_setup_py(
        script, data, deprecated_python):
534
    """
535
    Test installing in editable mode from a local directory with no setup.py.
536
    """
537
    result = script.pip('install', '-e', data.root, expect_error=True)
538
    assert not result.files_created
539 540 541 542 543

    msg = result.stderr
    if deprecated_python:
        assert 'File "setup.py" not found. ' in msg
    else:
544
        assert msg.startswith('ERROR: File "setup.py" not found. ')
545 546 547 548 549 550 551 552 553
    assert 'pyproject.toml' not in msg


def test_editable_install__local_dir_no_setup_py_with_pyproject(
        script, deprecated_python):
    """
    Test installing in editable mode from a local directory with no setup.py
    but that does have pyproject.toml.
    """
554 555 556
    local_dir = script.scratch_path.joinpath('temp').mkdir()
    pyproject_path = local_dir.joinpath('pyproject.toml')
    pyproject_path.write_text('')
557 558 559 560 561 562 563 564

    result = script.pip('install', '-e', local_dir, expect_error=True)
    assert not result.files_created

    msg = result.stderr
    if deprecated_python:
        assert 'File "setup.py" not found. ' in msg
    else:
565
        assert msg.startswith('ERROR: File "setup.py" not found. ')
566
    assert 'A "pyproject.toml" file was found' in msg
567 568


H
Hugo 已提交
569
@skip_if_not_python2
570
@pytest.mark.xfail
571
def test_install_argparse_shadowed(script):
572
    # When argparse is in the stdlib, we support installing it
J
Jakub Wilk 已提交
573
    # even though that's pretty useless because older packages did need to
574 575 576 577 578 579 580 581 582
    # depend on it, and not having its metadata will cause pkg_resources
    # requirements checks to fail // trigger easy-install, both of which are
    # bad.
    # XXX: Note, this test hits the outside-environment check, not the
    # in-stdlib check, because our tests run in virtualenvs...
    result = script.pip('install', 'argparse>=1.4')
    assert "Not uninstalling argparse" in result.stdout


M
Miro Hrončok 已提交
583
@pytest.mark.network
H
Hugo 已提交
584
@skip_if_python2
585
def test_upgrade_argparse_shadowed(script):
586 587 588 589 590 591 592
    # If argparse is installed - even if shadowed for imported - we support
    # upgrading it and properly remove the older versions files.
    script.pip('install', 'argparse==1.3')
    result = script.pip('install', 'argparse>=1.4')
    assert "Not uninstalling argparse" not in result.stdout


593
def test_install_curdir(script, data):
594 595 596
    """
    Test installing current directory ('.').
    """
597
    run_from = data.packages.joinpath("FSPkg")
598 599 600 601
    # Python 2.4 Windows balks if this exists already
    egg_info = join(run_from, "FSPkg.egg-info")
    if os.path.isdir(egg_info):
        rmtree(egg_info)
D
Donald Stufft 已提交
602
    result = script.pip('install', curdir, cwd=run_from, expect_error=False)
D
Donald Stufft 已提交
603
    fspkg_folder = script.site_packages / 'fspkg'
604
    egg_info_folder = (
D
Donald Stufft 已提交
605
        script.site_packages / 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion
606
    )
607 608
    assert fspkg_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)
609

610

611
def test_install_pardir(script, data):
612 613 614
    """
    Test installing parent directory ('..').
    """
615
    run_from = data.packages.joinpath("FSPkg", "fspkg")
D
Donald Stufft 已提交
616
    result = script.pip('install', pardir, cwd=run_from, expect_error=False)
D
Donald Stufft 已提交
617
    fspkg_folder = script.site_packages / 'fspkg'
618
    egg_info_folder = (
D
Donald Stufft 已提交
619
        script.site_packages / 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion
620
    )
621 622
    assert fspkg_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)
623 624


625
@pytest.mark.network
626
def test_install_global_option(script):
627
    """
628 629
    Test using global distutils options.
    (In particular those that disable the actual install action)
630
    """
631 632
    result = script.pip(
        'install', '--global-option=--version', "INITools==0.1",
633
        expect_stderr=True)
634
    assert 'INITools==0.1\n' in result.stdout
635 636


637
def test_install_with_hacked_egg_info(script, data):
638 639 640
    """
    test installing a package which defines its own egg_info class
    """
641
    run_from = data.packages.joinpath("HackedEggInfo")
D
Donald Stufft 已提交
642
    result = script.pip('install', '.', cwd=run_from)
643
    assert 'Successfully installed hackedegginfo-0.0.0\n' in result.stdout
644 645


646
@pytest.mark.network
647
def test_install_using_install_option_and_editable(script, tmpdir):
648 649 650
    """
    Test installing a tool using -e and --install-option
    """
H
Hugo Lopes Tavares 已提交
651
    folder = 'script_folder'
652
    script.scratch_path.joinpath(folder).mkdir()
653
    url = 'git+git://github.com/pypa/pip-test-package'
654
    result = script.pip(
655
        'install', '-e', '%s#egg=pip-test-package' %
656
        local_checkout(url, tmpdir),
657 658
        '--install-option=--script-dir=%s' % folder,
        expect_stderr=True)
659 660 661
    script_file = (
        script.venv / 'src' / 'pip-test-package' /
        folder / 'pip-test-package' + script.exe
662
    )
663
    assert script_file in result.files_created
664 665


666
@pytest.mark.network
667
@need_mercurial
668
def test_install_global_option_using_editable(script, tmpdir):
669 670 671
    """
    Test using global distutils options, but in an editable installation
    """
C
Carl Meyer 已提交
672
    url = 'hg+http://bitbucket.org/runeh/anyjson'
673 674
    result = script.pip(
        'install', '--global-option=--version', '-e',
675
        '%s@0.2.5#egg=anyjson' % local_checkout(url, tmpdir),
676
        expect_stderr=True)
677
    assert 'Successfully installed anyjson' in result.stdout
678 679


680
@pytest.mark.network
681
def test_install_package_with_same_name_in_curdir(script):
682 683 684
    """
    Test installing a package with the same name of a local folder
    """
685
    script.scratch_path.joinpath("mock==0.6").mkdir()
D
Donald Stufft 已提交
686 687
    result = script.pip('install', 'mock==0.6')
    egg_folder = script.site_packages / 'mock-0.6.0-py%s.egg-info' % pyversion
688 689 690 691 692 693 694 695 696
    assert egg_folder in result.files_created, str(result)


mock100_setup_py = textwrap.dedent('''\
                        from setuptools import setup
                        setup(name='mock',
                              version='100.1')''')


697
def test_install_folder_using_dot_slash(script):
698 699 700
    """
    Test installing a folder using pip install ./foldername
    """
701
    script.scratch_path.joinpath("mock").mkdir()
D
Donald Stufft 已提交
702
    pkg_path = script.scratch_path / 'mock'
703
    pkg_path.joinpath("setup.py").write_text(mock100_setup_py)
D
Donald Stufft 已提交
704 705
    result = script.pip('install', './mock')
    egg_folder = script.site_packages / 'mock-100.1-py%s.egg-info' % pyversion
706 707 708
    assert egg_folder in result.files_created, str(result)


709
def test_install_folder_using_slash_in_the_end(script):
710 711
    r"""
    Test installing a folder using pip install foldername/ or foldername\
712
    """
713
    script.scratch_path.joinpath("mock").mkdir()
D
Donald Stufft 已提交
714
    pkg_path = script.scratch_path / 'mock'
715
    pkg_path.joinpath("setup.py").write_text(mock100_setup_py)
D
Donald Stufft 已提交
716 717
    result = script.pip('install', 'mock' + os.path.sep)
    egg_folder = script.site_packages / 'mock-100.1-py%s.egg-info' % pyversion
718 719 720
    assert egg_folder in result.files_created, str(result)


721
def test_install_folder_using_relative_path(script):
722 723 724
    """
    Test installing a folder using pip install folder1/folder2
    """
725 726
    script.scratch_path.joinpath("initools").mkdir()
    script.scratch_path.joinpath("initools", "mock").mkdir()
D
Donald Stufft 已提交
727
    pkg_path = script.scratch_path / 'initools' / 'mock'
728
    pkg_path.joinpath("setup.py").write_text(mock100_setup_py)
D
Donald Stufft 已提交
729
    result = script.pip('install', Path('initools') / 'mock')
D
Donald Stufft 已提交
730
    egg_folder = script.site_packages / 'mock-100.1-py%s.egg-info' % pyversion
731
    assert egg_folder in result.files_created, str(result)
732

733

734
@pytest.mark.network
735
def test_install_package_which_contains_dev_in_name(script):
736
    """
J
Jon Dufresne 已提交
737
    Test installing package from PyPI which contains 'dev' in name
738
    """
D
Donald Stufft 已提交
739
    result = script.pip('install', 'django-devserver==0.0.4')
D
Donald Stufft 已提交
740
    devserver_folder = script.site_packages / 'devserver'
741
    egg_info_folder = (
D
Donald Stufft 已提交
742 743
        script.site_packages / 'django_devserver-0.0.4-py%s.egg-info' %
        pyversion
744
    )
745 746
    assert devserver_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)
747

748

749
def test_install_package_with_target(script):
750 751 752
    """
    Test installing a package using pip install --target
    """
D
Donald Stufft 已提交
753
    target_dir = script.scratch_path / 'target'
754 755
    result = script.pip_install_local('-t', target_dir, "simple==1.0")
    assert Path('scratch') / 'target' / 'simple' in result.files_created, (
756 757
        str(result)
    )
758

759
    # Test repeated call without --upgrade, no files should have changed
760 761 762
    result = script.pip_install_local(
        '-t', target_dir, "simple==1.0", expect_stderr=True,
    )
763
    assert not Path('scratch') / 'target' / 'simple' in result.files_updated
764 765

    # Test upgrade call, check that new version is installed
766 767 768
    result = script.pip_install_local('--upgrade', '-t',
                                      target_dir, "simple==2.0")
    assert Path('scratch') / 'target' / 'simple' in result.files_updated, (
769 770
        str(result)
    )
J
Jon Wayne Parrott 已提交
771
    egg_folder = (
772
        Path('scratch') / 'target' / 'simple-2.0-py%s.egg-info' % pyversion)
J
Jon Wayne Parrott 已提交
773
    assert egg_folder in result.files_created, (
774 775 776
        str(result)
    )

777
    # Test install and upgrade of single-module package
778 779 780
    result = script.pip_install_local('-t', target_dir, 'singlemodule==0.0.0')
    singlemodule_py = Path('scratch') / 'target' / 'singlemodule.py'
    assert singlemodule_py in result.files_created, str(result)
781

782 783 784
    result = script.pip_install_local('-t', target_dir, 'singlemodule==0.0.1',
                                      '--upgrade')
    assert singlemodule_py in result.files_updated, str(result)
785

786

787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
def test_install_nonlocal_compatible_wheel(script, data):
    target_dir = script.scratch_path / 'target'

    # Test install with --target
    result = script.pip(
        'install',
        '-t', target_dir,
        '--no-index', '--find-links', data.find_links,
        '--only-binary=:all:',
        '--python', '3',
        '--platform', 'fakeplat',
        '--abi', 'fakeabi',
        'simplewheel',
    )
    assert result.returncode == SUCCESS

    distinfo = Path('scratch') / 'target' / 'simplewheel-2.0-1.dist-info'
    assert distinfo in result.files_created

    # Test install without --target
    result = script.pip(
        'install',
        '--no-index', '--find-links', data.find_links,
        '--only-binary=:all:',
        '--python', '3',
        '--platform', 'fakeplat',
        '--abi', 'fakeabi',
        'simplewheel',
        expect_error=True
    )
    assert result.returncode == ERROR


def test_install_nonlocal_compatible_wheel_path(script, data):
    target_dir = script.scratch_path / 'target'

    # Test a full path requirement
    result = script.pip(
        'install',
        '-t', target_dir,
        '--no-index',
        '--only-binary=:all:',
        Path(data.packages) / 'simplewheel-2.0-py3-fakeabi-fakeplat.whl'
    )
    assert result.returncode == SUCCESS

    distinfo = Path('scratch') / 'target' / 'simplewheel-2.0.dist-info'
    assert distinfo in result.files_created

    # Test a full path requirement (without --target)
    result = script.pip(
        'install',
        '--no-index',
        '--only-binary=:all:',
        Path(data.packages) / 'simplewheel-2.0-py3-fakeabi-fakeplat.whl',
        expect_error=True
    )
    assert result.returncode == ERROR


847
def test_install_with_target_and_scripts_no_warning(script, with_wheel):
848 849 850 851 852 853 854
    """
    Test that installing with --target does not trigger the "script not
    in PATH" warning (issue #5201)
    """
    target_dir = script.scratch_path / 'target'
    pkga_path = script.scratch_path / 'pkga'
    pkga_path.mkdir()
855
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
856 857 858 859 860 861 862 863 864
        from setuptools import setup
        setup(name='pkga',
              version='0.1',
              py_modules=["pkga"],
              entry_points={
                  'console_scripts': ['pkga=pkga:main']
              }
        )
    """))
865
    pkga_path.joinpath("pkga.py").write_text(textwrap.dedent("""
866 867 868 869 870 871 872 873 874
        def main(): pass
    """))
    result = script.pip('install', '--target', target_dir, pkga_path)
    # This assertion isn't actually needed, if we get the script warning
    # the script.pip() call will fail with "stderr not expected". But we
    # leave the assertion to make the intention of the code clearer.
    assert "--no-warn-script-location" not in result.stderr, str(result)


875
def test_install_package_with_root(script, data):
876 877 878
    """
    Test installing a package using pip install --root
    """
D
Donald Stufft 已提交
879
    root_dir = script.scratch_path / 'root'
880 881 882 883 884 885 886 887 888
    result = script.pip(
        'install', '--root', root_dir, '-f', data.find_links, '--no-index',
        'simple==1.0',
    )
    normal_install_path = (
        script.base_path / script.site_packages / 'simple-1.0-py%s.egg-info' %
        pyversion
    )
    # use distutils to change the root exactly how the --root option does it
M
Marcus Smith 已提交
889
    from distutils.util import change_root
890 891 892 893
    root_path = change_root(
        os.path.join(script.scratch, 'root'),
        normal_install_path
    )
M
Marcus Smith 已提交
894
    assert root_path in result.files_created, str(result)
895

896 897 898 899
    # Should show find-links location in output
    assert "Looking in indexes: " not in result.stdout
    assert "Looking in links: " in result.stdout

900

901 902 903 904 905 906 907
def test_install_package_with_prefix(script, data):
    """
    Test installing a package using pip install --prefix
    """
    prefix_path = script.scratch_path / 'prefix'
    result = script.pip(
        'install', '--prefix', prefix_path, '-f', data.find_links,
908
        '--no-binary', 'simple', '--no-index', 'simple==1.0',
909 910
    )

911
    rel_prefix_path = script.scratch / 'prefix'
912
    install_path = (
913
        distutils.sysconfig.get_python_lib(prefix=rel_prefix_path) /
A
Anthony Sottile 已提交
914
        'simple-1.0-py{}.egg-info'.format(pyversion)
915 916 917 918
    )
    assert install_path in result.files_created, str(result)


919 920 921 922
def test_install_editable_with_prefix(script):
    # make a dummy project
    pkga_path = script.scratch_path / 'pkga'
    pkga_path.mkdir()
923
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
924 925 926 927 928
        from setuptools import setup
        setup(name='pkga',
              version='0.1')
    """))

929 930
    if hasattr(sys, "pypy_version_info"):
        site_packages = os.path.join(
A
Anthony Sottile 已提交
931
            'prefix', 'lib', 'python{}'.format(pyversion), 'site-packages')
932 933
    else:
        site_packages = distutils.sysconfig.get_python_lib(prefix='prefix')
934 935 936

    # make sure target path is in PYTHONPATH
    pythonpath = script.scratch_path / site_packages
937
    pythonpath.mkdir(parents=True)
938 939 940 941 942 943 944 945 946 947 948 949
    script.environ["PYTHONPATH"] = pythonpath

    # install pkga package into the absolute prefix directory
    prefix_path = script.scratch_path / 'prefix'
    result = script.pip(
        'install', '--editable', pkga_path, '--prefix', prefix_path)

    # assert pkga is installed at correct location
    install_path = script.scratch / site_packages / 'pkga.egg-link'
    assert install_path in result.files_created, str(result)


950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
def test_install_package_conflict_prefix_and_user(script, data):
    """
    Test installing a package using pip install --prefix --user errors out
    """
    prefix_path = script.scratch_path / 'prefix'
    result = script.pip(
        'install', '-f', data.find_links, '--no-index', '--user',
        '--prefix', prefix_path, 'simple==1.0',
        expect_error=True, quiet=True,
    )
    assert (
        "Can not combine '--user' and '--prefix'" in result.stderr
    )


965
def test_install_package_that_emits_unicode(script, data):
966
    """
967
    Install a package with a setup.py that emits UTF-8 output and then fails.
968

969
    Refs https://github.com/pypa/pip/issues/326
970
    """
971
    to_install = data.packages.joinpath("BrokenEmitsUTF8")
972 973 974 975
    result = script.pip(
        'install', to_install, expect_error=True, expect_temp=True, quiet=True,
    )
    assert (
976
        'FakeError: this package designed to fail on install' in result.stderr
977
    ), 'stderr: {}'.format(result.stderr)
978
    assert 'UnicodeDecodeError' not in result.stderr
979
    assert 'UnicodeDecodeError' not in result.stdout
980

981

982 983
def test_install_package_with_utf8_setup(script, data):
    """Install a package with a setup.py that declares a utf-8 encoding."""
984
    to_install = data.packages.joinpath("SetupPyUTF8")
985 986
    script.pip('install', to_install)

987

988 989
def test_install_package_with_latin1_setup(script, data):
    """Install a package with a setup.py that declares a latin-1 encoding."""
990
    to_install = data.packages.joinpath("SetupPyLatin1")
991
    script.pip('install', to_install)
992

993

994
def test_url_req_case_mismatch_no_index(script, data):
995
    """
996 997 998
    tar ball url requirements (with no egg fragment), that happen to have upper
    case project names, should be considered equal to later requirements that
    reference the project name using lower case.
999

1000
    tests/data/packages contains Upper-1.0.tar.gz and Upper-2.0.tar.gz
1001 1002
    'requiresupper' has install_requires = ['upper']
    """
1003
    Upper = '/'.join((data.find_links, 'Upper-1.0.tar.gz'))
1004 1005 1006
    result = script.pip(
        'install', '--no-index', '-f', data.find_links, Upper, 'requiresupper'
    )
1007

1008
    # only Upper-1.0.tar.gz should get installed.
D
Donald Stufft 已提交
1009
    egg_folder = script.site_packages / 'Upper-1.0-py%s.egg-info' % pyversion
1010
    assert egg_folder in result.files_created, str(result)
D
Donald Stufft 已提交
1011
    egg_folder = script.site_packages / 'Upper-2.0-py%s.egg-info' % pyversion
1012
    assert egg_folder not in result.files_created, str(result)
1013 1014


1015 1016 1017 1018 1019 1020
def test_url_req_case_mismatch_file_index(script, data):
    """
    tar ball url requirements (with no egg fragment), that happen to have upper
    case project names, should be considered equal to later requirements that
    reference the project name using lower case.

1021
    tests/data/packages3 contains Dinner-1.0.tar.gz and Dinner-2.0.tar.gz
1022 1023 1024 1025 1026 1027 1028 1029
    'requiredinner' has install_requires = ['dinner']

    This test is similar to test_url_req_case_mismatch_no_index; that test
    tests behaviour when using "--no-index -f", while this one does the same
    test when using "--index-url". Unfortunately this requires a different
    set of packages as it requires a prepared index.html file and
    subdirectory-per-package structure.
    """
1030
    Dinner = '/'.join((data.find_links3, 'dinner', 'Dinner-1.0.tar.gz'))
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
    result = script.pip(
        'install', '--index-url', data.find_links3, Dinner, 'requiredinner'
    )

    # only Upper-1.0.tar.gz should get installed.
    egg_folder = script.site_packages / 'Dinner-1.0-py%s.egg-info' % pyversion
    assert egg_folder in result.files_created, str(result)
    egg_folder = script.site_packages / 'Dinner-2.0-py%s.egg-info' % pyversion
    assert egg_folder not in result.files_created, str(result)


def test_url_incorrect_case_no_index(script, data):
    """
    Same as test_url_req_case_mismatch_no_index, except testing for the case
    where the incorrect case is given in the name of the package to install
    rather than in a requirements file.
    """
    result = script.pip(
        'install', '--no-index', '-f', data.find_links, "upper",
    )

    # only Upper-2.0.tar.gz should get installed.
    egg_folder = script.site_packages / 'Upper-1.0-py%s.egg-info' % pyversion
    assert egg_folder not in result.files_created, str(result)
    egg_folder = script.site_packages / 'Upper-2.0-py%s.egg-info' % pyversion
    assert egg_folder in result.files_created, str(result)


def test_url_incorrect_case_file_index(script, data):
    """
    Same as test_url_req_case_mismatch_file_index, except testing for the case
    where the incorrect case is given in the name of the package to install
    rather than in a requirements file.
    """
    result = script.pip(
        'install', '--index-url', data.find_links3, "dinner",
1067
        expect_stderr=True,
1068 1069 1070 1071 1072 1073 1074 1075
    )

    # only Upper-2.0.tar.gz should get installed.
    egg_folder = script.site_packages / 'Dinner-1.0-py%s.egg-info' % pyversion
    assert egg_folder not in result.files_created, str(result)
    egg_folder = script.site_packages / 'Dinner-2.0-py%s.egg-info' % pyversion
    assert egg_folder in result.files_created, str(result)

1076 1077 1078 1079
    # Should show index-url location in output
    assert "Looking in indexes: " in result.stdout
    assert "Looking in links: " not in result.stdout

1080

1081
@pytest.mark.network
1082 1083 1084 1085 1086
def test_compiles_pyc(script):
    """
    Test installing with --compile on
    """
    del script.environ["PYTHONDONTWRITEBYTECODE"]
1087
    script.pip("install", "--compile", "--no-binary=:all:", "INITools==0.2")
1088 1089 1090 1091

    # There are many locations for the __init__.pyc file so attempt to find
    #   any of them
    exists = [
D
Donald Stufft 已提交
1092
        os.path.exists(script.site_packages_path / "initools/__init__.pyc"),
1093 1094 1095
    ]

    exists += glob.glob(
D
Donald Stufft 已提交
1096
        script.site_packages_path / "initools/__pycache__/__init__*.pyc"
1097 1098 1099 1100 1101
    )

    assert any(exists)


1102
@pytest.mark.network
1103
def test_no_compiles_pyc(script):
1104 1105 1106 1107
    """
    Test installing from wheel with --compile on
    """
    del script.environ["PYTHONDONTWRITEBYTECODE"]
1108
    script.pip("install", "--no-compile", "--no-binary=:all:", "INITools==0.2")
1109 1110 1111 1112

    # There are many locations for the __init__.pyc file so attempt to find
    #   any of them
    exists = [
D
Donald Stufft 已提交
1113
        os.path.exists(script.site_packages_path / "initools/__init__.pyc"),
1114 1115 1116
    ]

    exists += glob.glob(
D
Donald Stufft 已提交
1117
        script.site_packages_path / "initools/__pycache__/__init__*.pyc"
1118 1119 1120
    )

    assert not any(exists)
1121 1122 1123


def test_install_upgrade_editable_depending_on_other_editable(script):
1124
    script.scratch_path.joinpath("pkga").mkdir()
1125
    pkga_path = script.scratch_path / 'pkga'
1126
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
1127 1128 1129 1130 1131
        from setuptools import setup
        setup(name='pkga',
              version='0.1')
    """))
    script.pip('install', '--editable', pkga_path)
X
Xavier Fernandez 已提交
1132 1133
    result = script.pip('list', '--format=freeze')
    assert "pkga==0.1" in result.stdout
1134

1135
    script.scratch_path.joinpath("pkgb").mkdir()
1136
    pkgb_path = script.scratch_path / 'pkgb'
1137
    pkgb_path.joinpath("setup.py").write_text(textwrap.dedent("""
1138 1139 1140 1141 1142
        from setuptools import setup
        setup(name='pkgb',
              version='0.1',
              install_requires=['pkga'])
    """))
X
Xavier Fernandez 已提交
1143 1144 1145
    script.pip('install', '--upgrade', '--editable', pkgb_path, '--no-index')
    result = script.pip('list', '--format=freeze')
    assert "pkgb==0.1" in result.stdout
1146

1147 1148

def test_install_subprocess_output_handling(script, data):
1149
    args = ['install', data.src.joinpath('chattymodule')]
1150 1151 1152 1153 1154 1155 1156 1157 1158

    # Regular install should not show output from the chatty setup.py
    result = script.pip(*args)
    assert 0 == result.stdout.count("HELLO FROM CHATTYMODULE")
    script.pip("uninstall", "-y", "chattymodule")

    # With --verbose we should show the output.
    # Only count examples with sys.argv[1] == egg_info, because we call
    # setup.py multiple times, which should not count as duplicate output.
1159 1160
    result = script.pip(*(args + ["--verbose"]), expect_stderr=True)
    assert 1 == result.stderr.count("HELLO FROM CHATTYMODULE egg_info")
1161 1162 1163 1164 1165 1166
    script.pip("uninstall", "-y", "chattymodule")

    # If the install fails, then we *should* show the output... but only once,
    # even if --verbose is given.
    result = script.pip(*(args + ["--global-option=--fail"]),
                        expect_error=True)
1167
    assert 1 == result.stderr.count("I DIE, I DIE")
1168 1169 1170

    result = script.pip(*(args + ["--global-option=--fail", "--verbose"]),
                        expect_error=True)
1171
    assert 1 == result.stderr.count("I DIE, I DIE")
1172

1173 1174 1175

def test_install_log(script, data, tmpdir):
    # test that verbose logs go to "--log" file
1176
    f = tmpdir.joinpath("log.txt")
1177
    args = ['--log=%s' % f,
1178
            'install', data.src.joinpath('chattymodule')]
1179 1180 1181 1182 1183 1184
    result = script.pip(*args)
    assert 0 == result.stdout.count("HELLO FROM CHATTYMODULE")
    with open(f, 'r') as fp:
        # one from egg_info, one from install
        assert 2 == fp.read().count("HELLO FROM CHATTYMODULE")

1185 1186

def test_install_topological_sort(script, data):
X
Xavier Fernandez 已提交
1187
    args = ['install', 'TopoRequires4', '--no-index', '-f', data.packages]
1188 1189 1190 1191
    res = str(script.pip(*args, expect_error=False))
    order1 = 'TopoRequires, TopoRequires2, TopoRequires3, TopoRequires4'
    order2 = 'TopoRequires, TopoRequires3, TopoRequires2, TopoRequires4'
    assert order1 in res or order2 in res, res
1192 1193


1194 1195
def test_install_wheel_broken(script, with_wheel):
    res = script.pip_install_local('wheelbroken', expect_stderr=True)
1196
    assert "Successfully installed wheelbroken-0.1" in str(res), str(res)
1197 1198


1199 1200
def test_cleanup_after_failed_wheel(script, with_wheel):
    res = script.pip_install_local('wheelbrokenafter', expect_stderr=True)
1201 1202
    # One of the effects of not cleaning up is broken scripts:
    script_py = script.bin_path / "script.py"
1203
    assert script_py.exists(), script_py
1204 1205 1206 1207 1208 1209
    shebang = open(script_py, 'r').readline().strip()
    assert shebang != '#!python', shebang
    # OK, assert that we *said* we were cleaning up:
    assert "Running setup.py clean for wheelbrokenafter" in str(res), str(res)


1210
def test_install_builds_wheels(script, data, with_wheel):
1211 1212 1213 1214 1215 1216
    # We need to use a subprocess to get the right value on Windows.
    res = script.run('python', '-c', (
        'from pip._internal.utils import appdirs; '
        'print(appdirs.user_cache_dir("pip"))'
    ))
    wheels_cache = os.path.join(res.stdout.rstrip('\n'), 'wheels')
1217 1218 1219
    # NB This incidentally tests a local tree + tarball inputs
    # see test_install_editable_from_git_autobuild_wheel for editable
    # vcs coverage.
1220
    to_install = data.packages.joinpath('requires_wheelbroken_upper')
1221
    res = script.pip(
1222
        'install', '--no-index', '-f', data.find_links,
1223 1224 1225 1226 1227 1228
        to_install, expect_stderr=True)
    expected = ("Successfully installed requires-wheelbroken-upper-0"
                " upper-2.0 wheelbroken-0.1")
    # Must have installed it all
    assert expected in str(res), str(res)
    wheels = []
1229
    for top, dirs, files in os.walk(wheels_cache):
1230 1231
        wheels.extend(files)
    # and built wheels for upper and wheelbroken
P
Paul Moore 已提交
1232 1233
    assert "Building wheel for upper" in str(res), str(res)
    assert "Building wheel for wheelb" in str(res), str(res)
T
Thomas Kluyver 已提交
1234
    # Wheels are built for local directories, but not cached.
P
Paul Moore 已提交
1235
    assert "Building wheel for requir" in str(res), str(res)
1236 1237 1238 1239 1240
    # wheelbroken has to run install
    # into the cache
    assert wheels != [], str(res)
    # and installed from the wheel
    assert "Running setup.py install for upper" not in str(res), str(res)
T
Thomas Kluyver 已提交
1241 1242
    # Wheels are built for local directories, but not cached.
    assert "Running setup.py install for requir" not in str(res), str(res)
1243 1244
    # wheelbroken has to run install
    assert "Running setup.py install for wheelb" in str(res), str(res)
1245 1246
    # We want to make sure we used the correct implementation tag
    assert wheels == [
A
Anthony Sottile 已提交
1247
        "Upper-2.0-{}-none-any.whl".format(pep425tags.implementation_tag),
1248
    ]
1249 1250


1251
def test_install_no_binary_disables_building_wheels(script, data, with_wheel):
1252
    to_install = data.packages.joinpath('requires_wheelbroken_upper')
1253 1254 1255 1256 1257 1258 1259 1260
    res = script.pip(
        'install', '--no-index', '--no-binary=upper', '-f', data.find_links,
        to_install, expect_stderr=True)
    expected = ("Successfully installed requires-wheelbroken-upper-0"
                " upper-2.0 wheelbroken-0.1")
    # Must have installed it all
    assert expected in str(res), str(res)
    # and built wheels for wheelbroken only
P
Paul Moore 已提交
1261
    assert "Building wheel for wheelb" in str(res), str(res)
1262
    # Wheels are built for local directories, but not cached across runs
P
Paul Moore 已提交
1263
    assert "Building wheel for requir" in str(res), str(res)
1264
    # Don't build wheel for upper which was blacklisted
P
Paul Moore 已提交
1265
    assert "Building wheel for upper" not in str(res), str(res)
1266
    # Wheels are built for local directories, but not cached across runs
1267
    assert "Running setup.py install for requir" not in str(res), str(res)
1268
    # And these two fell back to sdist based installed.
1269 1270
    assert "Running setup.py install for wheelb" in str(res), str(res)
    assert "Running setup.py install for upper" in str(res), str(res)
1271 1272


1273
def test_install_no_binary_disables_cached_wheels(script, data, with_wheel):
1274 1275
    # Seed the cache
    script.pip(
1276
        'install', '--no-index', '-f', data.find_links,
1277 1278 1279 1280 1281 1282 1283
        'upper')
    script.pip('uninstall', 'upper', '-y')
    res = script.pip(
        'install', '--no-index', '--no-binary=:all:', '-f', data.find_links,
        'upper', expect_stderr=True)
    assert "Successfully installed upper-2.0" in str(res), str(res)
    # No wheel building for upper, which was blacklisted
P
Paul Moore 已提交
1284
    assert "Building wheel for upper" not in str(res), str(res)
1285 1286
    # Must have used source, not a cached wheel to install upper.
    assert "Running setup.py install for upper" in str(res), str(res)
1287 1288 1289


def test_install_editable_with_wrong_egg_name(script):
1290
    script.scratch_path.joinpath("pkga").mkdir()
1291
    pkga_path = script.scratch_path / 'pkga'
1292
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
1293 1294 1295 1296 1297
        from setuptools import setup
        setup(name='pkga',
              version='0.1')
    """))
    result = script.pip(
C
Chris Hunt 已提交
1298 1299
        'install', '--editable', 'file://%s#egg=pkgb' % pkga_path
    )
P
Paul Moore 已提交
1300
    assert ("Generating metadata for package pkgb produced metadata "
1301 1302 1303
            "for project name pkga. Fix your #egg=pkgb "
            "fragments.") in result.stderr
    assert "Successfully installed pkga" in str(result), str(result)
1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321


def test_install_tar_xz(script, data):
    try:
        import lzma  # noqa
    except ImportError:
        pytest.skip("No lzma support")
    res = script.pip('install', data.packages / 'singlemodule-0.0.1.tar.xz')
    assert "Successfully installed singlemodule-0.0.1" in res.stdout, res


def test_install_tar_lzma(script, data):
    try:
        import lzma  # noqa
    except ImportError:
        pytest.skip("No lzma support")
    res = script.pip('install', data.packages / 'singlemodule-0.0.1.tar.lzma')
    assert "Successfully installed singlemodule-0.0.1" in res.stdout, res
1322 1323


1324
def test_double_install(script):
1325 1326 1327
    """
    Test double install passing with two same version requirements
    """
1328 1329
    result = script.pip('install', 'pip', 'pip',
                        expect_error=False)
1330 1331 1332 1333
    msg = "Double requirement given: pip (already in pip, name='pip')"
    assert msg not in result.stderr


1334
def test_double_install_fail(script):
1335 1336 1337 1338 1339 1340 1341
    """
    Test double install failing with two different version requirements
    """
    result = script.pip('install', 'pip==*', 'pip==7.1.2', expect_error=True)
    msg = ("Double requirement given: pip==7.1.2 (already in pip==*, "
           "name='pip')")
    assert msg in result.stderr
X
Xavier Fernandez 已提交
1342 1343


1344 1345 1346
def _get_expected_error_text():
    return (
        "Package 'pkga' requires a different Python: {} not in '<1.0'"
1347
    ).format('.'.join(map(str, sys.version_info[:3])))
1348 1349


1350
def test_install_incompatible_python_requires(script):
1351
    script.scratch_path.joinpath("pkga").mkdir()
X
Xavier Fernandez 已提交
1352
    pkga_path = script.scratch_path / 'pkga'
1353
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
X
Xavier Fernandez 已提交
1354 1355 1356 1357 1358 1359
        from setuptools import setup
        setup(name='pkga',
              python_requires='<1.0',
              version='0.1')
    """))
    result = script.pip('install', pkga_path, expect_error=True)
1360
    assert _get_expected_error_text() in result.stderr, str(result)
X
Xavier Fernandez 已提交
1361 1362


1363
def test_install_incompatible_python_requires_editable(script):
1364
    script.scratch_path.joinpath("pkga").mkdir()
X
Xavier Fernandez 已提交
1365
    pkga_path = script.scratch_path / 'pkga'
1366
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
X
Xavier Fernandez 已提交
1367 1368 1369 1370 1371 1372 1373
        from setuptools import setup
        setup(name='pkga',
              python_requires='<1.0',
              version='0.1')
    """))
    result = script.pip(
        'install', '--editable=%s' % pkga_path, expect_error=True)
1374
    assert _get_expected_error_text() in result.stderr, str(result)
X
Xavier Fernandez 已提交
1375 1376


1377
def test_install_incompatible_python_requires_wheel(script, with_wheel):
1378
    script.scratch_path.joinpath("pkga").mkdir()
X
Xavier Fernandez 已提交
1379
    pkga_path = script.scratch_path / 'pkga'
1380
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
X
Xavier Fernandez 已提交
1381 1382 1383 1384 1385 1386 1387 1388 1389
        from setuptools import setup
        setup(name='pkga',
              python_requires='<1.0',
              version='0.1')
    """))
    script.run(
        'python', 'setup.py', 'bdist_wheel', '--universal', cwd=pkga_path)
    result = script.pip('install', './pkga/dist/pkga-0.1-py2.py3-none-any.whl',
                        expect_error=True)
1390
    assert _get_expected_error_text() in result.stderr, str(result)
X
Xavier Fernandez 已提交
1391 1392


1393
def test_install_compatible_python_requires(script):
1394
    script.scratch_path.joinpath("pkga").mkdir()
X
Xavier Fernandez 已提交
1395
    pkga_path = script.scratch_path / 'pkga'
1396
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
X
Xavier Fernandez 已提交
1397 1398 1399 1400 1401
        from setuptools import setup
        setup(name='pkga',
              python_requires='>1.0',
              version='0.1')
    """))
C
Chris Hunt 已提交
1402
    res = script.pip('install', pkga_path)
X
Xavier Fernandez 已提交
1403
    assert "Successfully installed pkga-0.1" in res.stdout, res
1404 1405


1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
@pytest.mark.network
def test_install_pep508_with_url(script):
    res = script.pip(
        'install', '--no-index',
        'packaging@https://files.pythonhosted.org/packages/2f/2b/'
        'c681de3e1dbcd469537aefb15186b800209aa1f299d933d23b48d85c9d56/'
        'packaging-15.3-py2.py3-none-any.whl#sha256='
        'ce1a869fe039fbf7e217df36c4653d1dbe657778b2d41709593a0003584405f4'
    )
    assert "Successfully installed packaging-15.3" in str(res), str(res)


@pytest.mark.network
def test_install_pep508_with_url_in_install_requires(script):
    pkga_path = create_test_package_with_setup(
        script, name='pkga', version='1.0',
        install_requires=[
            'packaging@https://files.pythonhosted.org/packages/2f/2b/'
            'c681de3e1dbcd469537aefb15186b800209aa1f299d933d23b48d85c9d56/'
            'packaging-15.3-py2.py3-none-any.whl#sha256='
            'ce1a869fe039fbf7e217df36c4653d1dbe657778b2d41709593a0003584405f4'
        ],
    )
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
    res = script.pip('install', pkga_path)
    assert "Successfully installed packaging-15.3" in str(res), str(res)


@pytest.mark.network
@pytest.mark.parametrize('index', (PyPI.simple_url, TestPyPI.simple_url))
def test_install_from_test_pypi_with_ext_url_dep_is_blocked(script, index):
    res = script.pip(
        'install',
        '--index-url',
        index,
        'pep-508-url-deps',
        expect_error=True,
    )
    error_message = (
        "Packages installed from PyPI cannot depend on packages "
        "which are not also hosted on PyPI."
    )
    error_cause = (
        "pep-508-url-deps depends on sampleproject@ "
        "https://github.com/pypa/sampleproject/archive/master.zip"
    )
    assert res.returncode == 1
    assert error_message in res.stderr, str(res)
    assert error_cause in res.stderr, str(res)
1454 1455 1456 1457


def test_installing_scripts_outside_path_prints_warning(script):
    result = script.pip_install_local(
C
Chris Hunt 已提交
1458
        "--prefix", script.scratch_path, "script_wheel1"
1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476
    )
    assert "Successfully installed script-wheel1" in result.stdout, str(result)
    assert "--no-warn-script-location" in result.stderr


def test_installing_scripts_outside_path_can_suppress_warning(script):
    result = script.pip_install_local(
        "--prefix", script.scratch_path, "--no-warn-script-location",
        "script_wheel1"
    )
    assert "Successfully installed script-wheel1" in result.stdout, str(result)
    assert "--no-warn-script-location" not in result.stderr


def test_installing_scripts_on_path_does_not_print_warning(script):
    result = script.pip_install_local("script_wheel1")
    assert "Successfully installed script-wheel1" in result.stdout, str(result)
    assert "--no-warn-script-location" not in result.stderr
1477 1478 1479 1480 1481 1482 1483


def test_installed_files_recorded_in_deterministic_order(script, data):
    """
    Ensure that we record the files installed by a package in a deterministic
    order, to make installs reproducible.
    """
1484
    to_install = data.packages.joinpath("FSPkg")
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
    result = script.pip('install', to_install, expect_error=False)
    fspkg_folder = script.site_packages / 'fspkg'
    egg_info = 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion
    installed_files_path = (
        script.site_packages / egg_info / 'installed-files.txt'
    )
    assert fspkg_folder in result.files_created, str(result.stdout)
    assert installed_files_path in result.files_created, str(result)

    installed_files_path = result.files_created[installed_files_path].full
    installed_files_lines = [
        p for p in Path(installed_files_path).read_text().split('\n') if p
    ]
    assert installed_files_lines == sorted(installed_files_lines)
P
Pradyun Gedam 已提交
1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516


def test_install_conflict_results_in_warning(script, data):
    pkgA_path = create_test_package_with_setup(
        script,
        name='pkgA', version='1.0', install_requires=['pkgb == 1.0'],
    )
    pkgB_path = create_test_package_with_setup(
        script,
        name='pkgB', version='2.0',
    )

    # Install pkgA without its dependency
    result1 = script.pip('install', '--no-index', pkgA_path, '--no-deps')
    assert "Successfully installed pkgA-1.0" in result1.stdout, str(result1)

    # Then install an incorrect version of the dependency
    result2 = script.pip(
1517
        'install', '--no-index', pkgB_path, allow_stderr_error=True,
P
Pradyun Gedam 已提交
1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
    )
    assert "pkga 1.0 has requirement pkgb==1.0" in result2.stderr, str(result2)
    assert "Successfully installed pkgB-2.0" in result2.stdout, str(result2)


def test_install_conflict_warning_can_be_suppressed(script, data):
    pkgA_path = create_test_package_with_setup(
        script,
        name='pkgA', version='1.0', install_requires=['pkgb == 1.0'],
    )
    pkgB_path = create_test_package_with_setup(
        script,
        name='pkgB', version='2.0',
    )

    # Install pkgA without its dependency
    result1 = script.pip('install', '--no-index', pkgA_path, '--no-deps')
    assert "Successfully installed pkgA-1.0" in result1.stdout, str(result1)

    # Then install an incorrect version of the dependency; suppressing warning
    result2 = script.pip(
        'install', '--no-index', pkgB_path, '--no-warn-conflicts'
    )
    assert "Successfully installed pkgB-2.0" in result2.stdout, str(result2)
1542 1543 1544 1545


def test_target_install_ignores_distutils_config_install_prefix(script):
    prefix = script.scratch_path / 'prefix'
B
Benoit Pierre 已提交
1546 1547 1548
    distutils_config = Path(os.path.expanduser('~'),
                            'pydistutils.cfg' if sys.platform == 'win32'
                            else '.pydistutils.cfg')
1549
    distutils_config.write_text(textwrap.dedent(
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560
        '''
        [install]
        prefix=%s
        ''' % str(prefix)))
    target = script.scratch_path / 'target'
    result = script.pip_install_local('simplewheel', '-t', target)
    assert (
        "Successfully installed simplewheel" in result.stdout and
        (target - script.base_path) in result.files_created and
        (prefix - script.base_path) not in result.files_created
    ), str(result)
1561 1562


A
Albert Tugushev 已提交
1563
@pytest.mark.network
1564
@pytest.mark.skipif("sys.platform != 'win32'")
A
Albert Tugushev 已提交
1565 1566 1567 1568 1569 1570 1571 1572 1573
@pytest.mark.parametrize('pip_name', [
    'pip',
    'pip{}'.format(sys.version_info[0]),
    'pip{}.{}'.format(*sys.version_info[:2]),
    'pip.exe',
    'pip{}.exe'.format(sys.version_info[0]),
    'pip{}.{}.exe'.format(*sys.version_info[:2])
])
def test_protect_pip_from_modification_on_windows(script, pip_name):
1574
    """
A
Albert Tugushev 已提交
1575 1576
    Test that pip modification command using ``pip install ...``
    raises an error on Windows.
1577
    """
A
Albert Tugushev 已提交
1578
    command = [pip_name, 'install', 'pip != {}'.format(pip_current_version)]
1579
    result = script.run(*command, expect_error=True)
A
Albert Tugushev 已提交
1580
    new_command = [sys.executable, '-m', 'pip'] + command[1:]
A
Albert Tugushev 已提交
1581 1582 1583 1584 1585
    expected_message = (
        'To modify pip, please run the following command:\n{}'
        .format(' '.join(new_command))
    )
    assert expected_message in result.stderr, str(result)
1586 1587


A
Albert Tugushev 已提交
1588
@pytest.mark.network
1589
@pytest.mark.skipif("sys.platform != 'win32'")
A
Albert Tugushev 已提交
1590
def test_protect_pip_from_modification_via_deps_on_windows(script):
1591
    """
A
Albert Tugushev 已提交
1592
    Test ``pip install pkga`` raises an error on Windows
1593 1594
    if `pkga` implicitly tries to upgrade pip.
    """
A
Albert Tugushev 已提交
1595 1596 1597 1598
    pkga_wheel_path = create_basic_wheel_for_package(
        script,
        'pkga', '0.1',
        depends=['pip != {}'.format(pip_current_version)],
1599 1600
    )

A
Albert Tugushev 已提交
1601 1602 1603 1604
    # Make sure pip install pkga raises an error
    args = ['install', pkga_wheel_path]
    result = script.pip(*args, expect_error=True, use_module=False)
    new_command = [sys.executable, '-m', 'pip'] + args
A
Albert Tugushev 已提交
1605 1606 1607 1608 1609
    expected_message = (
        'To modify pip, please run the following command:\n{}'
        .format(' '.join(new_command))
    )
    assert expected_message in result.stderr, str(result)
1610 1611


A
Albert Tugushev 已提交
1612
@pytest.mark.network
1613
@pytest.mark.skipif("sys.platform != 'win32'")
A
Albert Tugushev 已提交
1614
def test_protect_pip_from_modification_via_sub_deps_on_windows(script):
1615
    """
A
Albert Tugushev 已提交
1616
    Test ``pip install pkga`` raises an error on Windows
A
Albert Tugushev 已提交
1617
    if sub-dependencies of `pkga` implicitly tries to upgrade pip.
1618
    """
A
Albert Tugushev 已提交
1619 1620 1621 1622 1623
    # Make a wheel for pkga which requires pkgb
    pkga_wheel_path = create_basic_wheel_for_package(
        script,
        'pkga', '0.1',
        depends=['pkgb'],
1624 1625
    )

A
Albert Tugushev 已提交
1626 1627 1628 1629 1630
    # Make a wheel for pkgb which requires pip
    pkgb_wheel_path = create_basic_wheel_for_package(
        script,
        'pkgb', '0.1',
        depends=['pip != {}'.format(pip_current_version)],
1631 1632
    )

A
Albert Tugushev 已提交
1633 1634 1635
    # Make sure pip install pkga raises an error
    args = [
        'install', pkga_wheel_path, '--find-links', pkgb_wheel_path.parent
1636
    ]
A
Albert Tugushev 已提交
1637 1638
    result = script.pip(*args, expect_error=True, use_module=False)
    new_command = [sys.executable, '-m', 'pip'] + args
A
Albert Tugushev 已提交
1639 1640 1641 1642 1643
    expected_message = (
        'To modify pip, please run the following command:\n{}'
        .format(' '.join(new_command))
    )
    assert expected_message in result.stderr, str(result)
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661


@pytest.mark.parametrize(
    'install_args, expected_message', [
        ([], 'Requirement already satisfied: pip in'),
        (['--upgrade'], 'Requirement already up-to-date: pip in'),
    ]
)
@pytest.mark.parametrize("use_module", [True, False])
def test_install_pip_does_not_modify_pip_when_satisfied(
        script, install_args, expected_message, use_module):
    """
    Test it doesn't upgrade the pip if it already satisfies the requirement.
    """
    result = script.pip_install_local(
        'pip', *install_args, use_module=use_module
    )
    assert expected_message in result.stdout, str(result)