test_download.py 29.2 KB
Newer Older
1
import os.path
2
import shutil
3
import textwrap
4
from hashlib import sha256
5

P
Pradyun S. Gedam 已提交
6
import pytest
7

8
from pip._internal.cli.status_codes import ERROR
9
from pip._internal.utils.urls import path_to_url
10
from tests.lib import create_really_basic_wheel
11
from tests.lib.path import Path
12
from tests.lib.server import file_response
13 14


15
def fake_wheel(data, wheel_path):
16 17 18 19
    wheel_name = os.path.basename(wheel_path)
    name, version, rest = wheel_name.split("-", 2)
    wheel_data = create_really_basic_wheel(name, version)
    data.packages.joinpath(wheel_path).write_bytes(wheel_data)
20 21


22 23 24 25 26
@pytest.mark.network
def test_download_if_requested(script):
    """
    It should download (in the scratch path) and not install if requested.
    """
27 28 29
    result = script.pip("download", "-d", "pip_downloads", "INITools==0.1")
    result.did_create(Path("scratch") / "pip_downloads" / "INITools-0.1.tar.gz")
    result.did_not_create(script.site_packages / "initools")
30 31 32


@pytest.mark.network
33
def test_basic_download_setuptools(script):
34 35 36
    """
    It should download (in the scratch path) and not install if requested.
    """
37 38 39
    result = script.pip("download", "setuptools")
    setuptools_prefix = str(Path("scratch") / "setuptools")
    assert any(path.startswith(setuptools_prefix) for path in result.files_created)
40 41


X
Xavier Fernandez 已提交
42
def test_download_wheel(script, data):
43 44 45 46
    """
    Test using "pip download" to download a *.whl archive.
    """
    result = script.pip(
47
        "download", "--no-index", "-f", data.packages, "-d", ".", "meta"
48
    )
49 50
    result.did_create(Path("scratch") / "meta-1.0-py2.py3-none-any.whl")
    result.did_not_create(script.site_packages / "piptestpackage")
51 52 53 54 55


@pytest.mark.network
def test_single_download_from_requirements_file(script):
    """
J
Jon Dufresne 已提交
56
    It should support download (in the scratch path) from PyPI from a
57 58
    requirements file
    """
59 60 61
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
62
        INITools==0.1
63 64 65
        """
        )
    )
66
    result = script.pip(
67 68 69 70 71
        "download",
        "-r",
        script.scratch_path / "test-req.txt",
        "-d",
        ".",
72
    )
73 74
    result.did_create(Path("scratch") / "INITools-0.1.tar.gz")
    result.did_not_create(script.site_packages / "initools")
75 76 77


@pytest.mark.network
78
def test_basic_download_should_download_dependencies(script):
79 80 81
    """
    It should download dependencies (in the scratch path)
    """
82 83 84 85 86
    result = script.pip("download", "Paste[openid]==1.7.5.1", "-d", ".")
    result.did_create(Path("scratch") / "Paste-1.7.5.1.tar.gz")
    openid_tarball_prefix = str(Path("scratch") / "python-openid-")
    assert any(path.startswith(openid_tarball_prefix) for path in result.files_created)
    result.did_not_create(script.site_packages / "openid")
87 88 89 90 91 92


def test_download_wheel_archive(script, data):
    """
    It should download a wheel archive path
    """
93 94 95 96
    wheel_filename = "colander-0.9.9-py2.py3-none-any.whl"
    wheel_path = "/".join((data.find_links, wheel_filename))
    result = script.pip("download", wheel_path, "-d", ".", "--no-deps")
    result.did_create(Path("scratch") / wheel_filename)
97 98 99 100 101 102


def test_download_should_download_wheel_deps(script, data):
    """
    It should download dependencies for wheels(in the scratch path)
    """
103 104 105
    wheel_filename = "colander-0.9.9-py2.py3-none-any.whl"
    dep_filename = "translationstring-1.1.tar.gz"
    wheel_path = "/".join((data.find_links, wheel_filename))
106
    result = script.pip(
107
        "download", wheel_path, "-d", ".", "--find-links", data.find_links, "--no-index"
108
    )
109 110
    result.did_create(Path("scratch") / wheel_filename)
    result.did_create(Path("scratch") / dep_filename)
111 112 113 114 115 116 117


@pytest.mark.network
def test_download_should_skip_existing_files(script):
    """
    It should not download files already existing in the scratch dir
    """
118 119 120
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
121
        INITools==0.1
122 123 124
        """
        )
    )
