Skip to content

Commit

Permalink
Merge pull request #12494 from sbidoul/pass-config-settings-to-editab…
Browse files Browse the repository at this point in the history
…le-in-req-file-sbi

Support per-requirement --config-settings for editables
  • Loading branch information
sbidoul committed Jan 31, 2024
2 parents ff30ba8 + 1f48ca3 commit 99a82b7
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 26 deletions.
1 change: 1 addition & 0 deletions news/12480.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support per requirement options for editable installs.
48 changes: 25 additions & 23 deletions src/pip/_internal/req/req_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,16 @@
cmdoptions.config_settings,
]

SUPPORTED_OPTIONS_EDITABLE_REQ: List[Callable[..., optparse.Option]] = [
cmdoptions.config_settings,
]


# the 'dest' string values
SUPPORTED_OPTIONS_REQ_DEST = [str(o().dest) for o in SUPPORTED_OPTIONS_REQ]
SUPPORTED_OPTIONS_EDITABLE_REQ_DEST = [
str(o().dest) for o in SUPPORTED_OPTIONS_EDITABLE_REQ
]

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -178,31 +186,25 @@ def handle_requirement_line(

assert line.is_requirement

# get the options that apply to requirements
if line.is_editable:
# For editable requirements, we don't support per-requirement
# options, so just return the parsed requirement.
return ParsedRequirement(
requirement=line.requirement,
is_editable=line.is_editable,
comes_from=line_comes_from,
constraint=line.constraint,
)
supported_dest = SUPPORTED_OPTIONS_EDITABLE_REQ_DEST
else:
# get the options that apply to requirements
req_options = {}
for dest in SUPPORTED_OPTIONS_REQ_DEST:
if dest in line.opts.__dict__ and line.opts.__dict__[dest]:
req_options[dest] = line.opts.__dict__[dest]

line_source = f"line {line.lineno} of {line.filename}"
return ParsedRequirement(
requirement=line.requirement,
is_editable=line.is_editable,
comes_from=line_comes_from,
constraint=line.constraint,
options=req_options,
line_source=line_source,
)
supported_dest = SUPPORTED_OPTIONS_REQ_DEST
req_options = {}
for dest in supported_dest:
if dest in line.opts.__dict__ and line.opts.__dict__[dest]:
req_options[dest] = line.opts.__dict__[dest]

line_source = f"line {line.lineno} of {line.filename}"
return ParsedRequirement(
requirement=line.requirement,
is_editable=line.is_editable,
comes_from=line_comes_from,
constraint=line.constraint,
options=req_options,
line_source=line_source,
)


def handle_option_line(
Expand Down
42 changes: 39 additions & 3 deletions tests/functional/test_pep660.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
with open("log.txt", "a") as f:
print(":build_wheel called", file=f)
print(f":build_wheel called with config_settings={config_settings}", file=f)
return _build_wheel(wheel_directory, config_settings, metadata_directory)
"""

Expand All @@ -55,7 +55,7 @@ def prepare_metadata_for_build_editable(metadata_directory, config_settings=None
def build_editable(wheel_directory, config_settings=None, metadata_directory=None):
with open("log.txt", "a") as f:
print(":build_editable called", file=f)
print(f":build_editable called with config_settings={config_settings}", file=f)
return _build_wheel(wheel_directory, config_settings, metadata_directory)
"""
# fmt: on
Expand Down Expand Up @@ -88,6 +88,16 @@ def _assert_hook_called(project_dir: Path, hook: str) -> None:
assert f":{hook} called" in log, f"{hook} has not been called"


def _assert_hook_called_with_config_settings(
project_dir: Path, hook: str, config_settings: Dict[str, str]
) -> None:
log = project_dir.joinpath("log.txt").read_text()
assert f":{hook} called" in log, f"{hook} has not been called"
assert (
f":{hook} called with config_settings={config_settings}" in log
), f"{hook} has not been called with the expected config settings:\n{log}"


def _assert_hook_not_called(project_dir: Path, hook: str) -> None:
log = project_dir.joinpath("log.txt").read_text()
assert f":{hook} called" not in log, f"{hook} should not have been called"
Expand Down Expand Up @@ -119,9 +129,35 @@ def test_install_pep660_basic(tmpdir: Path, script: PipTestEnvironment) -> None:
"--no-build-isolation",
"--editable",
project_dir,
"--config-setting",
"x=y",
)
_assert_hook_called(project_dir, "prepare_metadata_for_build_editable")
_assert_hook_called_with_config_settings(project_dir, "build_editable", {"x": "y"})
assert (
result.test_env.site_packages.joinpath("project.egg-link")
not in result.files_created
), "a .egg-link file should not have been created"


def test_install_pep660_from_reqs_file(
tmpdir: Path, script: PipTestEnvironment
) -> None:
"""
Test with backend that supports build_editable.
"""
project_dir = _make_project(tmpdir, BACKEND_WITH_PEP660, with_setup_py=False)
reqs_file = tmpdir / "requirements.txt"
reqs_file.write_text(f"-e {project_dir.as_uri()} --config-setting x=y\n")
result = script.pip(
"install",
"--no-index",
"--no-build-isolation",
"-r",
reqs_file,
)
_assert_hook_called(project_dir, "prepare_metadata_for_build_editable")
_assert_hook_called(project_dir, "build_editable")
_assert_hook_called_with_config_settings(project_dir, "build_editable", {"x": "y"})
assert (
result.test_env.site_packages.joinpath("project.egg-link")
not in result.files_created
Expand Down

0 comments on commit 99a82b7

Please sign in to comment.