1
1
Fork 0
mirror of https://github.com/pypa/pip synced 2023-12-13 21:30:23 +01:00
pip/tests/functional/test_install_reqs.py
Tzu-ping Chung 50e194f107 Selectively enable user site
The modern virtual environment structure does not allow us to enable
"fake user site" while disabling the global site, so we need to do more
fine-grained configuration to correctly set up test environments for
each test case.

With this done, we can also properly support the stdlib venv ad the test
environment backend, since it basically works identically with modern
virtualenv. The incompatible_with_test_venv is thus removed.
2022-10-28 01:51:13 +08:00

820 lines
26 KiB
Python

import json
import os
import textwrap
from pathlib import Path
from typing import Any, Callable
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
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())
@pytest.fixture()
def arg_recording_sdist_maker(
script: PipTestEnvironment,
) -> Callable[[str], ArgRecordingSdist]:
arg_writing_setup_py = textwrap.dedent(
"""
import io
import json
import os
import sys
from setuptools import setup
args_path = os.path.join(os.environ["OUTPUT_DIR"], "{name}.json")
with open(args_path, 'w') as f:
json.dump(sys.argv, f)
setup(name={name!r}, version="0.1.0")
"""
)
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) -> ArgRecordingSdist:
extra_files = {"setup.py": arg_writing_setup_py.format(name=name)}
sdist_path = create_basic_sdist_for_package(script, name, "0.1.0", extra_files)
args_path = output_dir / f"{name}.json"
return ArgRecordingSdist(sdist_path, args_path)
return _arg_recording_sdist_maker
@pytest.mark.network
@pytest.mark.usefixtures("with_wheel")
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),
],
)
@pytest.mark.usefixtures("with_wheel")
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
@pytest.mark.usefixtures("with_wheel")
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", "with_wheel")
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 "Running setup.py install for requiresupper" not in result.stdout
assert "installed requiresupper" in result.stdout
def test_install_option_in_requirements_file_overrides_cli(
script: PipTestEnvironment,
arg_recording_sdist_maker: Callable[[str], ArgRecordingSdist],
) -> None:
simple_sdist = arg_recording_sdist_maker("simple")
reqs_file = script.scratch_path.joinpath("reqs.txt")
reqs_file.write_text("simple --install-option='-O0'")
result = script.pip(
"install",
"--no-index",
"-f",
str(simple_sdist.sdist_path.parent),
"-r",
str(reqs_file),
"--install-option=-O1",
allow_stderr_warning=True,
)
simple_args = simple_sdist.args()
assert "install" in simple_args
assert simple_args.index("-O1") < simple_args.index("-O0")
assert "Implying --no-binary=:all:" in result.stderr
assert "Consider using --config-settings" in result.stderr
assert "--install-option is deprecated" in result.stderr
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 "Running setup.py install 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 "Running setup.py install for singlemodule" in result.stdout, str(result)
@pytest.mark.usefixtures("with_wheel")
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 "Running setup.py install 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 "Running setup.py install 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_install_options_local_to_package(
script: PipTestEnvironment,
arg_recording_sdist_maker: Callable[[str], ArgRecordingSdist],
) -> None:
"""Make sure --install-options does not leak across packages.
A requirements.txt file can have per-package --install-options; these
should be isolated to just the package instead of leaking to subsequent
packages. This needs to be a functional test because the bug was around
cross-contamination at install time.
"""
simple1_sdist = arg_recording_sdist_maker("simple1")
simple2_sdist = arg_recording_sdist_maker("simple2")
reqs_file = script.scratch_path.joinpath("reqs.txt")
reqs_file.write_text(
textwrap.dedent(
"""
simple1 --install-option='-O0'
simple2
"""
)
)
script.pip(
"install",
"--no-index",
"-f",
str(simple1_sdist.sdist_path.parent),
"-r",
reqs_file,
allow_stderr_warning=True,
)
simple1_args = simple1_sdist.args()
assert "install" in simple1_args
assert "-O0" in simple1_args
simple2_args = simple2_sdist.args()
assert "install" in simple2_args
assert "-O0" not in simple2_args
def test_location_related_install_option_fails(script: PipTestEnvironment) -> None:
simple_sdist = create_basic_sdist_for_package(script, "simple", "0.1.0")
reqs_file = script.scratch_path.joinpath("reqs.txt")
reqs_file.write_text("simple --install-option='--home=/tmp'")
result = script.pip(
"install",
"--no-index",
"-f",
str(simple_sdist.parent),
"-r",
reqs_file,
expect_error=True,
)
assert "['--home'] from simple" in result.stderr