125 126

    result = script.pip(
127 128 129 130 131
        "download",
        "-r",
        script.scratch_path / "test-req.txt",
        "-d",
        ".",
132
    )
133 134
    result.did_create(Path("scratch") / "INITools-0.1.tar.gz")
    result.did_not_create(script.site_packages / "initools")
135 136

    # adding second package to test-req.txt
137 138 139
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
140 141
        INITools==0.1
        python-openid==2.2.5
142 143 144
        """
        )
    )
145 146 147

    # only the second package should be downloaded
    result = script.pip(
148 149 150 151 152
        "download",
        "-r",
        script.scratch_path / "test-req.txt",
        "-d",
        ".",
153
    )
154 155 156 157 158
    openid_tarball_prefix = str(Path("scratch") / "python-openid-")
    assert any(path.startswith(openid_tarball_prefix) for path in result.files_created)
    result.did_not_create(Path("scratch") / "INITools-0.1.tar.gz")
    result.did_not_create(script.site_packages / "initools")
    result.did_not_create(script.site_packages / "openid")
159 160 161 162 163 164 165 166


@pytest.mark.network
def test_download_vcs_link(script):
    """
    It should allow -d flag for vcs links, regression test for issue #798.
    """
    result = script.pip(
167
        "download", "-d", ".", "git+git://github.com/pypa/pip-test-package.git"
168
    )
169 170
    result.did_create(Path("scratch") / "pip-test-package-0.1.1.zip")
    result.did_not_create(script.site_packages / "piptestpackage")
171 172


173
def test_only_binary_set_then_download_specific_platform(script, data):
174 175
    """
    Confirm that specifying an interpreter/platform constraint
176
    is allowed when ``--only-binary=:all:`` is set.
177
    """
178
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
179 180

    result = script.pip(
181 182 183 184 185 186 187 188 189 190
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake",
191
    )
192
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
193

194

195
def test_no_deps_set_then_download_specific_platform(script, data):
196 197
    """
    Confirm that specifying an interpreter/platform constraint
198 199
    is allowed when ``--no-deps`` is set.
    """
200
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
201 202

    result = script.pip(
203 204 205 206 207 208 209 210 211 212
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--no-deps",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake",
213
    )
214
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
215 216 217 218 219 220


def test_download_specific_platform_fails(script, data):
    """
    Confirm that specifying an interpreter/platform constraint
    enforces that ``--no-deps`` or ``--only-binary=:all:`` is set.
