test_install.py 60.0 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
10

A
Albert Tugushev 已提交
11
from pip import __version__ as pip_current_version
12
from pip._internal import pep425tags
13
from pip._internal.cli.status_codes import ERROR, SUCCESS
14
from pip._internal.models.index import PyPI, TestPyPI
15
from pip._internal.utils.misc import rmtree
P
Pradyun S. Gedam 已提交
16
from tests.lib import (
17 18 19 20 21 22 23 24 25 26
    _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 已提交
27
)
28
from tests.lib.filesystem import make_socket_file
M
Marcus Smith 已提交
29 30
from tests.lib.local_repos import local_checkout
from tests.lib.path import Path
31 32


B
Benoit Pierre 已提交
33 34 35 36
@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 已提交
37
        script.pip("uninstall", "-y", "setuptools")
B
Benoit Pierre 已提交
38
    elif variant == 'bad_setuptools':
39
        setuptools_mod = script.site_packages_path.joinpath("setuptools.py")
40
        with open(setuptools_mod, 'a') as f:
B
Benoit Pierre 已提交
41 42
            f.write('\nraise ImportError("toto")')
    else:
B
Benoit Pierre 已提交
43 44 45
        raise ValueError(variant)
    script.pip(
        command, '--no-index', '-f', common_wheels, '-f', data.packages,
46
        data.src.joinpath("pep518-3.0"),
B
Benoit Pierre 已提交
47
    )
48 49


50 51
def test_pep518_build_env_uses_same_pip(
        script, data, pip_src, common_wheels, deprecated_python):
52 53 54 55 56 57 58 59
    """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,
60
        data.src.joinpath("pep518-3.0"),
61
        expect_stderr=deprecated_python,
62 63 64
    )


B
Benoit Pierre 已提交
65 66 67
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')
68
    project_dir = data.src.joinpath("pep518_conflicting_requires")
B
Benoit Pierre 已提交
69 70 71 72 73 74
    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 '
75
         'setuptools>=40.8.0.' % path_to_url(project_dir)) in result.stderr
B
Benoit Pierre 已提交
76 77 78
    ), str(result)


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


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


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

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

111 112 113 114
    assert result.returncode == 0
    assert result.files_created


115
def test_pep518_with_user_pip(script, pip_src, data, common_wheels):
116 117 118 119 120 121 122 123 124
    """
    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 已提交
125 126
    script.pip("install", "--ignore-installed",
               "-f", common_wheels, "--user", pip_src)
127
    system_pip_dir = script.site_packages_path / 'pip'
128
    assert not system_pip_dir.exists()
129 130 131
    system_pip_dir.mkdir()
    with open(system_pip_dir / '__init__.py', 'w') as fp:
        fp.write('raise ImportError\n')
B
Benoit Pierre 已提交
132 133
    script.pip(
        'wheel', '--no-index', '-f', common_wheels, '-f', data.packages,
134
        data.src.joinpath("pep518-3.0"),
B
Benoit Pierre 已提交
135
    )
136 137


138 139 140 141 142
def test_pep518_with_extra_and_markers(script, data, common_wheels):
    script.pip(
        'wheel', '--no-index',
        '-f', common_wheels,
        '-f', data.find_links,
143
        data.src.joinpath("pep518_with_extra_and_markers-1.0"),
144 145 146
    )


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


157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
@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(
        'wheel', '--no-index', '-v',
        '-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),
173
    ) in result.stderr, str(result)
174 175


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

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


202 203 204 205 206 207 208 209 210 211 212 213 214
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
    """
215
    script.scratch_path.joinpath("blank.txt").write_text("\n")
216 217 218
    script.pip('install', '-r', 'blank.txt')


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

232 233 234 235
    # 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

236

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

249

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

263

264
def _test_install_editable_from_git(script, tmpdir):
265 266 267
    """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 已提交
268
    result = script.pip(*args)
269
    result.assert_installed('testpackage', with_files=['.git'])
270

271

272
def test_basic_install_editable_from_git(script, tmpdir):
273
    _test_install_editable_from_git(script, tmpdir)
