mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
28d7730087
The approach it uses now doesn't work anymore due to 452d7da8
.
The installation of `fake_dep` now succeeds whether or not `setuptools`
is installed in the test environment.
Use a different approach instead: try to import `pip` in the `setup.py`
script. If it succeeds, then we are not running in an isolated environment,
and therefore PEP 517 isn't being used.
To add this custom logic to `setup.py`, add a new argument to
`create_basic_sdist_for_package`. Note that to make this work, I had to
switch from f-strings to `str.format`, since the `dedent` has to happen
before formatting.
1216 lines
32 KiB
Python
1216 lines
32 KiB
Python
import os
|
|
import shutil
|
|
import textwrap
|
|
from hashlib import sha256
|
|
from pathlib import Path
|
|
from typing import List
|
|
|
|
import pytest
|
|
|
|
from pip._internal.cli.status_codes import ERROR
|
|
from tests.conftest import MockServer, ScriptFactory
|
|
from tests.lib import (
|
|
PipTestEnvironment,
|
|
TestData,
|
|
create_basic_sdist_for_package,
|
|
create_really_basic_wheel,
|
|
)
|
|
from tests.lib.server import file_response
|
|
|
|
|
|
def fake_wheel(data: TestData, wheel_path: str) -> None:
|
|
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)
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_download_if_requested(script: PipTestEnvironment) -> None:
|
|
"""
|
|
It should download (in the scratch path) and not install if requested.
|
|
"""
|
|
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")
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_basic_download_setuptools(script: PipTestEnvironment) -> None:
|
|
"""
|
|
It should download (in the scratch path) and not install if requested.
|
|
"""
|
|
result = script.pip("download", "setuptools")
|
|
setuptools_prefix = str(Path("scratch") / "setuptools")
|
|
assert any(os.fspath(p).startswith(setuptools_prefix) for p in result.files_created)
|
|
|
|
|
|
def test_download_wheel(script: PipTestEnvironment, data: TestData) -> None:
|
|
"""
|
|
Test using "pip download" to download a *.whl archive.
|
|
"""
|
|
result = script.pip(
|
|
"download", "--no-index", "-f", data.packages, "-d", ".", "meta"
|
|
)
|
|
result.did_create(Path("scratch") / "meta-1.0-py2.py3-none-any.whl")
|
|
result.did_not_create(script.site_packages / "piptestpackage")
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_single_download_from_requirements_file(script: PipTestEnvironment) -> None:
|
|
"""
|
|
It should support download (in the scratch path) from PyPI from a
|
|
requirements file
|
|
"""
|
|
script.scratch_path.joinpath("test-req.txt").write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
INITools==0.1
|
|
"""
|
|
)
|
|
)
|
|
result = script.pip(
|
|
"download",
|
|
"-r",
|
|
script.scratch_path / "test-req.txt",
|
|
"-d",
|
|
".",
|
|
)
|
|
result.did_create(Path("scratch") / "INITools-0.1.tar.gz")
|
|
result.did_not_create(script.site_packages / "initools")
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_basic_download_should_download_dependencies(
|
|
script: PipTestEnvironment,
|
|
) -> None:
|
|
"""
|
|
It should download dependencies (in the scratch path)
|
|
"""
|
|
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(
|
|
os.fspath(path).startswith(openid_tarball_prefix)
|
|
for path in result.files_created
|
|
)
|
|
result.did_not_create(script.site_packages / "openid")
|
|
|
|
|
|
def test_download_wheel_archive(script: PipTestEnvironment, data: TestData) -> None:
|
|
"""
|
|
It should download a wheel archive path
|
|
"""
|
|
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)
|
|
|
|
|
|
def test_download_should_download_wheel_deps(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
It should download dependencies for wheels(in the scratch path)
|
|
"""
|
|
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))
|
|
result = script.pip(
|
|
"download", wheel_path, "-d", ".", "--find-links", data.find_links, "--no-index"
|
|
)
|
|
result.did_create(Path("scratch") / wheel_filename)
|
|
result.did_create(Path("scratch") / dep_filename)
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_download_should_skip_existing_files(script: PipTestEnvironment) -> None:
|
|
"""
|
|
It should not download files already existing in the scratch dir
|
|
"""
|
|
script.scratch_path.joinpath("test-req.txt").write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
INITools==0.1
|
|
"""
|
|
)
|
|
)
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"-r",
|
|
script.scratch_path / "test-req.txt",
|
|
"-d",
|
|
".",
|
|
)
|
|
result.did_create(Path("scratch") / "INITools-0.1.tar.gz")
|
|
result.did_not_create(script.site_packages / "initools")
|
|
|
|
# adding second package to test-req.txt
|
|
script.scratch_path.joinpath("test-req.txt").write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
INITools==0.1
|
|
python-openid==2.2.5
|
|
"""
|
|
)
|
|
)
|
|
|
|
# only the second package should be downloaded
|
|
result = script.pip(
|
|
"download",
|
|
"-r",
|
|
script.scratch_path / "test-req.txt",
|
|
"-d",
|
|
".",
|
|
)
|
|
openid_tarball_prefix = str(Path("scratch") / "python-openid-")
|
|
assert any(
|
|
os.fspath(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")
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_download_vcs_link(script: PipTestEnvironment) -> None:
|
|
"""
|
|
It should allow -d flag for vcs links, regression test for issue #798.
|
|
"""
|
|
result = script.pip(
|
|
"download", "-d", ".", "git+https://github.com/pypa/pip-test-package.git"
|
|
)
|
|
result.did_create(Path("scratch") / "pip-test-package-0.1.1.zip")
|
|
result.did_not_create(script.site_packages / "piptestpackage")
|
|
|
|
|
|
def test_only_binary_set_then_download_specific_platform(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
Confirm that specifying an interpreter/platform constraint
|
|
is allowed when ``--only-binary=:all:`` is set.
|
|
"""
|
|
fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"linux_x86_64",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
|
|
def test_no_deps_set_then_download_specific_platform(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
Confirm that specifying an interpreter/platform constraint
|
|
is allowed when ``--no-deps`` is set.
|
|
"""
|
|
fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--no-deps",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"linux_x86_64",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
|
|
def test_download_specific_platform_fails(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
Confirm that specifying an interpreter/platform constraint
|
|
enforces that ``--no-deps`` or ``--only-binary=:all:`` is set.
|
|
"""
|
|
fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"linux_x86_64",
|
|
"fake",
|
|
expect_error=True,
|
|
)
|
|
assert "--only-binary=:all:" in result.stderr
|
|
|
|
|
|
def test_no_binary_set_then_download_specific_platform_fails(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
Confirm that specifying an interpreter/platform constraint
|
|
enforces that ``--only-binary=:all:`` is set without ``--no-binary``.
|
|
"""
|
|
fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--no-binary=fake",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"linux_x86_64",
|
|
"fake",
|
|
expect_error=True,
|
|
)
|
|
assert "--only-binary=:all:" in result.stderr
|
|
|
|
|
|
def test_download_specify_platform(script: PipTestEnvironment, data: TestData) -> None:
|
|
"""
|
|
Test using "pip download --platform" to download a .whl archive
|
|
supported for a specific platform
|
|
"""
|
|
fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
# Confirm that universal wheels are returned even for specific
|
|
# platforms.
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"linux_x86_64",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"macosx_10_9_x86_64",
|
|
"fake",
|
|
)
|
|
|
|
data.reset()
|
|
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")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"macosx_10_10_x86_64",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl")
|
|
|
|
# OSX platform wheels are not backward-compatible.
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"macosx_10_8_x86_64",
|
|
"fake",
|
|
expect_error=True,
|
|
)
|
|
|
|
# No linux wheel provided for this version.
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"linux_x86_64",
|
|
"fake==1",
|
|
expect_error=True,
|
|
)
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"linux_x86_64",
|
|
"fake==2",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-2.0-py2.py3-none-linux_x86_64.whl")
|
|
|
|
# Test with multiple supported platforms specified.
|
|
data.reset()
|
|
fake_wheel(data, "fake-3.0-py2.py3-none-linux_x86_64.whl")
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"manylinux1_x86_64",
|
|
"--platform",
|
|
"linux_x86_64",
|
|
"--platform",
|
|
"any",
|
|
"fake==3",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-3.0-py2.py3-none-linux_x86_64.whl")
|
|
|
|
|
|
class TestDownloadPlatformManylinuxes:
|
|
"""
|
|
"pip download --platform" downloads a .whl archive supported for
|
|
manylinux platforms.
|
|
"""
|
|
|
|
@pytest.mark.parametrize(
|
|
"platform",
|
|
[
|
|
"linux_x86_64",
|
|
"manylinux1_x86_64",
|
|
"manylinux2010_x86_64",
|
|
"manylinux2014_x86_64",
|
|
],
|
|
)
|
|
def test_download_universal(
|
|
self, platform: str, script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
Universal wheels are returned even for specific platforms.
|
|
"""
|
|
fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
platform,
|
|
"fake",
|
|
)
|
|
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"),
|
|
],
|
|
)
|
|
def test_download_compatible_manylinuxes(
|
|
self,
|
|
wheel_abi: str,
|
|
platform: str,
|
|
script: PipTestEnvironment,
|
|
data: TestData,
|
|
) -> None:
|
|
"""
|
|
Earlier manylinuxes are compatible with later manylinuxes.
|
|
"""
|
|
wheel = f"fake-1.0-py2.py3-none-{wheel_abi}.whl"
|
|
fake_wheel(data, wheel)
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
platform,
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / wheel)
|
|
|
|
def test_explicit_platform_only(
|
|
self, data: TestData, script: PipTestEnvironment
|
|
) -> None:
|
|
"""
|
|
When specifying the platform, manylinux1 needs to be the
|
|
explicit platform--it won't ever be added to the compatible
|
|
tags.
|
|
"""
|
|
fake_wheel(data, "fake-1.0-py2.py3-none-linux_x86_64.whl")
|
|
script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--platform",
|
|
"linux_x86_64",
|
|
"fake",
|
|
)
|
|
|
|
|
|
def test_download__python_version(script: PipTestEnvironment, data: TestData) -> None:
|
|
"""
|
|
Test using "pip download --python-version" to download a .whl archive
|
|
supported for a specific interpreter
|
|
"""
|
|
fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--python-version",
|
|
"2",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--python-version",
|
|
"3",
|
|
"fake",
|
|
)
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--python-version",
|
|
"27",
|
|
"fake",
|
|
)
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--python-version",
|
|
"33",
|
|
"fake",
|
|
)
|
|
|
|
data.reset()
|
|
fake_wheel(data, "fake-1.0-py2-none-any.whl")
|
|
fake_wheel(data, "fake-2.0-py3-none-any.whl")
|
|
|
|
# No py3 provided for version 1.
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--python-version",
|
|
"3",
|
|
"fake==1.0",
|
|
expect_error=True,
|
|
)
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--python-version",
|
|
"2",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-py2-none-any.whl")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--python-version",
|
|
"26",
|
|
"fake",
|
|
)
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--python-version",
|
|
"3",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-2.0-py3-none-any.whl")
|
|
|
|
|
|
def make_wheel_with_python_requires(
|
|
script: PipTestEnvironment, package_name: str, python_requires: str
|
|
) -> Path:
|
|
"""
|
|
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()
|
|
|
|
text = textwrap.dedent(
|
|
"""\
|
|
from setuptools import setup
|
|
setup(name='{}',
|
|
python_requires='{}',
|
|
version='1.0')
|
|
"""
|
|
).format(package_name, python_requires)
|
|
package_dir.joinpath("setup.py").write_text(text)
|
|
script.run(
|
|
"python",
|
|
"setup.py",
|
|
"bdist_wheel",
|
|
"--universal",
|
|
cwd=package_dir,
|
|
)
|
|
|
|
file_name = f"{package_name}-1.0-py2.py3-none-any.whl"
|
|
return package_dir / "dist" / file_name
|
|
|
|
|
|
@pytest.mark.usefixtures("with_wheel")
|
|
def test_download__python_version_used_for_python_requires(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
Test that --python-version is used for the Requires-Python check.
|
|
"""
|
|
wheel_path = make_wheel_with_python_requires(
|
|
script,
|
|
"mypackage",
|
|
python_requires="==3.2",
|
|
)
|
|
wheel_dir = os.path.dirname(wheel_path)
|
|
|
|
def make_args(python_version: str) -> List[str]:
|
|
return [
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
wheel_dir,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--python-version",
|
|
python_version,
|
|
"mypackage==1.0",
|
|
]
|
|
|
|
args = make_args("33")
|
|
result = script.pip(*args, expect_error=True)
|
|
expected_err = (
|
|
"ERROR: Package 'mypackage' requires a different Python: "
|
|
"3.3.0 not in '==3.2'"
|
|
)
|
|
assert expected_err in result.stderr, f"stderr: {result.stderr}"
|
|
|
|
# Now try with a --python-version that satisfies the Requires-Python.
|
|
args = make_args("32")
|
|
script.pip(*args) # no exception
|
|
|
|
|
|
@pytest.mark.usefixtures("with_wheel")
|
|
def test_download_ignore_requires_python_dont_fail_with_wrong_python(
|
|
script: PipTestEnvironment,
|
|
) -> None:
|
|
"""
|
|
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",
|
|
)
|
|
result.did_create(Path("scratch") / "mypackage-1.0-py2.py3-none-any.whl")
|
|
|
|
|
|
def test_download_specify_abi(script: PipTestEnvironment, data: TestData) -> None:
|
|
"""
|
|
Test using "pip download --abi" to download a .whl archive
|
|
supported for a specific abi
|
|
"""
|
|
fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--implementation",
|
|
"fk",
|
|
"--abi",
|
|
"fake_abi",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--implementation",
|
|
"fk",
|
|
"--abi",
|
|
"none",
|
|
"fake",
|
|
)
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--abi",
|
|
"cp27m",
|
|
"fake",
|
|
)
|
|
|
|
data.reset()
|
|
fake_wheel(data, "fake-1.0-fk2-fakeabi-fake_platform.whl")
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--python-version",
|
|
"2",
|
|
"--implementation",
|
|
"fk",
|
|
"--platform",
|
|
"fake_platform",
|
|
"--abi",
|
|
"fakeabi",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-fk2-fakeabi-fake_platform.whl")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--implementation",
|
|
"fk",
|
|
"--platform",
|
|
"fake_platform",
|
|
"--abi",
|
|
"none",
|
|
"fake",
|
|
expect_error=True,
|
|
)
|
|
|
|
data.reset()
|
|
fake_wheel(data, "fake-1.0-fk2-otherabi-fake_platform.whl")
|
|
result = script.pip(
|
|
"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",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-fk2-otherabi-fake_platform.whl")
|
|
|
|
|
|
def test_download_specify_implementation(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
"""
|
|
Test using "pip download --abi" to download a .whl archive
|
|
supported for a specific abi
|
|
"""
|
|
fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--implementation",
|
|
"fk",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")
|
|
|
|
data.reset()
|
|
fake_wheel(data, "fake-1.0-fk3-none-any.whl")
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--implementation",
|
|
"fk",
|
|
"--python-version",
|
|
"3",
|
|
"fake",
|
|
)
|
|
result.did_create(Path("scratch") / "fake-1.0-fk3-none-any.whl")
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"--find-links",
|
|
data.find_links,
|
|
"--only-binary=:all:",
|
|
"--dest",
|
|
".",
|
|
"--implementation",
|
|
"fk",
|
|
"--python-version",
|
|
"2",
|
|
"fake",
|
|
expect_error=True,
|
|
)
|
|
|
|
|
|
def test_download_exit_status_code_when_no_requirements(
|
|
script: PipTestEnvironment,
|
|
) -> None:
|
|
"""
|
|
Test download exit status code when no requirements specified
|
|
"""
|
|
result = script.pip("download", expect_error=True)
|
|
assert "You must give at least one requirement to download" in result.stderr
|
|
assert result.returncode == ERROR
|
|
|
|
|
|
def test_download_exit_status_code_when_blank_requirements_file(
|
|
script: PipTestEnvironment,
|
|
) -> None:
|
|
"""
|
|
Test download exit status code when blank requirements file specified
|
|
"""
|
|
script.scratch_path.joinpath("blank.txt").write_text("\n")
|
|
script.pip("download", "-r", "blank.txt")
|
|
|
|
|
|
def test_download_prefer_binary_when_tarball_higher_than_wheel(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
|
|
result = script.pip(
|
|
"download",
|
|
"--prefer-binary",
|
|
"--no-index",
|
|
"-f",
|
|
data.packages,
|
|
"-d",
|
|
".",
|
|
"source",
|
|
)
|
|
result.did_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")
|
|
result.did_not_create(Path("scratch") / "source-1.0.tar.gz")
|
|
|
|
|
|
def test_prefer_binary_tarball_higher_than_wheel_req_file(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
|
|
script.scratch_path.joinpath("test-req.txt").write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
--prefer-binary
|
|
source
|
|
"""
|
|
)
|
|
)
|
|
result = script.pip(
|
|
"download",
|
|
"-r",
|
|
script.scratch_path / "test-req.txt",
|
|
"--no-index",
|
|
"-f",
|
|
data.packages,
|
|
"-d",
|
|
".",
|
|
)
|
|
|
|
result.did_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")
|
|
result.did_not_create(Path("scratch") / "source-1.0.tar.gz")
|
|
|
|
|
|
def test_download_prefer_binary_when_wheel_doesnt_satisfy_req(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
|
|
script.scratch_path.joinpath("test-req.txt").write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
source>0.9
|
|
"""
|
|
)
|
|
)
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--prefer-binary",
|
|
"--no-index",
|
|
"-f",
|
|
data.packages,
|
|
"-d",
|
|
".",
|
|
"-r",
|
|
script.scratch_path / "test-req.txt",
|
|
)
|
|
result.did_create(Path("scratch") / "source-1.0.tar.gz")
|
|
result.did_not_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")
|
|
|
|
|
|
def test_prefer_binary_when_wheel_doesnt_satisfy_req_req_file(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
|
|
script.scratch_path.joinpath("test-req.txt").write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
--prefer-binary
|
|
source>0.9
|
|
"""
|
|
)
|
|
)
|
|
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"-f",
|
|
data.packages,
|
|
"-d",
|
|
".",
|
|
"-r",
|
|
script.scratch_path / "test-req.txt",
|
|
)
|
|
result.did_create(Path("scratch") / "source-1.0.tar.gz")
|
|
result.did_not_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")
|
|
|
|
|
|
def test_download_prefer_binary_when_only_tarball_exists(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
result = script.pip(
|
|
"download",
|
|
"--prefer-binary",
|
|
"--no-index",
|
|
"-f",
|
|
data.packages,
|
|
"-d",
|
|
".",
|
|
"source",
|
|
)
|
|
result.did_create(Path("scratch") / "source-1.0.tar.gz")
|
|
|
|
|
|
def test_prefer_binary_when_only_tarball_exists_req_file(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
script.scratch_path.joinpath("test-req.txt").write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
--prefer-binary
|
|
source
|
|
"""
|
|
)
|
|
)
|
|
result = script.pip(
|
|
"download",
|
|
"--no-index",
|
|
"-f",
|
|
data.packages,
|
|
"-d",
|
|
".",
|
|
"-r",
|
|
script.scratch_path / "test-req.txt",
|
|
)
|
|
result.did_create(Path("scratch") / "source-1.0.tar.gz")
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def shared_script(
|
|
tmpdir_factory: pytest.TempPathFactory, script_factory: ScriptFactory
|
|
) -> PipTestEnvironment:
|
|
tmpdir = tmpdir_factory.mktemp("download_shared_script")
|
|
script = script_factory(tmpdir.joinpath("workspace"))
|
|
return script
|
|
|
|
|
|
def test_download_file_url(
|
|
shared_script: PipTestEnvironment, shared_data: TestData, tmpdir: Path
|
|
) -> None:
|
|
download_dir = tmpdir / "download"
|
|
download_dir.mkdir()
|
|
downloaded_path = download_dir / "simple-1.0.tar.gz"
|
|
|
|
simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
|
|
|
|
shared_script.pip(
|
|
"download",
|
|
"-d",
|
|
str(download_dir),
|
|
"--no-index",
|
|
simple_pkg.as_uri(),
|
|
)
|
|
|
|
assert downloaded_path.exists()
|
|
assert simple_pkg.read_bytes() == downloaded_path.read_bytes()
|
|
|
|
|
|
def test_download_file_url_existing_ok_download(
|
|
shared_script: PipTestEnvironment, shared_data: TestData, tmpdir: Path
|
|
) -> None:
|
|
download_dir = tmpdir / "download"
|
|
download_dir.mkdir()
|
|
downloaded_path = download_dir / "simple-1.0.tar.gz"
|
|
fake_existing_package = shared_data.packages / "simple-2.0.tar.gz"
|
|
shutil.copy(str(fake_existing_package), str(downloaded_path))
|
|
downloaded_path_bytes = downloaded_path.read_bytes()
|
|
|
|
simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
|
|
url = f"{simple_pkg.as_uri()}#sha256={sha256(downloaded_path_bytes).hexdigest()}"
|
|
|
|
shared_script.pip("download", "-d", str(download_dir), url)
|
|
|
|
assert downloaded_path_bytes == downloaded_path.read_bytes()
|
|
|
|
|
|
def test_download_file_url_existing_bad_download(
|
|
shared_script: PipTestEnvironment, shared_data: TestData, tmpdir: Path
|
|
) -> None:
|
|
download_dir = tmpdir / "download"
|
|
download_dir.mkdir()
|
|
downloaded_path = download_dir / "simple-1.0.tar.gz"
|
|
fake_existing_package = shared_data.packages / "simple-2.0.tar.gz"
|
|
shutil.copy(str(fake_existing_package), str(downloaded_path))
|
|
|
|
simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
|
|
simple_pkg_bytes = simple_pkg.read_bytes()
|
|
url = f"{simple_pkg.as_uri()}#sha256={sha256(simple_pkg_bytes).hexdigest()}"
|
|
|
|
shared_script.pip("download", "-d", str(download_dir), url)
|
|
|
|
assert simple_pkg_bytes == downloaded_path.read_bytes()
|
|
|
|
|
|
def test_download_http_url_bad_hash(
|
|
shared_script: PipTestEnvironment,
|
|
shared_data: TestData,
|
|
tmpdir: Path,
|
|
mock_server: MockServer,
|
|
) -> None:
|
|
"""
|
|
If already-downloaded file has bad checksum, re-download.
|
|
"""
|
|
download_dir = tmpdir / "download"
|
|
download_dir.mkdir()
|
|
downloaded_path = download_dir / "simple-1.0.tar.gz"
|
|
fake_existing_package = shared_data.packages / "simple-2.0.tar.gz"
|
|
shutil.copy(str(fake_existing_package), str(downloaded_path))
|
|
|
|
simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
|
|
simple_pkg_bytes = simple_pkg.read_bytes()
|
|
digest = sha256(simple_pkg_bytes).hexdigest()
|
|
mock_server.set_responses([file_response(simple_pkg)])
|
|
mock_server.start()
|
|
base_address = f"http://{mock_server.host}:{mock_server.port}"
|
|
url = f"{base_address}/simple-1.0.tar.gz#sha256={digest}"
|
|
|
|
shared_script.pip("download", "-d", str(download_dir), url)
|
|
|
|
assert simple_pkg_bytes == downloaded_path.read_bytes()
|
|
|
|
mock_server.stop()
|
|
requests = mock_server.get_requests()
|
|
assert len(requests) == 1
|
|
assert requests[0]["PATH_INFO"] == "/simple-1.0.tar.gz"
|
|
assert requests[0]["HTTP_ACCEPT_ENCODING"] == "identity"
|
|
|
|
|
|
def test_download_editable(
|
|
script: PipTestEnvironment, data: TestData, tmpdir: Path
|
|
) -> None:
|
|
"""
|
|
Test 'pip download' of editables in requirement file.
|
|
"""
|
|
editable_path = str(data.src / "simplewheel-1.0").replace(os.path.sep, "/")
|
|
requirements_path = tmpdir / "requirements.txt"
|
|
requirements_path.write_text("-e " + editable_path + "\n")
|
|
download_dir = tmpdir / "download_dir"
|
|
script.pip(
|
|
"download", "--no-deps", "-r", str(requirements_path), "-d", str(download_dir)
|
|
)
|
|
downloads = os.listdir(download_dir)
|
|
assert len(downloads) == 1
|
|
assert downloads[0].endswith(".zip")
|
|
|
|
|
|
def test_download_use_pep517_propagation(
|
|
script: PipTestEnvironment, tmpdir: Path, common_wheels: Path
|
|
) -> None:
|
|
"""
|
|
Check that --use-pep517 applies not just to the requirements specified
|
|
on the command line, but to their dependencies too.
|
|
"""
|
|
|
|
create_basic_sdist_for_package(script, "fake_proj", "1.0", depends=["fake_dep"])
|
|
|
|
# If --use-pep517 is in effect, then setup.py should be running in an isolated
|
|
# environment that doesn't have pip in it.
|
|
create_basic_sdist_for_package(
|
|
script,
|
|
"fake_dep",
|
|
"1.0",
|
|
setup_py_prelude=textwrap.dedent(
|
|
"""\
|
|
try:
|
|
import pip
|
|
except ImportError:
|
|
pass
|
|
else:
|
|
raise Exception(f"not running in isolation")
|
|
"""
|
|
),
|
|
)
|
|
|
|
download_dir = tmpdir / "download_dir"
|
|
script.pip(
|
|
"download",
|
|
f"--dest={download_dir}",
|
|
"--no-index",
|
|
f"--find-links={common_wheels}",
|
|
f"--find-links={script.scratch_path}",
|
|
"--use-pep517",
|
|
"fake_proj",
|
|
)
|
|
|
|
downloads = os.listdir(download_dir)
|
|
assert len(downloads) == 2
|