221
    """
222
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
223

224
    result = script.pip(
225 226 227 228 229 230 231 232 233
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake",
234 235
        expect_error=True,
    )
236
    assert "--only-binary=:all:" in result.stderr
237

238 239 240 241 242 243

def test_no_binary_set_then_download_specific_platform_fails(script, data):
    """
    Confirm that specifying an interpreter/platform constraint
    enforces that ``--only-binary=:all:`` is set without ``--no-binary``.
    """
244
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
245

246
    result = script.pip(
247 248 249 250 251 252 253 254 255 256 257
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--no-binary=fake",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake",
258 259
        expect_error=True,
    )
260
    assert "--only-binary=:all:" in result.stderr
261 262


263 264 265 266 267
def test_download_specify_platform(script, data):
    """
    Test using "pip download --platform" to download a .whl archive
    supported for a specific platform
    """
268
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
269 270 271

    # Confirm that universal wheels are returned even for specific
    # platforms.
272
    result = script.pip(
273 274 275 276 277 278 279 280 281 282
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake",
283
    )
284
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
285 286

    result = script.pip(
287 288 289 290 291 292 293 294 295 296
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "macosx_10_9_x86_64",
        "fake",
297 298 299
    )

    data.reset()
300 301
    fake_wheel(data, "fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl")
    fake_wheel(data, "fake-2.0-py2.py3-none-linux_x86_64.whl")
302 303

    result = script.pip(
304 305 306 307 308 309 310 311 312 313
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "macosx_10_10_x86_64",
        "fake",
314
    )
315
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl")
316 317 318

    # OSX platform wheels are not backward-compatible.
    result = script.pip(
319 320 321 322 323 324 325 326 327 328
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "macosx_10_8_x86_64",
        "fake",
329 330 331 332 333
        expect_error=True,
    )

    # No linux wheel provided for this version.
    result = script.pip(
334 335 336 337 338 339 340 341 342 343
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake==1",
344 345 346 347
        expect_error=True,
    )

    result = script.pip(
348 349 350 351 352 353 354 355 356 357
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake==2",
358
    )
359
    result.did_create(Path("scratch") / "fake-2.0-py2.py3-none-linux_x86_64.whl")
360

361 362
    # Test with multiple supported platforms specified.
    data.reset()
363
    fake_wheel(data, "fake-3.0-py2.py3-none-linux_x86_64.whl")
364
    result = script.pip(
365 366 367 368 369 370 371 372 373 374 375 376 377 378
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "manylinux1_x86_64",
        "--platform",
        "linux_x86_64",
        "--platform",
        "any",
        "fake==3",
379
    )
380
    result.did_create(Path("scratch") / "fake-3.0-py2.py3-none-linux_x86_64.whl")
381

382

383
class TestDownloadPlatformManylinuxes:
M
Mark Williams 已提交
384 385 386 387 388
    """
    "pip download --platform" downloads a .whl archive supported for
    manylinux platforms.
    """

389 390 391 392 393 394 395 396 397
    @pytest.mark.parametrize(
        "platform",
        [
            "linux_x86_64",
            "manylinux1_x86_64",
            "manylinux2010_x86_64",
            "manylinux2014_x86_64",
        ],
    )
M
Mark Williams 已提交
398 399 400 401
    def test_download_universal(self, platform, script, data):
        """
        Universal wheels are returned even for specific platforms.
        """
402
        fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
M
Mark Williams 已提交
403
        result = script.pip(
404 405 406 407 408 409 410 411 412 413
            "download",
            "--no-index",
            "--find-links",
            data.find_links,
            "--only-binary=:all:",
            "--dest",
            ".",
            "--platform",
            platform,
            "fake",
M
Mark Williams 已提交
414
        )
415 416 417 418 419 420 421 422 423 424 425 426 427
        result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")

    @pytest.mark.parametrize(
        "wheel_abi,platform",
        [
            ("manylinux1_x86_64", "manylinux1_x86_64"),
            ("manylinux1_x86_64", "manylinux2010_x86_64"),
            ("manylinux2010_x86_64", "manylinux2010_x86_64"),
            ("manylinux1_x86_64", "manylinux2014_x86_64"),
            ("manylinux2010_x86_64", "manylinux2014_x86_64"),
            ("manylinux2014_x86_64", "manylinux2014_x86_64"),
        ],
    )
M
Mark Williams 已提交
428
    def test_download_compatible_manylinuxes(
429 430 431 432 433
        self,
        wheel_abi,
        platform,
        script,
        data,
M
Mark Williams 已提交
434 435 436 437
    ):
        """
        Earlier manylinuxes are compatible with later manylinuxes.
        """
438
        wheel = f"fake-1.0-py2.py3-none-{wheel_abi}.whl"
M
Mark Williams 已提交
439 440
        fake_wheel(data, wheel)
        result = script.pip(
441 442 443 444 445 446 447 448 449 450
            "download",
            "--no-index",
            "--find-links",
            data.find_links,
            "--only-binary=:all:",
            "--dest",
            ".",
            "--platform",
            platform,
            "fake",
M
Mark Williams 已提交
451
        )
452
        result.did_create(Path("scratch") / wheel)
M
Mark Williams 已提交
453 454 455 456 457 458 459

    def test_explicit_platform_only(self, data, script):
        """
        When specifying the platform, manylinux1 needs to be the
        explicit platform--it won't ever be added to the compatible
        tags.
        """
460
        fake_wheel(data, "fake-1.0-py2.py3-none-linux_x86_64.whl")
M
Mark Williams 已提交
461
        script.pip(
462 463 464 465 466 467 468 469 470 471
            "download",
            "--no-index",
            "--find-links",
            data.find_links,
            "--only-binary=:all:",
            "--dest",
            ".",
            "--platform",
            "linux_x86_64",
            "fake",
M
Mark Williams 已提交
472
        )
473 474


475
def test_download__python_version(script, data):
476 477 478 479
    """
    Test using "pip download --python-version" to download a .whl archive
    supported for a specific interpreter
    """
480
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
481
    result = script.pip(
482 483 484 485 486 487 488 489 490 491
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "2",
        "fake",
492
    )
493
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
494 495

    result = script.pip(
496 497 498 499 500 501 502 503 504 505
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "3",
        "fake",
506 507 508
    )

    result = script.pip(
509 510 511 512 513 514 515 516 517 518
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "27",
        "fake",
519 520 521
    )

    result = script.pip(
522 523 524 525 526 527 528 529 530 531
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "33",
        "fake",
532 533 534
    )

    data.reset()
535 536
    fake_wheel(data, "fake-1.0-py2-none-any.whl")
    fake_wheel(data, "fake-2.0-py3-none-any.whl")
537 538 539

    # No py3 provided for version 1.
    result = script.pip(
540 541 542 543 544 545 546 547 548 549
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "3",
        "fake==1.0",
550 551 552 553
        expect_error=True,
    )

    result = script.pip(
554 555 556 557 558 559 560 561 562 563
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "2",
        "fake",
564
    )
565
    result.did_create(Path("scratch") / "fake-1.0-py2-none-any.whl")
566 567

    result = script.pip(
568 569 570 571 572 573 574 575 576 577
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "26",
        "fake",
578 579 580
    )

    result = script.pip(
581 582 583 584 585 586 587 588 589 590
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "3",
        "fake",
591
    )
592
    result.did_create(Path("scratch") / "fake-2.0-py3-none-any.whl")
593 594


595 596 597 598 599 600 601 602 603
def make_wheel_with_python_requires(script, package_name, python_requires):
    """
    Create a wheel using the given python_requires.

    :return: the path to the wheel file.
    """
    package_dir = script.scratch_path / package_name
    package_dir.mkdir()

604 605
    text = textwrap.dedent(
        """\
