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

8
import pytest
9

10
from pip._internal import pep425tags
11
from pip._internal.cli.status_codes import ERROR, SUCCESS
12
from pip._internal.models.index import PyPI, TestPyPI
13
from pip._internal.utils.misc import rmtree
P
Pradyun S. Gedam 已提交
14
from tests.lib import (
B
Benoit Pierre 已提交
15 16 17
    _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 已提交
18
)
M
Marcus Smith 已提交
19 20
from tests.lib.local_repos import local_checkout
from tests.lib.path import Path
21 22


B
Benoit Pierre 已提交
23 24 25 26
@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 已提交
27
        script.pip("uninstall", "-y", "setuptools")
B
Benoit Pierre 已提交
28
    elif variant == 'bad_setuptools':
29 30
        setuptools_mod = script.site_packages_path.join("setuptools.py")
        with open(setuptools_mod, 'a') as f:
B
Benoit Pierre 已提交
31 32
            f.write('\nraise ImportError("toto")')
    else:
B
Benoit Pierre 已提交
33 34 35
        raise ValueError(variant)
    script.pip(
        command, '--no-index', '-f', common_wheels, '-f', data.packages,
36
        data.src.join("pep518-3.0"),
B
Benoit Pierre 已提交
37
    )
38 39


40 41
def test_pep518_build_env_uses_same_pip(
        script, data, pip_src, common_wheels, deprecated_python):
42 43 44 45 46 47 48 49 50
    """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,
        data.src.join("pep518-3.0"),
51
        expect_stderr=deprecated_python,
52 53 54
    )


B
Benoit Pierre 已提交
55 56 57 58 59 60 61 62 63 64
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')
    project_dir = data.src.join("pep518_conflicting_requires")
    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 '
65
         'setuptools>=40.8.0.' % path_to_url(project_dir)) in result.stderr
B
Benoit Pierre 已提交
66 67 68
    ), str(result)


69
def test_pep518_refuses_invalid_requires(script, data, common_wheels):
70
    result = script.pip(
71 72
        'install', '-f', common_wheels,
        data.src.join("pep518_invalid_requires"),
73 74 75 76 77 78
        expect_error=True
    )
    assert result.returncode == 1
    assert "does not comply with PEP 518" in result.stderr


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


89
def test_pep518_allows_missing_requires(script, data, common_wheels):
90 91 92 93 94
    result = script.pip(
        'install', '-f', common_wheels,
        data.src.join("pep518_missing_requires"),
        expect_stderr=True
    )
95 96
    # Make sure we don't warn when this occurs.
    assert "does not comply with PEP 518" not in result.stderr
97 98 99 100

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

101 102 103 104
    assert result.returncode == 0
    assert result.files_created


105
def test_pep518_with_user_pip(script, pip_src, data, common_wheels):
106 107 108 109 110 111 112 113 114
    """
    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 已提交
115 116
    script.pip("install", "--ignore-installed",
               "-f", common_wheels, "--user", pip_src)
117 118 119 120 121
    system_pip_dir = script.site_packages_path / 'pip'
    system_pip_dir.rmtree()
    system_pip_dir.mkdir()
    with open(system_pip_dir / '__init__.py', 'w') as fp:
        fp.write('raise ImportError\n')
B
Benoit Pierre 已提交
122 123
    script.pip(
        'wheel', '--no-index', '-f', common_wheels, '-f', data.packages,
124
        data.src.join("pep518-3.0"),
B
Benoit Pierre 已提交
125
    )
126 127


128 129 130 131 132 133 134 135 136
def test_pep518_with_extra_and_markers(script, data, common_wheels):
    script.pip(
        'wheel', '--no-index',
        '-f', common_wheels,
        '-f', data.find_links,
        data.src.join("pep518_with_extra_and_markers-1.0"),
    )


137 138 139 140 141 142 143 144 145 146
def test_pep518_with_namespace_package(script, data, common_wheels):
    script.pip(
        'wheel', '--no-index',
        '-f', common_wheels,
        '-f', data.find_links,
        data.src.join("pep518_with_namespace_package-1.0"),
        use_module=True,
    )


147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
@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),
    ) in result.stdout, str(result)


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

P
Paul Nasrat 已提交
180
    args = ['pip%s' % pyversion]
181
    args.extend(['install', 'INITools==0.2'])
182
    args.extend(['-f', data.packages])
183
    result = script.run(*args, **kwargs)
184 185 186
    egg_info_folder = (
        script.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion
    )
D
Donald Stufft 已提交
187
    initools_folder = script.site_packages / 'initools'
188 189 190 191
    assert egg_info_folder in result.files_created, str(result)
    assert initools_folder in result.files_created, str(result)


