pip/tests/functional/test_fast_deps.py

139 lines
4.2 KiB
Python

import fnmatch
import json
import os
import pathlib
import re
from os.path import basename
from typing import Iterable
from pip._vendor.packaging.utils import canonicalize_name
from pytest import mark
from pip._internal.utils.misc import hash_file
from tests.lib import PipTestEnvironment, TestData, TestPipResult
def pip(script: PipTestEnvironment, command: str, requirement: str) -> TestPipResult:
return script.pip(
command,
"--prefer-binary",
"--no-cache-dir",
"--use-feature=fast-deps",
requirement,
allow_stderr_warning=True,
)
def assert_installed(script: PipTestEnvironment, names: str) -> None:
list_output = json.loads(script.pip("list", "--format=json").stdout)
installed = {canonicalize_name(item["name"]) for item in list_output}
assert installed.issuperset(map(canonicalize_name, names))
@mark.network
@mark.parametrize(
("requirement", "expected"),
(
("Paste==3.4.2", ("Paste", "six")),
("Paste[flup]==3.4.2", ("Paste", "six", "flup")),
),
)
def test_install_from_pypi(
requirement: str, expected: str, script: PipTestEnvironment
) -> None:
pip(script, "install", requirement)
assert_installed(script, expected)
@mark.network
@mark.parametrize(
("requirement", "expected"),
(
("Paste==3.4.2", ("Paste-3.4.2-*.whl", "six-*.whl")),
("Paste[flup]==3.4.2", ("Paste-3.4.2-*.whl", "six-*.whl", "flup-*")),
),
)
def test_download_from_pypi(
requirement: str, expected: Iterable[str], script: PipTestEnvironment
) -> None:
result = pip(script, "download", requirement)
created = [basename(f) for f in result.files_created]
assert all(fnmatch.filter(created, f) for f in expected)
@mark.network
def test_build_wheel_with_deps(data: TestData, script: PipTestEnvironment) -> None:
result = pip(script, "wheel", os.fspath(data.packages / "requiresPaste"))
created = [basename(f) for f in result.files_created]
assert fnmatch.filter(created, "requirespaste-3.1.4-*.whl")
assert fnmatch.filter(created, "Paste-3.4.2-*.whl")
assert fnmatch.filter(created, "six-*.whl")
@mark.network
def test_require_hash(script: PipTestEnvironment, tmp_path: pathlib.Path) -> None:
reqs = tmp_path / "requirements.txt"
reqs.write_text(
"idna==2.10"
" --hash=sha256:"
"b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
" --hash=sha256:"
"b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"
)
result = script.pip(
"download",
"--use-feature=fast-deps",
"-r",
str(reqs),
allow_stderr_warning=True,
)
created = [basename(f) for f in result.files_created]
assert fnmatch.filter(created, "idna-2.10*")
@mark.network
def test_hash_mismatch(script: PipTestEnvironment, tmp_path: pathlib.Path) -> None:
reqs = tmp_path / "requirements.txt"
reqs.write_text("idna==2.10 --hash=sha256:irna")
result = script.pip(
"download",
"--use-feature=fast-deps",
"-r",
str(reqs),
expect_error=True,
)
assert "DO NOT MATCH THE HASHES" in result.stderr
@mark.network
def test_hash_mismatch_existing_download_for_metadata_only_wheel(
script: PipTestEnvironment, tmp_path: pathlib.Path
) -> None:
"""Metadata-only wheels from PEP 658 or fast-deps check for hash matching in
a separate code path than when the wheel is downloaded all at once. Make sure we
still check for hash mismatches."""
reqs = tmp_path / "requirements.txt"
reqs.write_text("idna==2.10")
dl_dir = tmp_path / "downloads"
dl_dir.mkdir()
idna_wheel = dl_dir / "idna-2.10-py2.py3-none-any.whl"
idna_wheel.write_text("asdf")
result = script.pip(
"download",
# Ensure that we have a metadata-only dist for idna.
"--use-feature=fast-deps",
"-r",
str(reqs),
"-d",
str(dl_dir),
allow_stderr_warning=True,
)
assert re.search(
r"WARNING: Previously-downloaded file.*has bad hash", result.stderr
)
# This is the correct hash for idna==2.10.
assert (
hash_file(str(idna_wheel))[0].hexdigest()
== "b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
)