606 607 608 609
    from setuptools import setup
    setup(name='{}',
          python_requires='{}',
          version='1.0')
610 611 612
    """
    ).format(package_name, python_requires)
    package_dir.joinpath("setup.py").write_text(text)
613
    script.run(
614 615 616 617 618
        "python",
        "setup.py",
        "bdist_wheel",
        "--universal",
        cwd=package_dir,
619 620
    )

621 622
    file_name = f"{package_name}-1.0-py2.py3-none-any.whl"
    return package_dir / "dist" / file_name
623 624


625 626
@pytest.mark.usefixtures("with_wheel")
def test_download__python_version_used_for_python_requires(script, data):
627 628 629 630
    """
    Test that --python-version is used for the Requires-Python check.
    """
    wheel_path = make_wheel_with_python_requires(
631 632 633
        script,
        "mypackage",
        python_requires="==3.2",
634 635 636 637 638
    )
    wheel_dir = os.path.dirname(wheel_path)

    def make_args(python_version):
        return [
639 640 641 642 643 644 645 646 647 648
            "download",
            "--no-index",
            "--find-links",
            wheel_dir,
            "--only-binary=:all:",
            "--dest",
            ".",
            "--python-version",
            python_version,
            "mypackage==1.0",
649 650
        ]

651
    args = make_args("33")
652 653 654 655 656
    result = script.pip(*args, expect_error=True)
    expected_err = (
        "ERROR: Package 'mypackage' requires a different Python: "
        "3.3.0 not in '==3.2'"
    )
657
    assert expected_err in result.stderr, f"stderr: {result.stderr}"
658 659

    # Now try with a --python-version that satisfies the Requires-Python.
660
    args = make_args("32")
661 662 663
    script.pip(*args)  # no exception


664 665
@pytest.mark.usefixtures("with_wheel")
def test_download_ignore_requires_python_dont_fail_with_wrong_python(script):
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
    """
    Test that --ignore-requires-python ignores Requires-Python check.
    """
    wheel_path = make_wheel_with_python_requires(
        script,
        "mypackage",
        python_requires="==999",
    )
    wheel_dir = os.path.dirname(wheel_path)

    result = script.pip(
        "download",
        "--ignore-requires-python",
        "--no-index",
        "--find-links",
        wheel_dir,
        "--only-binary=:all:",
        "--dest",
        ".",
        "mypackage==1.0",
    )
687
    result.did_create(Path("scratch") / "mypackage-1.0-py2.py3-none-any.whl")
688 689


690 691 692 693 694
def test_download_specify_abi(script, data):
    """
    Test using "pip download --abi" to download a .whl archive
    supported for a specific abi
    """
695
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
696
    result = script.pip(
697 698 699 700 701 702 703 704 705 706 707 708
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "--abi",
        "fake_abi",
        "fake",
709
    )
710
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
711 712

    result = script.pip(
713 714 715 716 717 718 719 720 721 722 723 724
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "--abi",
        "none",
        "fake",
725 726 727
    )

    result = script.pip(
728 729 730 731 732 733 734 735 736 737
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--abi",
        "cp27m",
        "fake",
738 739 740
    )

    data.reset()
741
    fake_wheel(data, "fake-1.0-fk2-fakeabi-fake_platform.whl")
742
    result = script.pip(
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "2",
        "--implementation",
        "fk",
        "--platform",
        "fake_platform",
        "--abi",
        "fakeabi",
        "fake",
759
    )
760
    result.did_create(Path("scratch") / "fake-1.0-fk2-fakeabi-fake_platform.whl")
761 762

    result = script.pip(
763 764 765 766 767 768 769 770 771 772 773 774 775 776
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "--platform",
        "fake_platform",
        "--abi",
        "none",
        "fake",
777 778 779
        expect_error=True,
    )

780
    data.reset()
781
    fake_wheel(data, "fake-1.0-fk2-otherabi-fake_platform.whl")
782
    result = script.pip(
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "2",
        "--implementation",
        "fk",
        "--platform",
        "fake_platform",
        "--abi",
        "fakeabi",
        "--abi",
        "otherabi",
        "--abi",
        "none",
        "fake",
803
    )
804
    result.did_create(Path("scratch") / "fake-1.0-fk2-otherabi-fake_platform.whl")
805

806 807 808 809 810 811

def test_download_specify_implementation(script, data):
    """
    Test using "pip download --abi" to download a .whl archive
    supported for a specific abi
    """
812
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
813
    result = script.pip(
814 815 816 817 818 819 820 821 822 823
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "fake",
824
    )
825
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
826 827

    data.reset()
828
    fake_wheel(data, "fake-1.0-fk3-none-any.whl")
829
    result = script.pip(
830 831 832 833 834 835 836 837 838 839 840 841
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "--python-version",
        "3",
        "fake",
842
    )
843
    result.did_create(Path("scratch") / "fake-1.0-fk3-none-any.whl")
844 845

    result = script.pip(
846 847 848 849 850 851 852 853 854 855 856 857
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "--python-version",
        "2",
        "fake",
858 859
        expect_error=True,
    )
860 861 862 863 864 865


def test_download_exit_status_code_when_no_requirements(script):
    """
    Test download exit status code when no requirements specified
    """
866 867
    result = script.pip("download", expect_error=True)
    assert "You must give at least one requirement to download" in result.stderr
868 869 870 871 872 873 874
    assert result.returncode == ERROR


def test_download_exit_status_code_when_blank_requirements_file(script):
    """
    Test download exit status code when blank requirements file specified
    """
875
    script.scratch_path.joinpath("blank.txt").write_text("\n")
876
    script.pip("download", "-r", "blank.txt")
877 878 879


def test_download_prefer_binary_when_tarball_higher_than_wheel(script, data):
880
    fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
881
    result = script.pip(
882 883 884 885 886 887 888 889
        "download",
        "--prefer-binary",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
        "source",
890
    )
891 892
    result.did_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")
    result.did_not_create(Path("scratch") / "source-1.0.tar.gz")
893 894


D
Devesh Kumar Singh 已提交
895
def test_prefer_binary_tarball_higher_than_wheel_req_file(script, data):
896 897 898 899
    fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
D
Devesh Kumar Singh 已提交
900 901
                --prefer-binary
                 source
902 903 904
                """
        )
    )