192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
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
    """
    script.scratch_path.join("blank.txt").write("\n")
    script.pip('install', '-r', 'blank.txt')


209
@pytest.mark.network
210
def test_basic_install_from_pypi(script):
211 212 213
    """
    Test installing a package from PyPI.
    """
D
Donald Stufft 已提交
214
    result = script.pip('install', '-vvv', 'INITools==0.2')
215 216 217
    egg_info_folder = (
        script.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion
    )
D
Donald Stufft 已提交
218
    initools_folder = script.site_packages / 'initools'
219 220
    assert egg_info_folder in result.files_created, str(result)
    assert initools_folder in result.files_created, str(result)
221

222 223 224 225
    # 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

226

227
def test_basic_editable_install(script):
228 229 230
    """
    Test editable installation.
    """
D
Donald Stufft 已提交
231
    result = script.pip('install', '-e', 'INITools==0.2', expect_error=True)
232 233
    assert (
        "INITools==0.2 should either be a path to a local project or a VCS url"
234
        in result.stderr
235
    )
236 237
    assert not result.files_created
    assert not result.files_updated
238

239

X
Xavier Fernandez 已提交
240
@pytest.mark.svn
241
def test_basic_install_editable_from_svn(script):
242 243 244
    """
    Test checking out from svn.
    """
245 246
    checkout_path = _create_test_package(script)
    repo_url = _create_svn_repo(script, checkout_path)
247 248
    result = script.pip(
        'install',
249
        '-e', 'svn+' + repo_url + '#egg=version-pkg'
250
    )
251
    result.assert_installed('version-pkg', with_files=['.svn'])
252

253

254
def _test_install_editable_from_git(script, tmpdir):
255 256 257
    """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)]
D
Donald Stufft 已提交
258
    result = script.pip(*args, **{"expect_error": True})
259
    result.assert_installed('testpackage', with_files=['.git'])
260

261

262
def test_basic_install_editable_from_git(script, tmpdir):
263
    _test_install_editable_from_git(script, tmpdir)
264 265


266
def test_install_editable_from_git_autobuild_wheel(
267
        script, tmpdir, with_wheel):
268
    _test_install_editable_from_git(script, tmpdir)
269 270


X
Xavier Fernandez 已提交
271
@pytest.mark.network
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
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
    """
    to_install = data.packages.join("pip-test-package-0.1.tar.gz")
    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(
288
            'git+https://github.com/pypa/pip-test-package.git',
289 290 291 292 293
            tmpdir.join("cache"),
        ),
    )
    result.assert_installed('pip-test-package', with_files=['.git'])
    assert 'Found existing installation: pip-test-package 0.1' in result.stdout
294
    assert 'Uninstalling pip-test-package-' in result.stdout
295 296 297
    assert 'Successfully uninstalled pip-test-package' in result.stdout


298 299 300 301 302 303 304 305
def test_install_editable_uninstalls_existing_from_path(script, data):
    """
    Test that installing an editable uninstalls a previously installed
    non-editable version from path
    """
    to_install = data.src.join('simplewheel-1.0')
    result = script.pip_install_local(to_install)
    assert 'Successfully installed simplewheel' in result.stdout
306 307
    simple_folder = script.site_packages / 'simplewheel'
    result.assert_installed('simplewheel', editable=False)
308 309 310 311 312 313 314 315 316 317 318 319 320 321
    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)


322
@need_mercurial
323
def test_basic_install_editable_from_hg(script, tmpdir):
324 325 326 327 328
    """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)]
    result = script.pip(*args, **{"expect_error": True})
    result.assert_installed('testpackage', with_files=['.hg'])
329

330

331
@need_mercurial
332
def test_vcs_url_final_slash_normalization(script, tmpdir):
333 334 335
    """
    Test that presence or absence of final slash in VCS URL is normalized.
    """
336 337 338 339
    pkg_path = _create_test_package(script, name='testpackage', vcs='hg')
    args = ['install', '-e', 'hg+%s/#egg=testpackage' % path_to_url(pkg_path)]
    result = script.pip(*args, **{"expect_error": True})
    result.assert_installed('testpackage', with_files=['.hg'])
340

341

342
@need_bzr
343
def test_install_editable_from_bazaar(script, tmpdir):
344 345 346 347 348
    """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)]
    result = script.pip(*args, **{"expect_error": True})
    result.assert_installed('testpackage', with_files=['.bzr'])
F
Francesco 已提交
349

350

351
@pytest.mark.network
352
@need_bzr
353
def test_vcs_url_urlquote_normalization(script, tmpdir):
354 355 356
    """
    Test that urlquoted characters are normalized for repo URL comparison.
    """
357
    script.pip(
358 359 360 361 362 363 364 365
        'install', '-e',
        '%s/#egg=django-wikiapp' %
        local_checkout(
            'bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp'
            '/release-0.1',
            tmpdir.join("cache"),
        ),
    )
366

367

368
def test_basic_install_from_local_directory(script, data):
369 370 371
    """
    Test installing from a local directory.
    """
372
    to_install = data.packages.join("FSPkg")
D
Donald Stufft 已提交
373
    result = script.pip('install', to_install, expect_error=False)
D
Donald Stufft 已提交
374
    fspkg_folder = script.site_packages / 'fspkg'
375
    egg_info_folder = (
D
Donald Stufft 已提交
376
        script.site_packages / 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion
377
    )
378 379
    assert fspkg_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)
380

381

382
def test_basic_install_relative_directory(script, data):
383
    """