274 275


276
def test_install_editable_from_git_autobuild_wheel(
277
        script, tmpdir, with_wheel):
278
    _test_install_editable_from_git(script, tmpdir)
279 280


X
Xavier Fernandez 已提交
281
@pytest.mark.network
282 283 284 285 286 287 288
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
    """
289
    to_install = data.packages.joinpath("pip-test-package-0.1.tar.gz")
290 291 292 293 294 295 296 297
    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(
298
            'git+https://github.com/pypa/pip-test-package.git',
299
            tmpdir.joinpath("cache"),
300 301 302 303
        ),
    )
    result.assert_installed('pip-test-package', with_files=['.git'])
    assert 'Found existing installation: pip-test-package 0.1' in result.stdout
304
    assert 'Uninstalling pip-test-package-' in result.stdout
305 306 307
    assert 'Successfully uninstalled pip-test-package' in result.stdout


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


332
@need_mercurial
333
def test_basic_install_editable_from_hg(script, tmpdir):
334 335 336
    """Test cloning from Mercurial."""
    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 已提交
337
    result = script.pip(*args)
338
    result.assert_installed('testpackage', with_files=['.hg'])
339

340

341
@need_mercurial
342
def test_vcs_url_final_slash_normalization(script, tmpdir):
343 344 345
    """
    Test that presence or absence of final slash in VCS URL is normalized.
    """
346 347
    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 已提交
348
    result = script.pip(*args)
349
    result.assert_installed('testpackage', with_files=['.hg'])
350

351

352
@need_bzr
353
def test_install_editable_from_bazaar(script, tmpdir):
354 355 356
    """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 已提交
357
    result = script.pip(*args)
358
    result.assert_installed('testpackage', with_files=['.bzr'])
F
Francesco 已提交
359

360

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

377

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

391

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

    # Compute relative install path to FSPkg from scratch path.
405
    full_rel_path = data.packages.joinpath('FSPkg') - script.scratch_path
406 407 408
    full_rel_url = (
        'file:' + full_rel_path.replace(os.path.sep, '/') + '#egg=FSPkg'
    )
409
    embedded_rel_path = script.scratch_path.joinpath(full_rel_path)
410 411 412

    # For each relative path, install as either editable or not using either
    # URLs with egg links or not.
413
    for req_path in (full_rel_path, full_rel_url, embedded_rel_path):
414 415 416 417 418
        # 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)
419 420
        script.pip('uninstall', '-y', 'fspkg')

421 422 423 424 425
        # 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')
426 427


428 429 430 431 432 433 434 435
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
436
    to_install = data.packages.joinpath("FSPkg")
437
    result = script.pip('install', '-qqq', to_install, expect_error=False)
438 439 440 441
    assert result.stdout == ""
    assert result.stderr == ""


442 443 444 445 446 447 448 449 450 451 452
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 已提交
453 454 455 456 457 458 459
    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)
460 461


462
def test_hashed_install_failure(script, tmpdir):
463 464 465 466 467 468 469
    """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 已提交
470 471
    with requirements_file('simple2==1.0 --hash=sha256:9336af72ca661e6336eb87b'
                           'c7de3e8844d853e3848c2b9bbd2e8bf01db88c2c\n',
472 473 474 475 476 477 478
                           tmpdir) as reqs_file:
        result = script.pip_install_local('-r',
                                          reqs_file.abspath,
                                          expect_error=True)
    assert len(result.files_created) == 0


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


494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
@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


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

526

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

    msg = result.stderr
    if deprecated_python:
        assert 'File "setup.py" not found. ' in msg
    else:
539
        assert msg.startswith('ERROR: File "setup.py" not found. ')
540 541 542 543 544 545 546 547 548
    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.
    """
549 550 551
    local_dir = script.scratch_path.joinpath('temp').mkdir()
    pyproject_path = local_dir.joinpath('pyproject.toml')
    pyproject_path.write_text('')
552 553 554 555 556 557 558 559

    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:
560
        assert msg.startswith('ERROR: File "setup.py" not found. ')