D
Devesh Kumar Singh 已提交
905
    result = script.pip(
906 907 908 909 910 911 912 913
        "download",
        "-r",
        script.scratch_path / "test-req.txt",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
D
Devesh Kumar Singh 已提交
914 915
    )

916 917
    result.did_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")
    result.did_not_create(Path("scratch") / "source-1.0.tar.gz")
D
Devesh Kumar Singh 已提交
918 919


920
def test_download_prefer_binary_when_wheel_doesnt_satisfy_req(script, data):
921 922 923 924
    fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
925
        source>0.9
926 927 928
        """
        )
    )
929 930

    result = script.pip(
931 932 933 934 935 936 937 938 939
        "download",
        "--prefer-binary",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
        "-r",
        script.scratch_path / "test-req.txt",
940
    )
941 942
    result.did_create(Path("scratch") / "source-1.0.tar.gz")
    result.did_not_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")
943 944


D
Devesh Kumar Singh 已提交
945
def test_prefer_binary_when_wheel_doesnt_satisfy_req_req_file(script, data):
946 947 948 949
    fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
D
Devesh Kumar Singh 已提交
950 951
        --prefer-binary
        source>0.9
952 953 954
        """
        )
    )
D
Devesh Kumar Singh 已提交
955 956

    result = script.pip(
957 958 959 960 961 962 963 964
        "download",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
        "-r",
        script.scratch_path / "test-req.txt",
D
Devesh Kumar Singh 已提交
965
    )