384
    Test installing a requirement using a relative path.
385
    """
386
    egg_info_file = (
387 388 389 390 391
        script.site_packages / 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion
    )
    egg_link_file = (
        script.site_packages / 'FSPkg.egg-link'
    )
392 393 394 395
    package_folder = script.site_packages / 'fspkg'

    # Compute relative install path to FSPkg from scratch path.
    full_rel_path = data.packages.join('FSPkg') - script.scratch_path
396 397 398
    full_rel_url = (
        'file:' + full_rel_path.replace(os.path.sep, '/') + '#egg=FSPkg'
    )
399 400 401 402
    embedded_rel_path = script.scratch_path.join(full_rel_path)

    # For each relative path, install as either editable or not using either
    # URLs with egg links or not.
403
    for req_path in (full_rel_path, full_rel_url, embedded_rel_path):
404 405 406 407 408
        # 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)
409 410
        script.pip('uninstall', '-y', 'fspkg')

411 412 413 414 415
        # 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')
416 417


418 419 420 421 422 423 424 425 426
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
    to_install = data.packages.join("FSPkg")
427
    result = script.pip('install', '-qqq', to_install, expect_error=False)
428 429 430 431
    assert result.stdout == ""
    assert result.stderr == ""


432 433 434 435 436 437 438 439 440 441 442
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 已提交
443 444 445 446 447 448 449
    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)
450 451


452
def test_hashed_install_failure(script, tmpdir):
453 454 455 456 457 458 459
    """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 已提交
460 461
    with requirements_file('simple2==1.0 --hash=sha256:9336af72ca661e6336eb87b'
                           'c7de3e8844d853e3848c2b9bbd2e8bf01db88c2c\n',
462 463 464 465 466 467 468
                           tmpdir) as reqs_file:
        result = script.pip_install_local('-r',
                                          reqs_file.abspath,
                                          expect_error=True)
    assert len(result.files_created) == 0


469 470
def test_install_from_local_directory_with_symlinks_to_directories(
        script, data):
471 472 473 474 475
    """
    Test installing from a local directory containing symlinks to directories.
    """
    to_install = data.packages.join("symlinks")
    result = script.pip('install', to_install, expect_error=False)
D
Donald Stufft 已提交
476
    pkg_folder = script.site_packages / 'symlinks'
477
    egg_info_folder = (
D
Donald Stufft 已提交
478
        script.site_packages / 'symlinks-0.1.dev0-py%s.egg-info' % pyversion
479
    )
480 481 482 483
    assert pkg_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)


484
def test_install_from_local_directory_with_no_setup_py(script, data):
485 486 487
    """
    Test installing from a local directory with no 'setup.py'.
    """
488
    result = script.pip('install', data.root, expect_error=True)
489
    assert not result.files_created
490 491
    assert "is not installable." in result.stderr
    assert "Neither 'setup.py' nor 'pyproject.toml' found." in result.stderr
492

493

494 495
def test_editable_install__local_dir_no_setup_py(
        script, data, deprecated_python):
496
    """
497
    Test installing in editable mode from a local directory with no setup.py.
498
    """
499
    result = script.pip('install', '-e', data.root, expect_error=True)
500
    assert not result.files_created
501 502 503 504 505

    msg = result.stderr
    if deprecated_python:
        assert 'File "setup.py" not found. ' in msg
    else:
506
        assert msg.startswith('ERROR: File "setup.py" not found. ')
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
    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.
    """
    local_dir = script.scratch_path.join('temp').mkdir()
    pyproject_path = local_dir.join('pyproject.toml')
    pyproject_path.write('')

    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:
527
        assert msg.startswith('ERROR: File "setup.py" not found. ')
528
    assert 'A "pyproject.toml" file was found' in msg
529 530


531
@pytest.mark.skipif("sys.version_info >= (3,4)")
532
@pytest.mark.xfail
533
def test_install_argparse_shadowed(script):
534
    # When argparse is in the stdlib, we support installing it
J
Jakub Wilk 已提交
535
    # even though that's pretty useless because older packages did need to
536 537 538 539 540 541 542 543 544
    # 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 已提交
545
@pytest.mark.network
546
@pytest.mark.skipif("sys.version_info < (3,4)")
547
def test_upgrade_argparse_shadowed(script):
548 549 550 551 552 553 554
    # 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


555
def test_install_curdir(script, data):
556 557 558
    """
    Test installing current directory ('.').
    """
559
    run_from = data.packages.join("FSPkg")
560 561 562 563
    # 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 已提交
564
    result = script.pip('install', curdir, cwd=run_from, expect_error=False)
D
Donald Stufft 已提交
565
    fspkg_folder = script.site_packages / 'fspkg'
566
    egg_info_folder = (
D
Donald Stufft 已提交
567
        script.site_packages / 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion
568
    )
569 570
    assert fspkg_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)
571

572

573
def test_install_pardir(script, data):
574 575 576
    """
    Test installing parent directory ('..').
    """
577
    run_from = data.packages.join("FSPkg", "fspkg")
D
Donald Stufft 已提交
578
    result = script.pip('install', pardir, cwd=run_from, expect_error=False)
D
Donald Stufft 已提交
579
    fspkg_folder = script.site_packages / 'fspkg'
580
    egg_info_folder = (
D
Donald Stufft 已提交
581
        script.site_packages / 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion
582
    )
583 584
    assert fspkg_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)
585 586


587
@pytest.mark.network
588
def test_install_global_option(script):
589
    """
590 591
    Test using global distutils options.
    (In particular those that disable the actual install action)
592
    """
593 594
    result = script.pip(
        'install', '--global-option=--version', "INITools==0.1",
595
        expect_stderr=True)
596
    assert '0.1\n' in result.stdout
597 598


599
def test_install_with_hacked_egg_info(script, data):
600 601 602
    """
    test installing a package which defines its own egg_info class
    """
603
    run_from = data.packages.join("HackedEggInfo")
D
Donald Stufft 已提交
604
    result = script.pip('install', '.', cwd=run_from)
605
    assert 'Successfully installed hackedegginfo-0.0.0\n' in result.stdout
606 607


608
@pytest.mark.network
609
def test_install_using_install_option_and_editable(script, tmpdir):
610 611 612
    """
    Test installing a tool using -e and --install-option
    """
H
Hugo Lopes Tavares 已提交
613
    folder = 'script_folder'
D
Donald Stufft 已提交
614
    script.scratch_path.join(folder).mkdir()
615
    url = 'git+git://github.com/pypa/pip-test-package'
616
    result = script.pip(
617
        'install', '-e', '%s#egg=pip-test-package' %
618
        local_checkout(url, tmpdir.join("cache")),
619 620
        '--install-option=--script-dir=%s' % folder,
        expect_stderr=True)
621 622 623
    script_file = (
        script.venv / 'src' / 'pip-test-package' /
        folder / 'pip-test-package' + script.exe
624
    )
625
    assert script_file in result.files_created
626 627


628
@pytest.mark.network
629
@need_mercurial
630
def test_install_global_option_using_editable(script, tmpdir):
631 632 633
    """
    Test using global distutils options, but in an editable installation
    """
C
Carl Meyer 已提交
634
    url = 'hg+http://bitbucket.org/runeh/anyjson'
635 636
    result = script.pip(
        'install', '--global-option=--version', '-e',
637 638
        '%s@0.2.5#egg=anyjson' % local_checkout(url, tmpdir.join("cache")),
        expect_stderr=True)
639
    assert 'Successfully installed anyjson' in result.stdout
640 641


642
@pytest.mark.network
643
def test_install_package_with_same_name_in_curdir(script):
644 645 646
    """
    Test installing a package with the same name of a local folder
    """
D
Donald Stufft 已提交
647 648 649
    script.scratch_path.join("mock==0.6").mkdir()
    result = script.pip('install', 'mock==0.6')
    egg_folder = script.site_packages / 'mock-0.6.0-py%s.egg-info' % pyversion
650 651 652 653 654 655 656 657 658
    assert egg_folder in result.files_created, str(result)


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


659
def test_install_folder_using_dot_slash(script):
660 661 662
    """
    Test installing a folder using pip install ./foldername
    """
D
Donald Stufft 已提交
663
    script.scratch_path.join("mock").mkdir()
D
Donald Stufft 已提交
664
    pkg_path = script.scratch_path / 'mock'
D
Donald Stufft 已提交
665 666 667
    pkg_path.join("setup.py").write(mock100_setup_py)
    result = script.pip('install', './mock')
    egg_folder = script.site_packages / 'mock-100.1-py%s.egg-info' % pyversion
668 669 670
    assert egg_folder in result.files_created, str(result)


671
def test_install_folder_using_slash_in_the_end(script):
672 673
    r"""
    Test installing a folder using pip install foldername/ or foldername\