561
    assert 'A "pyproject.toml" file was found' in msg
562 563


564
@pytest.mark.skipif("sys.version_info >= (3,4)")
565
@pytest.mark.xfail
566
def test_install_argparse_shadowed(script):
567
    # When argparse is in the stdlib, we support installing it
J
Jakub Wilk 已提交
568
    # even though that's pretty useless because older packages did need to
569 570 571 572 573 574 575 576 577
    # 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 已提交
578
@pytest.mark.network
579
@pytest.mark.skipif("sys.version_info < (3,4)")
580
def test_upgrade_argparse_shadowed(script):
581 582 583 584 585 586 587
    # 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


588
def test_install_curdir(script, data):
589 590 591
    """
    Test installing current directory ('.').
    """
592
    run_from = data.packages.joinpath("FSPkg")
593 594 595 596
    # 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 已提交
597
    result = script.pip('install', curdir, cwd=run_from, expect_error=False)
D
Donald Stufft 已提交
598
    fspkg_folder = script.site_packages / 'fspkg'
599
    egg_info_folder = (
D
Donald Stufft 已提交
600
        script.site_packages / 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion
601
    )
602 603
    assert fspkg_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)
604

605

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


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


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


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


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


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


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


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


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


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

728

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

743

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

754
    # Test repeated call without --upgrade, no files should have changed
755 756 757
    result = script.pip_install_local(
        '-t', target_dir, "simple==1.0", expect_stderr=True,
    )
758
    assert not Path('scratch') / 'target' / 'simple' in result.files_updated
759 760

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

772
    # Test install and upgrade of single-module package
773 774 775
    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)
776

777 778 779
    result = script.pip_install_local('-t', target_dir, 'singlemodule==0.0.1',
                                      '--upgrade')
    assert singlemodule_py in result.files_updated, str(result)
780

781

782 783 784 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
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


842
def test_install_with_target_and_scripts_no_warning(script, with_wheel):
843 844 845 846 847 848 849
    """
    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()
850
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
851 852 853 854 855 856 857 858 859
        from setuptools import setup
        setup(name='pkga',
              version='0.1',
              py_modules=["pkga"],
              entry_points={
                  'console_scripts': ['pkga=pkga:main']
              }
        )
    """))
860
    pkga_path.joinpath("pkga.py").write_text(textwrap.dedent("""
861 862 863 864 865 866 867 868 869
        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)


870
def test_install_package_with_root(script, data):
871 872 873
    """
    Test installing a package using pip install --root
    """
D
Donald Stufft 已提交
874
    root_dir = script.scratch_path / 'root'
875 876 877 878 879 880 881 882 883
    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 已提交
884
    from distutils.util import change_root
885 886 887 888
    root_path = change_root(
        os.path.join(script.scratch, 'root'),
        normal_install_path
    )
M
Marcus Smith 已提交
889
    assert root_path in result.files_created, str(result)
890

891 892 893 894
    # Should show find-links location in output
    assert "Looking in indexes: " not in result.stdout
    assert "Looking in links: " in result.stdout

895

896 897 898 899 900 901 902
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,
903
        '--no-binary', 'simple', '--no-index', 'simple==1.0',
904 905
    )

906
    rel_prefix_path = script.scratch / 'prefix'
907
    install_path = (
908
        distutils.sysconfig.get_python_lib(prefix=rel_prefix_path) /
A
Anthony Sottile 已提交
909
        'simple-1.0-py{}.egg-info'.format(pyversion)
910 911 912 913
    )
    assert install_path in result.files_created, str(result)


914 915 916 917
def test_install_editable_with_prefix(script):
    # make a dummy project
    pkga_path = script.scratch_path / 'pkga'
    pkga_path.mkdir()
918
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
919 920 921 922 923
        from setuptools import setup
        setup(name='pkga',
              version='0.1')
    """))

924 925
    if hasattr(sys, "pypy_version_info"):
        site_packages = os.path.join(
A
Anthony Sottile 已提交
926
            'prefix', 'lib', 'python{}'.format(pyversion), 'site-packages')