966 967
    result.did_create(Path("scratch") / "source-1.0.tar.gz")
    result.did_not_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")
D
Devesh Kumar Singh 已提交
968 969


970 971
def test_download_prefer_binary_when_only_tarball_exists(script, data):
    result = script.pip(
972 973 974 975 976 977 978 979
        "download",
        "--prefer-binary",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
        "source",
980
    )
981
    result.did_create(Path("scratch") / "source-1.0.tar.gz")
982 983


D
Devesh Kumar Singh 已提交
984
def test_prefer_binary_when_only_tarball_exists_req_file(script, data):
985 986 987
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
D
Devesh Kumar Singh 已提交
988 989
            --prefer-binary
            source
990 991 992
            """
        )
    )
D
Devesh Kumar Singh 已提交
993
    result = script.pip(
994 995 996 997 998 999 1000 1001
        "download",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
        "-r",
        script.scratch_path / "test-req.txt",
D
Devesh Kumar Singh 已提交
1002
    )
1003
    result.did_create(Path("scratch") / "source-1.0.tar.gz")
D
Devesh Kumar Singh 已提交
1004 1005


1006 1007 1008 1009 1010 1011 1012 1013
@pytest.fixture(scope="session")
def shared_script(tmpdir_factory, script_factory):
    tmpdir = Path(str(tmpdir_factory.mktemp("download_shared_script")))
    script = script_factory(tmpdir.joinpath("workspace"))
    return script


def test_download_file_url(shared_script, shared_data, tmpdir):
1014
    download_dir = tmpdir / "download"
1015
    download_dir.mkdir()
1016
    downloaded_path = download_dir / "simple-1.0.tar.gz"
1017

1018
    simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
1019 1020

    shared_script.pip(
1021 1022
        "download",
        "-d",
1023
        str(download_dir),
1024
        "--no-index",
1025 1026 1027 1028 1029
        path_to_url(str(simple_pkg)),
    )

    assert downloaded_path.exists()
    assert simple_pkg.read_bytes() == downloaded_path.read_bytes()
1030 1031


1032 1033
def test_download_file_url_existing_ok_download(shared_script, shared_data, tmpdir):
    download_dir = tmpdir / "download"
1034
    download_dir.mkdir()
1035 1036
    downloaded_path = download_dir / "simple-1.0.tar.gz"
    fake_existing_package = shared_data.packages / "simple-2.0.tar.gz"
1037 1038 1039 1040
    shutil.copy(str(fake_existing_package), str(downloaded_path))
    downloaded_path_bytes = downloaded_path.read_bytes()
    digest = sha256(downloaded_path_bytes).hexdigest()

1041
    simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
1042 1043
    url = "{}#sha256={}".format(path_to_url(simple_pkg), digest)

1044
    shared_script.pip("download", "-d", str(download_dir), url)
1045 1046

    assert downloaded_path_bytes == downloaded_path.read_bytes()
1047 1048


1049 1050
def test_download_file_url_existing_bad_download(shared_script, shared_data, tmpdir):
    download_dir = tmpdir / "download"
1051
    download_dir.mkdir()
1052 1053
    downloaded_path = download_dir / "simple-1.0.tar.gz"
    fake_existing_package = shared_data.packages / "simple-2.0.tar.gz"
1054 1055
    shutil.copy(str(fake_existing_package), str(downloaded_path))

1056
    simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
1057 1058 1059 1060
    simple_pkg_bytes = simple_pkg.read_bytes()
    digest = sha256(simple_pkg_bytes).hexdigest()
    url = "{}#sha256={}".format(path_to_url(simple_pkg), digest)

1061
    shared_script.pip("download", "-d", str(download_dir), url)
1062 1063

    assert simple_pkg_bytes == downloaded_path.read_bytes()
1064 1065


1066
def test_download_http_url_bad_hash(shared_script, shared_data, tmpdir, mock_server):
1067 1068 1069
    """
    If already-downloaded file has bad checksum, re-download.
    """
1070
    download_dir = tmpdir / "download"
1071
    download_dir.mkdir()
1072 1073
    downloaded_path = download_dir / "simple-1.0.tar.gz"
    fake_existing_package = shared_data.packages / "simple-2.0.tar.gz"
1074 1075
    shutil.copy(str(fake_existing_package), str(downloaded_path))

1076
    simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
1077 1078
    simple_pkg_bytes = simple_pkg.read_bytes()
    digest = sha256(simple_pkg_bytes).hexdigest()
1079
    mock_server.set_responses([file_response(simple_pkg)])
1080
    mock_server.start()
1081
    base_address = f"http://{mock_server.host}:{mock_server.port}"
1082
    url = f"{base_address}/simple-1.0.tar.gz#sha256={digest}"
1083

1084
    shared_script.pip("download", "-d", str(download_dir), url)
1085 1086 1087 1088 1089 1090

    assert simple_pkg_bytes == downloaded_path.read_bytes()

    mock_server.stop()
    requests = mock_server.get_requests()
    assert len(requests) == 1
1091 1092
    assert requests[0]["PATH_INFO"] == "/simple-1.0.tar.gz"
    assert requests[0]["HTTP_ACCEPT_ENCODING"] == "identity"
S
Stéphane Bidoul 已提交
1093 1094 1095 1096 1097 1098


def test_download_editable(script, data, tmpdir):
    """
    Test 'pip download' of editables in requirement file.
    """
1099
    editable_path = str(data.src / "simplewheel-1.0").replace(os.path.sep, "/")
S
Stéphane Bidoul 已提交
1100
    requirements_path = tmpdir / "requirements.txt"
1101
    requirements_path.write_text("-e " + editable_path + "\n")
S
Stéphane Bidoul 已提交
1102 1103
    download_dir = tmpdir / "download_dir"
    script.pip(
1104
        "download", "--no-deps", "-r", str(requirements_path), "-d", str(download_dir)
S
Stéphane Bidoul 已提交
1105 1106 1107 1108
    )
    downloads = os.listdir(download_dir)
    assert len(downloads) == 1
    assert downloads[0].endswith(".zip")