674
    """
D
Donald Stufft 已提交
675
    script.scratch_path.join("mock").mkdir()
D
Donald Stufft 已提交
676
    pkg_path = script.scratch_path / 'mock'
D
Donald Stufft 已提交
677 678 679
    pkg_path.join("setup.py").write(mock100_setup_py)
    result = script.pip('install', 'mock' + os.path.sep)
    egg_folder = script.site_packages / 'mock-100.1-py%s.egg-info' % pyversion
680 681 682
    assert egg_folder in result.files_created, str(result)


683
def test_install_folder_using_relative_path(script):
684 685 686
    """
    Test installing a folder using pip install folder1/folder2
    """
D
Donald Stufft 已提交
687 688
    script.scratch_path.join("initools").mkdir()
    script.scratch_path.join("initools", "mock").mkdir()
D
Donald Stufft 已提交
689
    pkg_path = script.scratch_path / 'initools' / 'mock'
D
Donald Stufft 已提交
690
    pkg_path.join("setup.py").write(mock100_setup_py)
D
Donald Stufft 已提交
691
    result = script.pip('install', Path('initools') / 'mock')
D
Donald Stufft 已提交
692
    egg_folder = script.site_packages / 'mock-100.1-py%s.egg-info' % pyversion
693
    assert egg_folder in result.files_created, str(result)
694

695

696
@pytest.mark.network
697
def test_install_package_which_contains_dev_in_name(script):
698
    """
J
Jon Dufresne 已提交
699
    Test installing package from PyPI which contains 'dev' in name