927 928
    else:
        site_packages = distutils.sysconfig.get_python_lib(prefix='prefix')
929 930 931

    # make sure target path is in PYTHONPATH
    pythonpath = script.scratch_path / site_packages
932
    pythonpath.mkdir(parents=True)
933 934 935 936 937 938 939 940 941 942 943 944
    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)


945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
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
    )


960
def test_install_package_that_emits_unicode(script, data):
961
    """
962
    Install a package with a setup.py that emits UTF-8 output and then fails.
963

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

976

977 978
def test_install_package_with_utf8_setup(script, data):
    """Install a package with a setup.py that declares a utf-8 encoding."""
979
    to_install = data.packages.joinpath("SetupPyUTF8")
980 981
    script.pip('install', to_install)

982

983 984
def test_install_package_with_latin1_setup(script, data):
    """Install a package with a setup.py that declares a latin-1 encoding."""
985
    to_install = data.packages.joinpath("SetupPyLatin1")
986
    script.pip('install', to_install)
987

988

989
def test_url_req_case_mismatch_no_index(script, data):
990
    """
991 992 993
    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.
994

995
    tests/data/packages contains Upper-1.0.tar.gz and Upper-2.0.tar.gz
996 997
    'requiresupper' has install_requires = ['upper']
    """
998
    Upper = '/'.join((data.find_links, 'Upper-1.0.tar.gz'))
999 1000 1001
    result = script.pip(
        'install', '--no-index', '-f', data.find_links, Upper, 'requiresupper'
    )
1002

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


1010 1011 1012 1013 1014 1015
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.

1016
    tests/data/packages3 contains Dinner-1.0.tar.gz and Dinner-2.0.tar.gz
1017 1018 1019 1020 1021 1022 1023 1024
    '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.
    """
1025
    Dinner = '/'.join((data.find_links3, 'dinner', 'Dinner-1.0.tar.gz'))
1026 1027 1028 1029 1030 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
    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",
1062
        expect_stderr=True,
1063 1064 1065 1066 1067 1068 1069 1070
    )

    # 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)

1071 1072 1073 1074
    # Should show index-url location in output
    assert "Looking in indexes: " in result.stdout
    assert "Looking in links: " not in result.stdout

1075

1076
@pytest.mark.network
1077 1078 1079 1080 1081
def test_compiles_pyc(script):
    """
    Test installing with --compile on
    """
    del script.environ["PYTHONDONTWRITEBYTECODE"]
1082
    script.pip("install", "--compile", "--no-binary=:all:", "INITools==0.2")
1083 1084 1085 1086

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

    exists += glob.glob(
D
Donald Stufft 已提交
1091
        script.site_packages_path / "initools/__pycache__/__init__*.pyc"
1092 1093 1094 1095 1096
    )

    assert any(exists)


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

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

    exists += glob.glob(
D
Donald Stufft 已提交
1112
        script.site_packages_path / "initools/__pycache__/__init__*.pyc"
1113 1114 1115
    )

    assert not any(exists)
1116 1117 1118


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

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

1142 1143

def test_install_subprocess_output_handling(script, data):
1144
    args = ['install', data.src.joinpath('chattymodule')]
1145 1146 1147 1148 1149 1150 1151 1152 1153

    # 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.
1154 1155
    result = script.pip(*(args + ["--verbose"]), expect_stderr=True)
    assert 1 == result.stderr.count("HELLO FROM CHATTYMODULE egg_info")
1156 1157 1158 1159 1160 1161
    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)
1162
    assert 1 == result.stderr.count("I DIE, I DIE")
1163 1164 1165

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

1168 1169 1170

def test_install_log(script, data, tmpdir):
    # test that verbose logs go to "--log" file
1171
    f = tmpdir.joinpath("log.txt")
1172
    args = ['--log=%s' % f,
1173
            'install', data.src.joinpath('chattymodule')]
1174 1175 1176 1177 1178 1179
    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")

1180 1181

