mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
819 lines
26 KiB
Python
819 lines
26 KiB
Python
import json
|
|
import os
|
|
import textwrap
|
|
from pathlib import Path
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
import pytest
|
|
|
|
from tests.lib import (
|
|
PipTestEnvironment,
|
|
ResolverVariant,
|
|
TestData,
|
|
_create_test_package_with_subdirectory,
|
|
create_basic_sdist_for_package,
|
|
create_basic_wheel_for_package,
|
|
need_svn,
|
|
requirements_file,
|
|
)
|
|
from tests.lib.local_repos import local_checkout
|
|
|
|
if TYPE_CHECKING:
|
|
from typing import Protocol
|
|
else:
|
|
Protocol = object
|
|
|
|
|
|
class ArgRecordingSdist:
|
|
def __init__(self, sdist_path: Path, args_path: Path) -> None:
|
|
self.sdist_path = sdist_path
|
|
self._args_path = args_path
|
|
|
|
def args(self) -> Any:
|
|
return json.loads(self._args_path.read_text())
|
|
|
|
|
|
class ArgRecordingSdistMaker(Protocol):
|
|
def __call__(self, name: str, **kwargs: Any) -> ArgRecordingSdist:
|
|
...
|
|
|
|
|
|
@pytest.fixture()
|
|
def arg_recording_sdist_maker(
|
|
script: PipTestEnvironment,
|
|
) -> ArgRecordingSdistMaker:
|
|
arg_writing_setup_py_prelude = textwrap.dedent(
|
|
"""
|
|
import io
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
args_path = os.path.join(os.environ["OUTPUT_DIR"], "{name}.json")
|
|
with open(args_path, 'w') as f:
|
|
json.dump(sys.argv, f)
|
|
"""
|
|
)
|
|
output_dir = script.scratch_path.joinpath("args_recording_sdist_maker_output")
|
|
output_dir.mkdir(parents=True)
|
|
script.environ["OUTPUT_DIR"] = str(output_dir)
|
|
|
|
def _arg_recording_sdist_maker(
|
|
name: str,
|
|
**kwargs: Any,
|
|
) -> ArgRecordingSdist:
|
|
sdist_path = create_basic_sdist_for_package(
|
|
script,
|
|
name,
|
|
"0.1.0",
|
|
setup_py_prelude=arg_writing_setup_py_prelude.format(name=name),
|
|
**kwargs,
|
|
)
|
|
args_path = output_dir / f"{name}.json"
|
|
return ArgRecordingSdist(sdist_path, args_path)
|
|
|
|
return _arg_recording_sdist_maker
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_requirements_file(script: PipTestEnvironment) -> None:
|
|
"""
|
|
Test installing from a requirements file.
|
|
|
|
"""
|
|
other_lib_name, other_lib_version = "peppercorn", "0.6"
|
|
script.scratch_path.joinpath("initools-req.txt").write_text(
|
|
textwrap.dedent(
|
|
f"""\
|
|
INITools==0.2
|
|
# and something else to test out:
|
|
{other_lib_name}<={other_lib_version}
|
|
"""
|
|
)
|
|
)
|
|
result = script.pip("install", "-r", script.scratch_path / "initools-req.txt")
|
|
result.did_create(script.site_packages / "INITools-0.2.dist-info")
|
|
result.did_create(script.site_packages / "initools")
|
|
assert result.files_created[script.site_packages / other_lib_name].dir
|
|
fn = "{}-{}.dist-info".format(other_lib_name, other_lib_version)
|
|
assert result.files_created[script.site_packages / fn].dir
|
|
|
|
|
|
def test_schema_check_in_requirements_file(script: PipTestEnvironment) -> None:
|
|
"""
|
|
Test installing from a requirements file with an invalid vcs schema..
|
|
|
|
"""
|
|
script.scratch_path.joinpath("file-egg-req.txt").write_text(
|
|
"\n{}\n".format(
|
|
"git://github.com/alex/django-fixture-generator.git"
|
|
"#egg=fixture_generator"
|
|
)
|
|
)
|
|
|
|
with pytest.raises(AssertionError):
|
|
script.pip("install", "-vvv", "-r", script.scratch_path / "file-egg-req.txt")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"test_type,editable",
|
|
[
|
|
("rel_path", False),
|
|
("rel_path", True),
|
|
("rel_url", False),
|
|
("rel_url", True),
|
|
("embedded_rel_path", False),
|
|
("embedded_rel_path", True),
|
|
],
|
|
)
|
|
def test_relative_requirements_file(
|
|
script: PipTestEnvironment, data: TestData, test_type: str, editable: bool
|
|
) -> None:
|
|
"""
|
|
Test installing from a requirements file with a relative path. For path
|
|
URLs, use an egg= definition.
|
|
|
|
"""
|
|
dist_info_folder = script.site_packages / "FSPkg-0.1.dev0.dist-info"
|
|
egg_link_file = script.site_packages / "FSPkg.egg-link"
|
|
package_folder = script.site_packages / "fspkg"
|
|
|
|
# Compute relative install path to FSPkg from scratch path.
|
|
full_rel_path = os.path.relpath(
|
|
data.packages.joinpath("FSPkg"), script.scratch_path
|
|
)
|
|
full_rel_url = "file:" + full_rel_path + "#egg=FSPkg"
|
|
embedded_rel_path = script.scratch_path.joinpath(full_rel_path)
|
|
|
|
req_path = {
|
|
"rel_path": full_rel_path,
|
|
"rel_url": full_rel_url,
|
|
"embedded_rel_path": os.fspath(embedded_rel_path),
|
|
}[test_type]
|
|
|
|
req_path = req_path.replace(os.path.sep, "/")
|
|
# Install as either editable or not.
|
|
if not editable:
|
|
with requirements_file(req_path + "\n", script.scratch_path) as reqs_file:
|
|
result = script.pip(
|
|
"install", "-vvv", "-r", reqs_file.name, cwd=script.scratch_path
|
|
)
|
|
result.did_create(dist_info_folder)
|
|
result.did_create(package_folder)
|
|
else:
|
|
with requirements_file(
|
|
"-e " + req_path + "\n", script.scratch_path
|
|
) as reqs_file:
|
|
result = script.pip(
|
|
"install", "-vvv", "-r", reqs_file.name, cwd=script.scratch_path
|
|
)
|
|
result.did_create(egg_link_file)
|
|
|
|
|
|
@pytest.mark.xfail
|
|
@pytest.mark.network
|
|
@need_svn
|
|
def test_multiple_requirements_files(script: PipTestEnvironment, tmpdir: Path) -> None:
|
|
"""
|
|
Test installing from multiple nested requirements files.
|
|
|
|
"""
|
|
other_lib_name, other_lib_version = "six", "1.16.0"
|
|
script.scratch_path.joinpath("initools-req.txt").write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
-e {}@10#egg=INITools
|
|
-r {}-req.txt
|
|
"""
|
|
).format(
|
|
local_checkout("svn+http://svn.colorstudy.com/INITools", tmpdir),
|
|
other_lib_name,
|
|
),
|
|
)
|
|
script.scratch_path.joinpath(f"{other_lib_name}-req.txt").write_text(
|
|
f"{other_lib_name}<={other_lib_version}"
|
|
)
|
|
result = script.pip("install", "-r", script.scratch_path / "initools-req.txt")
|
|
assert result.files_created[script.site_packages / other_lib_name].dir
|
|
fn = f"{other_lib_name}-{other_lib_version}.dist-info"
|
|
assert result.files_created[script.site_packages / fn].dir
|
|
result.did_create(script.venv / "src" / "initools")
|
|
|
|
|
|
def test_package_in_constraints_and_dependencies(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
script.scratch_path.joinpath("constraints.txt").write_text(
|
|
"TopoRequires2==0.0.1\nTopoRequires==0.0.1"
|
|
)
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
"TopoRequires2",
|
|
)
|
|
assert "installed TopoRequires-0.0.1" in result.stdout
|
|
|
|
|
|
def test_multiple_constraints_files(script: PipTestEnvironment, data: TestData) -> None:
|
|
script.scratch_path.joinpath("outer.txt").write_text("-c inner.txt")
|
|
script.scratch_path.joinpath("inner.txt").write_text("Upper==1.0")
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"-c",
|
|
script.scratch_path / "outer.txt",
|
|
"Upper",
|
|
)
|
|
assert "installed Upper-1.0" in result.stdout
|
|
|
|
|
|
# FIXME: Unclear what this guarantee is for.
|
|
def test_respect_order_in_requirements_file(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
script.scratch_path.joinpath("frameworks-req.txt").write_text(
|
|
textwrap.dedent(
|
|
"""\
|
|
parent
|
|
child
|
|
simple
|
|
"""
|
|
)
|
|
)
|
|
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"-r",
|
|
script.scratch_path / "frameworks-req.txt",
|
|
)
|
|
|
|
downloaded = [line for line in result.stdout.split("\n") if "Processing" in line]
|
|
|
|
assert (
|
|
"parent" in downloaded[0]
|
|
), 'First download should be "parent" but was "{}"'.format(downloaded[0])
|
|
assert (
|
|
"child" in downloaded[1]
|
|
), 'Second download should be "child" but was "{}"'.format(downloaded[1])
|
|
assert (
|
|
"simple" in downloaded[2]
|
|
), 'Third download should be "simple" but was "{}"'.format(downloaded[2])
|
|
|
|
|
|
def test_install_local_editable_with_extras(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
to_install = data.packages.joinpath("LocalExtras")
|
|
res = script.pip_install_local(
|
|
"-e", f"{to_install}[bar]", allow_stderr_warning=True
|
|
)
|
|
res.did_update(script.site_packages / "easy-install.pth")
|
|
res.did_create(script.site_packages / "LocalExtras.egg-link")
|
|
res.did_create(script.site_packages / "simple")
|
|
|
|
|
|
def test_install_collected_dependencies_first(script: PipTestEnvironment) -> None:
|
|
result = script.pip_install_local(
|
|
"toporequires2",
|
|
)
|
|
text = [line for line in result.stdout.split("\n") if "Installing" in line][0]
|
|
assert text.endswith("toporequires2")
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_install_local_editable_with_subdirectory(script: PipTestEnvironment) -> None:
|
|
version_pkg_path = _create_test_package_with_subdirectory(script, "version_subdir")
|
|
result = script.pip(
|
|
"install",
|
|
"-e",
|
|
"{uri}#egg=version_subpkg&subdirectory=version_subdir".format(
|
|
uri=f"git+{version_pkg_path.as_uri()}",
|
|
),
|
|
)
|
|
|
|
result.assert_installed("version-subpkg", sub_dir="version_subdir")
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_install_local_with_subdirectory(script: PipTestEnvironment) -> None:
|
|
version_pkg_path = _create_test_package_with_subdirectory(script, "version_subdir")
|
|
result = script.pip(
|
|
"install",
|
|
"{uri}#egg=version_subpkg&subdirectory=version_subdir".format(
|
|
uri=f"git+{version_pkg_path.as_uri()}",
|
|
),
|
|
)
|
|
|
|
result.assert_installed("version_subpkg.py", editable=False)
|
|
|
|
|
|
@pytest.mark.usefixtures("enable_user_site")
|
|
def test_wheel_user_with_prefix_in_pydistutils_cfg(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
if os.name == "posix":
|
|
user_filename = ".pydistutils.cfg"
|
|
else:
|
|
user_filename = "pydistutils.cfg"
|
|
user_cfg = os.path.join(os.path.expanduser("~"), user_filename)
|
|
script.scratch_path.joinpath("bin").mkdir()
|
|
with open(user_cfg, "w") as cfg:
|
|
cfg.write(
|
|
textwrap.dedent(
|
|
f"""
|
|
[install]
|
|
prefix={script.scratch_path}"""
|
|
)
|
|
)
|
|
|
|
result = script.pip(
|
|
"install", "--user", "--no-index", "-f", data.find_links, "requiresupper"
|
|
)
|
|
# Check that we are really installing a wheel
|
|
assert "installed requiresupper" in result.stdout
|
|
|
|
|
|
def test_constraints_not_installed_by_default(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
script.scratch_path.joinpath("c.txt").write_text("requiresupper")
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"-c",
|
|
script.scratch_path / "c.txt",
|
|
"Upper",
|
|
)
|
|
assert "requiresupper" not in result.stdout
|
|
|
|
|
|
def test_constraints_only_causes_error(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
script.scratch_path.joinpath("c.txt").write_text("requiresupper")
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"-c",
|
|
script.scratch_path / "c.txt",
|
|
expect_error=True,
|
|
)
|
|
assert "installed requiresupper" not in result.stdout
|
|
|
|
|
|
def test_constraints_local_editable_install_causes_error(
|
|
script: PipTestEnvironment,
|
|
data: TestData,
|
|
resolver_variant: ResolverVariant,
|
|
) -> None:
|
|
script.scratch_path.joinpath("constraints.txt").write_text("singlemodule==0.0.0")
|
|
to_install = data.src.joinpath("singlemodule")
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
"-e",
|
|
to_install,
|
|
expect_error=True,
|
|
)
|
|
if resolver_variant == "legacy-resolver":
|
|
assert "Could not satisfy constraints" in result.stderr, str(result)
|
|
else:
|
|
# Because singlemodule only has 0.0.1 available.
|
|
assert "Cannot install singlemodule 0.0.1" in result.stderr, str(result)
|
|
|
|
|
|
@pytest.mark.network
|
|
def test_constraints_local_editable_install_pep518(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
to_install = data.src.joinpath("pep518-3.0")
|
|
|
|
script.pip("download", "setuptools", "wheel", "-d", data.packages)
|
|
script.pip("install", "--no-index", "-f", data.find_links, "-e", to_install)
|
|
|
|
|
|
def test_constraints_local_install_causes_error(
|
|
script: PipTestEnvironment,
|
|
data: TestData,
|
|
resolver_variant: ResolverVariant,
|
|
) -> None:
|
|
script.scratch_path.joinpath("constraints.txt").write_text("singlemodule==0.0.0")
|
|
to_install = data.src.joinpath("singlemodule")
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
to_install,
|
|
expect_error=True,
|
|
)
|
|
if resolver_variant == "legacy-resolver":
|
|
assert "Could not satisfy constraints" in result.stderr, str(result)
|
|
else:
|
|
# Because singlemodule only has 0.0.1 available.
|
|
assert "Cannot install singlemodule 0.0.1" in result.stderr, str(result)
|
|
|
|
|
|
def test_constraints_constrain_to_local_editable(
|
|
script: PipTestEnvironment,
|
|
data: TestData,
|
|
resolver_variant: ResolverVariant,
|
|
) -> None:
|
|
to_install = data.src.joinpath("singlemodule")
|
|
script.scratch_path.joinpath("constraints.txt").write_text(
|
|
f"-e {to_install.as_uri()}#egg=singlemodule"
|
|
)
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
"singlemodule",
|
|
allow_stderr_warning=True,
|
|
expect_error=(resolver_variant == "2020-resolver"),
|
|
)
|
|
if resolver_variant == "2020-resolver":
|
|
assert "Editable requirements are not allowed as constraints" in result.stderr
|
|
else:
|
|
assert "Running setup.py develop for singlemodule" in result.stdout
|
|
|
|
|
|
def test_constraints_constrain_to_local(
|
|
script: PipTestEnvironment, data: TestData, resolver_variant: ResolverVariant
|
|
) -> None:
|
|
to_install = data.src.joinpath("singlemodule")
|
|
script.scratch_path.joinpath("constraints.txt").write_text(
|
|
f"{to_install.as_uri()}#egg=singlemodule"
|
|
)
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
"singlemodule",
|
|
allow_stderr_warning=True,
|
|
)
|
|
assert "Building wheel for singlemodule" in result.stdout
|
|
|
|
|
|
def test_constrained_to_url_install_same_url(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
to_install = data.src.joinpath("singlemodule")
|
|
constraints = f"{to_install.as_uri()}#egg=singlemodule"
|
|
script.scratch_path.joinpath("constraints.txt").write_text(constraints)
|
|
result = script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
data.find_links,
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
to_install,
|
|
allow_stderr_warning=True,
|
|
)
|
|
assert "Building wheel for singlemodule" in result.stdout, str(result)
|
|
|
|
|
|
def test_double_install_spurious_hash_mismatch(
|
|
script: PipTestEnvironment, tmpdir: Path, data: TestData
|
|
) -> None:
|
|
"""Make sure installing the same hashed sdist twice doesn't throw hash
|
|
mismatch errors.
|
|
|
|
Really, this is a test that we disable reads from the wheel cache in
|
|
hash-checking mode. Locally, implicitly built wheels of sdists obviously
|
|
have different hashes from the original archives. Comparing against those
|
|
causes spurious mismatch errors.
|
|
|
|
"""
|
|
# Install wheel package, otherwise, it won't try to build wheels.
|
|
with requirements_file(
|
|
"simple==1.0 --hash=sha256:393043e672415891885c9a2a"
|
|
"0929b1af95fb866d6ca016b42d2e6ce53619b653",
|
|
tmpdir,
|
|
) as reqs_file:
|
|
# Install a package (and build its wheel):
|
|
result = script.pip_install_local(
|
|
"--find-links",
|
|
data.find_links,
|
|
"-r",
|
|
reqs_file.resolve(),
|
|
)
|
|
assert "Successfully installed simple-1.0" in str(result)
|
|
|
|
# Uninstall it:
|
|
script.pip("uninstall", "-y", "simple")
|
|
|
|
# Then install it again. We should not hit a hash mismatch, and the
|
|
# package should install happily.
|
|
result = script.pip_install_local(
|
|
"--find-links",
|
|
data.find_links,
|
|
"-r",
|
|
reqs_file.resolve(),
|
|
)
|
|
assert "Successfully installed simple-1.0" in str(result)
|
|
|
|
|
|
def test_install_with_extras_from_constraints(
|
|
script: PipTestEnvironment, data: TestData, resolver_variant: ResolverVariant
|
|
) -> None:
|
|
to_install = data.packages.joinpath("LocalExtras")
|
|
script.scratch_path.joinpath("constraints.txt").write_text(
|
|
f"{to_install.as_uri()}#egg=LocalExtras[bar]"
|
|
)
|
|
result = script.pip_install_local(
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
"LocalExtras",
|
|
allow_stderr_warning=True,
|
|
expect_error=(resolver_variant == "2020-resolver"),
|
|
)
|
|
if resolver_variant == "2020-resolver":
|
|
assert "Constraints cannot have extras" in result.stderr
|
|
else:
|
|
result.did_create(script.site_packages / "simple")
|
|
|
|
|
|
def test_install_with_extras_from_install(script: PipTestEnvironment) -> None:
|
|
create_basic_wheel_for_package(
|
|
script,
|
|
name="LocalExtras",
|
|
version="0.0.1",
|
|
extras={"bar": ["simple"], "baz": ["singlemodule"]},
|
|
)
|
|
script.scratch_path.joinpath("constraints.txt").write_text("LocalExtras")
|
|
result = script.pip_install_local(
|
|
"--find-links",
|
|
script.scratch_path,
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
"LocalExtras[baz]",
|
|
)
|
|
result.did_create(script.site_packages / "singlemodule.py")
|
|
|
|
|
|
def test_install_with_extras_joined(
|
|
script: PipTestEnvironment, data: TestData, resolver_variant: ResolverVariant
|
|
) -> None:
|
|
to_install = data.packages.joinpath("LocalExtras")
|
|
script.scratch_path.joinpath("constraints.txt").write_text(
|
|
f"{to_install.as_uri()}#egg=LocalExtras[bar]"
|
|
)
|
|
result = script.pip_install_local(
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
"LocalExtras[baz]",
|
|
allow_stderr_warning=True,
|
|
expect_error=(resolver_variant == "2020-resolver"),
|
|
)
|
|
if resolver_variant == "2020-resolver":
|
|
assert "Constraints cannot have extras" in result.stderr
|
|
else:
|
|
result.did_create(script.site_packages / "simple")
|
|
result.did_create(script.site_packages / "singlemodule.py")
|
|
|
|
|
|
def test_install_with_extras_editable_joined(
|
|
script: PipTestEnvironment, data: TestData, resolver_variant: ResolverVariant
|
|
) -> None:
|
|
to_install = data.packages.joinpath("LocalExtras")
|
|
script.scratch_path.joinpath("constraints.txt").write_text(
|
|
f"-e {to_install.as_uri()}#egg=LocalExtras[bar]"
|
|
)
|
|
result = script.pip_install_local(
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
"LocalExtras[baz]",
|
|
allow_stderr_warning=True,
|
|
expect_error=(resolver_variant == "2020-resolver"),
|
|
)
|
|
if resolver_variant == "2020-resolver":
|
|
assert "Editable requirements are not allowed as constraints" in result.stderr
|
|
else:
|
|
result.did_create(script.site_packages / "simple")
|
|
result.did_create(script.site_packages / "singlemodule.py")
|
|
|
|
|
|
def test_install_distribution_full_union(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
to_install = data.packages.joinpath("LocalExtras")
|
|
result = script.pip_install_local(
|
|
to_install, f"{to_install}[bar]", f"{to_install}[baz]"
|
|
)
|
|
assert "Building wheel for LocalExtras" in result.stdout
|
|
result.did_create(script.site_packages / "simple")
|
|
result.did_create(script.site_packages / "singlemodule.py")
|
|
|
|
|
|
def test_install_distribution_duplicate_extras(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
to_install = data.packages.joinpath("LocalExtras")
|
|
package_name = f"{to_install}[bar]"
|
|
with pytest.raises(AssertionError):
|
|
result = script.pip_install_local(package_name, package_name)
|
|
expected = f"Double requirement given: {package_name}"
|
|
assert expected in result.stderr
|
|
|
|
|
|
def test_install_distribution_union_with_constraints(
|
|
script: PipTestEnvironment,
|
|
data: TestData,
|
|
resolver_variant: ResolverVariant,
|
|
) -> None:
|
|
to_install = data.packages.joinpath("LocalExtras")
|
|
script.scratch_path.joinpath("constraints.txt").write_text(f"{to_install}[bar]")
|
|
result = script.pip_install_local(
|
|
"-c",
|
|
script.scratch_path / "constraints.txt",
|
|
f"{to_install}[baz]",
|
|
allow_stderr_warning=True,
|
|
expect_error=(resolver_variant == "2020-resolver"),
|
|
)
|
|
if resolver_variant == "2020-resolver":
|
|
msg = "Unnamed requirements are not allowed as constraints"
|
|
assert msg in result.stderr
|
|
else:
|
|
assert "Building wheel for LocalExtras" in result.stdout
|
|
result.did_create(script.site_packages / "singlemodule.py")
|
|
|
|
|
|
def test_install_distribution_union_with_versions(
|
|
script: PipTestEnvironment,
|
|
data: TestData,
|
|
resolver_variant: ResolverVariant,
|
|
) -> None:
|
|
to_install_001 = data.packages.joinpath("LocalExtras")
|
|
to_install_002 = data.packages.joinpath("LocalExtras-0.0.2")
|
|
result = script.pip_install_local(
|
|
f"{to_install_001}[bar]",
|
|
f"{to_install_002}[baz]",
|
|
expect_error=(resolver_variant == "2020-resolver"),
|
|
)
|
|
if resolver_variant == "2020-resolver":
|
|
assert "Cannot install localextras[bar]" in result.stderr
|
|
assert ("localextras[bar] 0.0.1 depends on localextras 0.0.1") in result.stdout
|
|
assert ("localextras[baz] 0.0.2 depends on localextras 0.0.2") in result.stdout
|
|
else:
|
|
assert (
|
|
"Successfully installed LocalExtras-0.0.1 simple-3.0 singlemodule-0.0.1"
|
|
) in result.stdout
|
|
|
|
|
|
@pytest.mark.xfail
|
|
def test_install_distribution_union_conflicting_extras(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
# LocalExtras requires simple==1.0, LocalExtras[bar] requires simple==2.0;
|
|
# without a resolver, pip does not detect the conflict between simple==1.0
|
|
# and simple==2.0. Once a resolver is added, this conflict should be
|
|
# detected.
|
|
to_install = data.packages.joinpath("LocalExtras-0.0.2")
|
|
result = script.pip_install_local(
|
|
to_install, f"{to_install}[bar]", expect_error=True
|
|
)
|
|
assert "installed" not in result.stdout
|
|
assert "Conflict" in result.stderr
|
|
|
|
|
|
def test_install_unsupported_wheel_link_with_marker(script: PipTestEnvironment) -> None:
|
|
script.scratch_path.joinpath("with-marker.txt").write_text(
|
|
textwrap.dedent(
|
|
"""\
|
|
{url}; {req}
|
|
"""
|
|
).format(
|
|
url="https://github.com/a/b/c/asdf-1.5.2-cp27-none-xyz.whl",
|
|
req='sys_platform == "xyz"',
|
|
)
|
|
)
|
|
result = script.pip("install", "-r", script.scratch_path / "with-marker.txt")
|
|
|
|
assert (
|
|
"Ignoring asdf: markers 'sys_platform == \"xyz\"' don't match "
|
|
"your environment"
|
|
) in result.stdout
|
|
assert len(result.files_created) == 0
|
|
|
|
|
|
def test_install_unsupported_wheel_file(
|
|
script: PipTestEnvironment, data: TestData
|
|
) -> None:
|
|
# Trying to install a local wheel with an incompatible version/type
|
|
# should fail.
|
|
path = data.packages.joinpath("simple.dist-0.1-py1-none-invalid.whl")
|
|
script.scratch_path.joinpath("wheel-file.txt").write_text(f"{path}\n")
|
|
result = script.pip(
|
|
"install",
|
|
"-r",
|
|
script.scratch_path / "wheel-file.txt",
|
|
expect_error=True,
|
|
expect_stderr=True,
|
|
)
|
|
assert (
|
|
"simple.dist-0.1-py1-none-invalid.whl is not a supported wheel on this platform"
|
|
in result.stderr
|
|
)
|
|
assert len(result.files_created) == 0
|
|
|
|
|
|
def test_config_settings_local_to_package(
|
|
script: PipTestEnvironment,
|
|
common_wheels: Path,
|
|
arg_recording_sdist_maker: ArgRecordingSdistMaker,
|
|
) -> None:
|
|
pyproject_toml = textwrap.dedent(
|
|
"""
|
|
[build-system]
|
|
requires = ["setuptools"]
|
|
build-backend = "setuptools.build_meta"
|
|
"""
|
|
)
|
|
simple0_sdist = arg_recording_sdist_maker(
|
|
"simple0",
|
|
extra_files={"pyproject.toml": pyproject_toml},
|
|
depends=["foo"],
|
|
)
|
|
foo_sdist = arg_recording_sdist_maker(
|
|
"foo",
|
|
extra_files={"pyproject.toml": pyproject_toml},
|
|
)
|
|
simple1_sdist = arg_recording_sdist_maker(
|
|
"simple1",
|
|
extra_files={"pyproject.toml": pyproject_toml},
|
|
depends=["bar"],
|
|
)
|
|
bar_sdist = arg_recording_sdist_maker(
|
|
"bar",
|
|
extra_files={"pyproject.toml": pyproject_toml},
|
|
depends=["simple3"],
|
|
)
|
|
simple3_sdist = arg_recording_sdist_maker(
|
|
"simple3", extra_files={"pyproject.toml": pyproject_toml}
|
|
)
|
|
simple2_sdist = arg_recording_sdist_maker(
|
|
"simple2",
|
|
extra_files={"pyproject.toml": pyproject_toml},
|
|
)
|
|
|
|
reqs_file = script.scratch_path.joinpath("reqs.txt")
|
|
reqs_file.write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
simple0 --config-settings "--build-option=--verbose"
|
|
foo --config-settings "--build-option=--quiet"
|
|
simple1 --config-settings "--build-option=--verbose"
|
|
simple2
|
|
"""
|
|
)
|
|
)
|
|
|
|
script.pip(
|
|
"install",
|
|
"--no-index",
|
|
"-f",
|
|
script.scratch_path,
|
|
"-f",
|
|
common_wheels,
|
|
"-r",
|
|
reqs_file,
|
|
)
|
|
|
|
simple0_args = simple0_sdist.args()
|
|
assert "--verbose" in simple0_args
|
|
foo_args = foo_sdist.args()
|
|
assert "--quiet" in foo_args
|
|
simple1_args = simple1_sdist.args()
|
|
assert "--verbose" in simple1_args
|
|
bar_args = bar_sdist.args()
|
|
assert "--verbose" not in bar_args
|
|
simple3_args = simple3_sdist.args()
|
|
assert "--verbose" not in simple3_args
|
|
simple2_args = simple2_sdist.args()
|
|
assert "--verbose" not in simple2_args
|