700
    """
D
Donald Stufft 已提交
701
    result = script.pip('install', 'django-devserver==0.0.4')
D
Donald Stufft 已提交
702
    devserver_folder = script.site_packages / 'devserver'
703
    egg_info_folder = (
D
Donald Stufft 已提交
704 705
        script.site_packages / 'django_devserver-0.0.4-py%s.egg-info' %
        pyversion
706
    )
707 708
    assert devserver_folder in result.files_created, str(result.stdout)
    assert egg_info_folder in result.files_created, str(result)
709

710

711
def test_install_package_with_target(script):
712 713 714
    """
    Test installing a package using pip install --target
    """
D
Donald Stufft 已提交
715
    target_dir = script.scratch_path / 'target'
716 717
    result = script.pip_install_local('-t', target_dir, "simple==1.0")
    assert Path('scratch') / 'target' / 'simple' in result.files_created, (
718 719
        str(result)
    )
720

721
    # Test repeated call without --upgrade, no files should have changed
722 723 724
    result = script.pip_install_local(
        '-t', target_dir, "simple==1.0", expect_stderr=True,
    )
725
    assert not Path('scratch') / 'target' / 'simple' in result.files_updated
726 727

    # Test upgrade call, check that new version is installed
728 729 730
    result = script.pip_install_local('--upgrade', '-t',
                                      target_dir, "simple==2.0")
    assert Path('scratch') / 'target' / 'simple' in result.files_updated, (
731 732
        str(result)
    )
J
Jon Wayne Parrott 已提交
733
    egg_folder = (
734
        Path('scratch') / 'target' / 'simple-2.0-py%s.egg-info' % pyversion)
J
Jon Wayne Parrott 已提交
735
    assert egg_folder in result.files_created, (
736 737 738
        str(result)
    )

739
    # Test install and upgrade of single-module package
740 741 742
    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)
743

744 745 746
    result = script.pip_install_local('-t', target_dir, 'singlemodule==0.0.1',
                                      '--upgrade')
    assert singlemodule_py in result.files_updated, str(result)
747

748

749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 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
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


809
def test_install_with_target_and_scripts_no_warning(script, with_wheel):
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
    """
    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()
    pkga_path.join("setup.py").write(textwrap.dedent("""
        from setuptools import setup
        setup(name='pkga',
              version='0.1',
              py_modules=["pkga"],
              entry_points={
                  'console_scripts': ['pkga=pkga:main']
              }
        )
    """))
    pkga_path.join("pkga.py").write(textwrap.dedent("""
        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)


837
def test_install_package_with_root(script, data):
838 839 840
    """
    Test installing a package using pip install --root
    """
D
Donald Stufft 已提交
841
    root_dir = script.scratch_path / 'root'
842 843 844 845 846 847 848 849 850
    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 已提交
851
    from distutils.util import change_root
852 853 854 855
    root_path = change_root(
        os.path.join(script.scratch, 'root'),
        normal_install_path
    )
M
Marcus Smith 已提交
856
    assert root_path in result.files_created, str(result)
857

858 859 860 861
    # Should show find-links location in output
    assert "Looking in indexes: " not in result.stdout
    assert "Looking in links: " in result.stdout

862

863 864 865 866 867 868 869
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,
870
        '--no-binary', 'simple', '--no-index', 'simple==1.0',
871 872
    )

873
    rel_prefix_path = script.scratch / 'prefix'
874
    install_path = (
875
        distutils.sysconfig.get_python_lib(prefix=rel_prefix_path) /
A
Anthony Sottile 已提交
876
        'simple-1.0-py{}.egg-info'.format(pyversion)
877 878 879 880
    )
    assert install_path in result.files_created, str(result)


881 882 883 884 885 886 887 888 889 890
def test_install_editable_with_prefix(script):
    # make a dummy project
    pkga_path = script.scratch_path / 'pkga'
    pkga_path.mkdir()
    pkga_path.join("setup.py").write(textwrap.dedent("""
        from setuptools import setup
        setup(name='pkga',
              version='0.1')
    """))

891 892
    if hasattr(sys, "pypy_version_info"):
        site_packages = os.path.join(
A
Anthony Sottile 已提交
893
            'prefix', 'lib', 'python{}'.format(pyversion), 'site-packages')
894 895
    else:
        site_packages = distutils.sysconfig.get_python_lib(prefix='prefix')
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911

    # make sure target path is in PYTHONPATH
    pythonpath = script.scratch_path / site_packages
    pythonpath.makedirs()
    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)


912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
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
    )


927 928
# skip on win/py3 for now, see issue #782
@pytest.mark.skipif("sys.platform == 'win32' and sys.version_info >= (3,)")
929
def test_install_package_that_emits_unicode(script, data):
930
    """
931
    Install a package with a setup.py that emits UTF-8 output and then fails.
932

933
    Refs https://github.com/pypa/pip/issues/326
934
    """
935
    to_install = data.packages.join("BrokenEmitsUTF8")
936 937 938 939 940 941
    result = script.pip(
        'install', to_install, expect_error=True, expect_temp=True, quiet=True,
    )
    assert (
        'FakeError: this package designed to fail on install' in result.stdout
    )
942
    assert 'UnicodeDecodeError' not in result.stdout
943

944

945 946 947 948 949
def test_install_package_with_utf8_setup(script, data):
    """Install a package with a setup.py that declares a utf-8 encoding."""
    to_install = data.packages.join("SetupPyUTF8")
    script.pip('install', to_install)

950

951 952 953 954
def test_install_package_with_latin1_setup(script, data):
    """Install a package with a setup.py that declares a latin-1 encoding."""
    to_install = data.packages.join("SetupPyLatin1")
    script.pip('install', to_install)
955

956

957
def test_url_req_case_mismatch_no_index(script, data):
958
    """
959 960 961
    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.
962

963
    tests/data/packages contains Upper-1.0.tar.gz and Upper-2.0.tar.gz
964 965
    'requiresupper' has install_requires = ['upper']
    """
966
    Upper = '/'.join((data.find_links, 'Upper-1.0.tar.gz'))
967 968 969
    result = script.pip(
        'install', '--no-index', '-f', data.find_links, Upper, 'requiresupper'
    )
970

971
    # only Upper-1.0.tar.gz should get installed.
D
Donald Stufft 已提交
972
    egg_folder = script.site_packages / 'Upper-1.0-py%s.egg-info' % pyversion
973
    assert egg_folder in result.files_created, str(result)
D
Donald Stufft 已提交
974
    egg_folder = script.site_packages / 'Upper-2.0-py%s.egg-info' % pyversion
975
    assert egg_folder not in result.files_created, str(result)
976 977


978 979 980 981 982 983
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.

984
    tests/data/packages3 contains Dinner-1.0.tar.gz and Dinner-2.0.tar.gz
985 986 987 988 989 990 991 992
    '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.
    """
993
    Dinner = '/'.join((data.find_links3, 'dinner', 'Dinner-1.0.tar.gz'))
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
    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",
1030
        expect_stderr=True,
1031 1032 1033 1034 1035 1036 1037 1038
    )

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

1039 1040 1041 1042
    # Should show index-url location in output
    assert "Looking in indexes: " in result.stdout
    assert "Looking in links: " not in result.stdout

1043

1044
@pytest.mark.network
1045 1046 1047 1048 1049
def test_compiles_pyc(script):
    """
    Test installing with --compile on
    """
    del script.environ["PYTHONDONTWRITEBYTECODE"]
1050
    script.pip("install", "--compile", "--no-binary=:all:", "INITools==0.2")
1051 1052 1053 1054

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

    exists += glob.glob(
D
Donald Stufft 已提交
1059
        script.site_packages_path / "initools/__pycache__/__init__*.pyc"
1060 1061 1062 1063 1064
    )

    assert any(exists)


1065
@pytest.mark.network
1066
def test_no_compiles_pyc(script):
1067 1068 1069 1070
    """
    Test installing from wheel with --compile on
    """
    del script.environ["PYTHONDONTWRITEBYTECODE"]
1071
    script.pip("install", "--no-compile", "--no-binary=:all:", "INITools==0.2")
1072 1073 1074 1075

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

    exists += glob.glob(
D
Donald Stufft 已提交
1080
        script.site_packages_path / "initools/__pycache__/__init__*.pyc"
1081 1082 1083
    )

    assert not any(exists)
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094


def test_install_upgrade_editable_depending_on_other_editable(script):
    script.scratch_path.join("pkga").mkdir()
    pkga_path = script.scratch_path / 'pkga'
    pkga_path.join("setup.py").write(textwrap.dedent("""
        from setuptools import setup
        setup(name='pkga',
              version='0.1')
    """))
    script.pip('install', '--editable', pkga_path)
X
Xavier Fernandez 已提交
1095 1096
    result = script.pip('list', '--format=freeze')
    assert "pkga==0.1" in result.stdout
1097 1098 1099 1100 1101 1102 1103 1104 1105

    script.scratch_path.join("pkgb").mkdir()
    pkgb_path = script.scratch_path / 'pkgb'
    pkgb_path.join("setup.py").write(textwrap.dedent("""
        from setuptools import setup
        setup(name='pkgb',
              version='0.1',
              install_requires=['pkga'])
    """))
X
Xavier Fernandez 已提交
1106 1107 1108
    script.pip('install', '--upgrade', '--editable', pkgb_path, '--no-index')
    result = script.pip('list', '--format=freeze')
    assert "pkgb==0.1" in result.stdout
1109

1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135

def test_install_subprocess_output_handling(script, data):
    args = ['install', data.src.join('chattymodule')]

    # 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.
    result = script.pip(*(args + ["--verbose"]))
    assert 1 == result.stdout.count("HELLO FROM CHATTYMODULE egg_info")
    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)
    assert 1 == result.stdout.count("I DIE, I DIE")

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