def test_install_topological_sort(script, data):
X
Xavier Fernandez 已提交
1182
    args = ['install', 'TopoRequires4', '--no-index', '-f', data.packages]
1183 1184 1185 1186
    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
1187 1188


1189 1190
def test_install_wheel_broken(script, with_wheel):
    res = script.pip_install_local('wheelbroken', expect_stderr=True)
1191
    assert "Successfully installed wheelbroken-0.1" in str(res), str(res)
1192 1193


1194 1195
def test_cleanup_after_failed_wheel(script, with_wheel):
    res = script.pip_install_local('wheelbrokenafter', expect_stderr=True)
1196 1197
    # One of the effects of not cleaning up is broken scripts:
    script_py = script.bin_path / "script.py"
1198
    assert script_py.exists(), script_py
1199 1200 1201 1202 1203 1204
    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)


1205
def test_install_builds_wheels(script, data, with_wheel):
1206 1207 1208 1209 1210 1211
    # 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')
1212 1213 1214
    # NB This incidentally tests a local tree + tarball inputs
    # see test_install_editable_from_git_autobuild_wheel for editable
    # vcs coverage.
1215
    to_install = data.packages.joinpath('requires_wheelbroken_upper')
1216
    res = script.pip(
1217
        'install', '--no-index', '-f', data.find_links,
1218 1219 1220 1221 1222 1223
        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 = []
1224
    for top, dirs, files in os.walk(wheels_cache):
1225 1226
        wheels.extend(files)
    # and built wheels for upper and wheelbroken
P
Paul Moore 已提交
1227 1228
    assert "Building wheel for upper" in str(res), str(res)
    assert "Building wheel for wheelb" in str(res), str(res)
T
Thomas Kluyver 已提交
1229
    # Wheels are built for local directories, but not cached.
P
Paul Moore 已提交
1230
    assert "Building wheel for requir" in str(res), str(res)
1231 1232 1233 1234 1235
    # 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 已提交
1236 1237
    # Wheels are built for local directories, but not cached.
    assert "Running setup.py install for requir" not in str(res), str(res)
1238 1239
    # wheelbroken has to run install
    assert "Running setup.py install for wheelb" in str(res), str(res)
1240 1241
    # We want to make sure we used the correct implementation tag
    assert wheels == [
A
Anthony Sottile 已提交
1242
        "Upper-2.0-{}-none-any.whl".format(pep425tags.implementation_tag),
1243
    ]
1244 1245


1246
def test_install_no_binary_disables_building_wheels(script, data, with_wheel):
1247
    to_install = data.packages.joinpath('requires_wheelbroken_upper')
1248 1249 1250 1251 1252 1253 1254 1255
    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 已提交
1256
    assert "Building wheel for wheelb" in str(res), str(res)
1257
    # Wheels are built for local directories, but not cached across runs
P
Paul Moore 已提交
1258
    assert "Building wheel for requir" in str(res), str(res)
1259
    # Don't build wheel for upper which was blacklisted
P
Paul Moore 已提交
1260
    assert "Building wheel for upper" not in str(res), str(res)
1261
    # Wheels are built for local directories, but not cached across runs
1262
    assert "Running setup.py install for requir" not in str(res), str(res)
1263
    # And these two fell back to sdist based installed.
1264 1265
    assert "Running setup.py install for wheelb" in str(res), str(res)
    assert "Running setup.py install for upper" in str(res), str(res)
1266 1267


1268
def test_install_no_binary_disables_cached_wheels(script, data, with_wheel):
1269 1270
    # Seed the cache
    script.pip(
1271
        'install', '--no-index', '-f', data.find_links,
1272 1273 1274 1275 1276 1277 1278
        '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 已提交
1279
    assert "Building wheel for upper" not in str(res), str(res)
1280 1281
    # Must have used source, not a cached wheel to install upper.
    assert "Running setup.py install for upper" in str(res), str(res)
1282 1283 1284


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


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
1317 1318


1319
def test_double_install(script):
1320 1321 1322
    """
    Test double install passing with two same version requirements
    """
1323 1324
    result = script.pip('install', 'pip', 'pip',
                        expect_error=False)
1325 1326 1327 1328
    msg = "Double requirement given: pip (already in pip, name='pip')"
    assert msg not in result.stderr


1329
def test_double_install_fail(script):
1330 1331 1332 1333 1334 1335 1336
    """
    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 已提交
1337 1338


1339 1340 1341
def _get_expected_error_text():
    return (
        "Package 'pkga' requires a different Python: {} not in '<1.0'"
1342
    ).format('.'.join(map(str, sys.version_info[:3])))
1343 1344


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


1358
def test_install_incompatible_python_requires_editable(script):
1359
    script.scratch_path.joinpath("pkga").mkdir()
X
Xavier Fernandez 已提交
1360
    pkga_path = script.scratch_path / 'pkga'
1361
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
X
Xavier Fernandez 已提交
1362 1363 1364 1365 1366 1367 1368
        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)
1369
    assert _get_expected_error_text() in result.stderr, str(result)
X
Xavier Fernandez 已提交
1370 1371


1372
def test_install_incompatible_python_requires_wheel(script, with_wheel):
1373
    script.scratch_path.joinpath("pkga").mkdir()
X
Xavier Fernandez 已提交
1374
    pkga_path = script.scratch_path / 'pkga'
1375
    pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
X
Xavier Fernandez 已提交
1376 1377 1378 1379 1380 1381 1382 1383 1384
        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)
1385
    assert _get_expected_error_text() in result.stderr, str(result)
X
Xavier Fernandez 已提交
1386 1387


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


1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
@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'
        ],
    )
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
    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)
1449 1450 1451 1452


def test_installing_scripts_outside_path_prints_warning(script):
    result = script.pip_install_local(
C
Chris Hunt 已提交
1453
        "--prefix", script.scratch_path, "script_wheel1"
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471
    )
    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
1472 1473 1474 1475 1476 1477 1478


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.
    """
1479
    to_install = data.packages.joinpath("FSPkg")
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
    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 已提交
1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511


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(
1512
        'install', '--no-index', pkgB_path, allow_stderr_error=True,
P
Pradyun Gedam 已提交
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
    )
    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)
1537 1538 1539 1540


def test_target_install_ignores_distutils_config_install_prefix(script):
    prefix = script.scratch_path / 'prefix'
B
Benoit Pierre 已提交
1541 1542 1543
    distutils_config = Path(os.path.expanduser('~'),
                            'pydistutils.cfg' if sys.platform == 'win32'
                            else '.pydistutils.cfg')
1544
    distutils_config.write_text(textwrap.dedent(
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
        '''
        [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)
1556 1557


A
Albert Tugushev 已提交
1558
@pytest.mark.network
1559
@pytest.mark.skipif("sys.platform != 'win32'")
A
Albert Tugushev 已提交
1560 1561 1562 1563 1564 1565 1566 1567 1568
@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):
1569
    """
A
Albert Tugushev 已提交
1570 1571
    Test that pip modification command using ``pip install ...``
    raises an error on Windows.
1572
    """
A
Albert Tugushev 已提交
1573
    command = [pip_name, 'install', 'pip != {}'.format(pip_current_version)]
1574
    result = script.run(*command, expect_error=True)
A
Albert Tugushev 已提交
1575
    new_command = [sys.executable, '-m', 'pip'] + command[1:]
A
Albert Tugushev 已提交
1576 1577 1578 1579 1580
    expected_message = (
        'To modify pip, please run the following command:\n{}'
        .format(' '.join(new_command))
    )
    assert expected_message in result.stderr, str(result)
1581 1582


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

A
Albert Tugushev 已提交
1596 1597 1598 1599
    # 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 已提交
1600 1601 1602 1603 1604
    expected_message = (
        'To modify pip, please run the following command:\n{}'
        .format(' '.join(new_command))
    )
    assert expected_message in result.stderr, str(result)
1605 1606


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

A
Albert Tugushev 已提交
1621 1622 1623 1624 1625
    # 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)],
1626 1627
    )

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


@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)