1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147

def test_install_log(script, data, tmpdir):
    # test that verbose logs go to "--log" file
    f = tmpdir.join("log.txt")
    args = ['--log=%s' % f,
            'install', data.src.join('chattymodule')]
    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")

1148 1149

def test_install_topological_sort(script, data):
X
Xavier Fernandez 已提交
1150
    args = ['install', 'TopoRequires4', '--no-index', '-f', data.packages]
1151 1152 1153 1154
    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
1155 1156


1157 1158
def test_install_wheel_broken(script, with_wheel):
    res = script.pip_install_local('wheelbroken', expect_stderr=True)
1159
    assert "Successfully installed wheelbroken-0.1" in str(res), str(res)
1160 1161


1162 1163
def test_cleanup_after_failed_wheel(script, with_wheel):
    res = script.pip_install_local('wheelbrokenafter', expect_stderr=True)
1164 1165 1166 1167 1168 1169 1170 1171 1172
    # One of the effects of not cleaning up is broken scripts:
    script_py = script.bin_path / "script.py"
    assert script_py.exists, script_py
    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)


1173
def test_install_builds_wheels(script, data, with_wheel):
1174 1175 1176 1177 1178 1179
    # 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')
1180 1181 1182 1183 1184
    # NB This incidentally tests a local tree + tarball inputs
    # see test_install_editable_from_git_autobuild_wheel for editable
    # vcs coverage.
    to_install = data.packages.join('requires_wheelbroken_upper')
    res = script.pip(
1185
        'install', '--no-index', '-f', data.find_links,
1186 1187 1188 1189 1190 1191
        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 = []
1192
    for top, dirs, files in os.walk(wheels_cache):
1193 1194
        wheels.extend(files)
    # and built wheels for upper and wheelbroken
P
Paul Moore 已提交
1195 1196
    assert "Building wheel for upper" in str(res), str(res)
    assert "Building wheel for wheelb" in str(res), str(res)
T
Thomas Kluyver 已提交
1197
    # Wheels are built for local directories, but not cached.
P
Paul Moore 已提交
1198
    assert "Building wheel for requir" in str(res), str(res)
1199 1200 1201 1202 1203
    # 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 已提交
1204 1205
    # Wheels are built for local directories, but not cached.
    assert "Running setup.py install for requir" not in str(res), str(res)
1206 1207
    # wheelbroken has to run install
    assert "Running setup.py install for wheelb" in str(res), str(res)
1208 1209
    # We want to make sure we used the correct implementation tag
    assert wheels == [
A
Anthony Sottile 已提交
1210
        "Upper-2.0-{}-none-any.whl".format(pep425tags.implementation_tag),
1211
    ]
1212 1213


1214
def test_install_no_binary_disables_building_wheels(script, data, with_wheel):
1215 1216 1217 1218 1219 1220 1221 1222 1223
    to_install = data.packages.join('requires_wheelbroken_upper')
    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 已提交
1224
    assert "Building wheel for wheelb" in str(res), str(res)
1225
    # Wheels are built for local directories, but not cached across runs
P
Paul Moore 已提交
1226
    assert "Building wheel for requir" in str(res), str(res)
1227
    # Don't build wheel for upper which was blacklisted
P
Paul Moore 已提交
1228
    assert "Building wheel for upper" not in str(res), str(res)
1229
    # Wheels are built for local directories, but not cached across runs
1230
    assert "Running setup.py install for requir" not in str(res), str(res)
1231
    # And these two fell back to sdist based installed.
1232 1233
    assert "Running setup.py install for wheelb" in str(res), str(res)
    assert "Running setup.py install for upper" in str(res), str(res)
1234 1235


1236
def test_install_no_binary_disables_cached_wheels(script, data, with_wheel):
1237 1238
    # Seed the cache
    script.pip(
1239
        'install', '--no-index', '-f', data.find_links,
1240 1241 1242 1243 1244 1245 1246
        '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 已提交
1247
    assert "Building wheel for upper" not in str(res), str(res)
1248 1249
    # Must have used source, not a cached wheel to install upper.
    assert "Running setup.py install for upper" in str(res), str(res)
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262


def test_install_editable_with_wrong_egg_name(script):
    script.scratch_path.join("pkga").mkdir()
    pkga_path = script.scratch_path / 'pkga'
    pkga_path.join("setup.py").write(textwrap.dedent("""
        from setuptools import setup
        setup(name='pkga',
              version='0.1')
    """))
    result = script.pip(
        'install', '--editable', 'file://%s#egg=pkgb' % pkga_path,
        expect_error=True)
P
Paul Moore 已提交
1263
    assert ("Generating metadata for package pkgb produced metadata "
1264 1265 1266
            "for project name pkga. Fix your #egg=pkgb "
            "fragments.") in result.stderr
    assert "Successfully installed pkga" in str(result), str(result)
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284


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
1285 1286


1287
def test_double_install(script):
1288 1289 1290
    """
    Test double install passing with two same version requirements
    """
1291 1292
    result = script.pip('install', 'pip', 'pip',
                        expect_error=False)
1293 1294 1295 1296
    msg = "Double requirement given: pip (already in pip, name='pip')"
    assert msg not in result.stderr


1297
def test_double_install_fail(script):
1298 1299 1300 1301 1302 1303 1304
    """
    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 已提交
1305 1306


1307
def test_install_incompatible_python_requires(script):
X
Xavier Fernandez 已提交
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
    script.scratch_path.join("pkga").mkdir()
    pkga_path = script.scratch_path / 'pkga'
    pkga_path.join("setup.py").write(textwrap.dedent("""
        from setuptools import setup
        setup(name='pkga',
              python_requires='<1.0',
              version='0.1')
    """))
    result = script.pip('install', pkga_path, expect_error=True)
    assert ("pkga requires Python '<1.0' "
1318
            "but the running Python is ") in result.stderr, str(result)
X
Xavier Fernandez 已提交
1319 1320


1321
def test_install_incompatible_python_requires_editable(script):
X
Xavier Fernandez 已提交
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
    script.scratch_path.join("pkga").mkdir()
    pkga_path = script.scratch_path / 'pkga'
    pkga_path.join("setup.py").write(textwrap.dedent("""
        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)
    assert ("pkga requires Python '<1.0' "
1333
            "but the running Python is ") in result.stderr, str(result)
X
Xavier Fernandez 已提交
1334 1335


1336
def test_install_incompatible_python_requires_wheel(script, with_wheel):
X
Xavier Fernandez 已提交
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
    script.scratch_path.join("pkga").mkdir()
    pkga_path = script.scratch_path / 'pkga'
    pkga_path.join("setup.py").write(textwrap.dedent("""
        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)
    assert ("pkga requires Python '<1.0' "
            "but the running Python is ") in result.stderr


1353
def test_install_compatible_python_requires(script):
X
Xavier Fernandez 已提交
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363
    script.scratch_path.join("pkga").mkdir()
    pkga_path = script.scratch_path / 'pkga'
    pkga_path.join("setup.py").write(textwrap.dedent("""
        from setuptools import setup
        setup(name='pkga',
              python_requires='>1.0',
              version='0.1')
    """))
    res = script.pip('install', pkga_path, expect_error=True)
    assert "Successfully installed pkga-0.1" in res.stdout, res
1364 1365


1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
@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'
        ],
    )
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413
    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)
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436


def test_installing_scripts_outside_path_prints_warning(script):
    result = script.pip_install_local(
        "--prefix", script.scratch_path, "script_wheel1", expect_error=True
    )
    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
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458


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.
    """
    to_install = data.packages.join("FSPkg")
    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 已提交
1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502


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(
        'install', '--no-index', pkgB_path,
        expect_stderr=True,
    )
    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)