Skip to content

Commit 99a82b7

Browse files
authored
Merge pull request #12494 from sbidoul/pass-config-settings-to-editable-in-req-file-sbi
Support per-requirement --config-settings for editables
2 parents ff30ba8 + 1f48ca3 commit 99a82b7

File tree

3 files changed

+65
-26
lines changed

3 files changed

+65
-26
lines changed

news/12480.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support per requirement options for editable installs.

src/pip/_internal/req/req_file.py

+25-23
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,16 @@
7575
cmdoptions.config_settings,
7676
]
7777

78+
SUPPORTED_OPTIONS_EDITABLE_REQ: List[Callable[..., optparse.Option]] = [
79+
cmdoptions.config_settings,
80+
]
81+
82+
7883
# the 'dest' string values
7984
SUPPORTED_OPTIONS_REQ_DEST = [str(o().dest) for o in SUPPORTED_OPTIONS_REQ]
85+
SUPPORTED_OPTIONS_EDITABLE_REQ_DEST = [
86+
str(o().dest) for o in SUPPORTED_OPTIONS_EDITABLE_REQ
87+
]
8088

8189
logger = logging.getLogger(__name__)
8290

@@ -178,31 +186,25 @@ def handle_requirement_line(
178186

179187
assert line.is_requirement
180188

189+
# get the options that apply to requirements
181190
if line.is_editable:
182-
# For editable requirements, we don't support per-requirement
183-
# options, so just return the parsed requirement.
184-
return ParsedRequirement(
185-
requirement=line.requirement,
186-
is_editable=line.is_editable,
187-
comes_from=line_comes_from,
188-
constraint=line.constraint,
189-
)
191+
supported_dest = SUPPORTED_OPTIONS_EDITABLE_REQ_DEST
190192
else:
191-
# get the options that apply to requirements
192-
req_options = {}
193-
for dest in SUPPORTED_OPTIONS_REQ_DEST:
194-
if dest in line.opts.__dict__ and line.opts.__dict__[dest]:
195-
req_options[dest] = line.opts.__dict__[dest]
196-
197-
line_source = f"line {line.lineno} of {line.filename}"
198-
return ParsedRequirement(
199-
requirement=line.requirement,
200-
is_editable=line.is_editable,
201-
comes_from=line_comes_from,
202-
constraint=line.constraint,
203-
options=req_options,
204-
line_source=line_source,
205-
)
193+
supported_dest = SUPPORTED_OPTIONS_REQ_DEST
194+
req_options = {}
195+
for dest in supported_dest:
196+
if dest in line.opts.__dict__ and line.opts.__dict__[dest]:
197+
req_options[dest] = line.opts.__dict__[dest]
198+
199+
line_source = f"line {line.lineno} of {line.filename}"
200+
return ParsedRequirement(
201+
requirement=line.requirement,
202+
is_editable=line.is_editable,
203+
comes_from=line_comes_from,
204+
constraint=line.constraint,
205+
options=req_options,
206+
line_source=line_source,
207+
)
206208

207209

208210
def handle_option_line(

tests/functional/test_pep660.py

+39-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
3737
3838
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
3939
with open("log.txt", "a") as f:
40-
print(":build_wheel called", file=f)
40+
print(f":build_wheel called with config_settings={config_settings}", file=f)
4141
return _build_wheel(wheel_directory, config_settings, metadata_directory)
4242
"""
4343

@@ -55,7 +55,7 @@ def prepare_metadata_for_build_editable(metadata_directory, config_settings=None
5555
5656
def build_editable(wheel_directory, config_settings=None, metadata_directory=None):
5757
with open("log.txt", "a") as f:
58-
print(":build_editable called", file=f)
58+
print(f":build_editable called with config_settings={config_settings}", file=f)
5959
return _build_wheel(wheel_directory, config_settings, metadata_directory)
6060
"""
6161
# fmt: on
@@ -88,6 +88,16 @@ def _assert_hook_called(project_dir: Path, hook: str) -> None:
8888
assert f":{hook} called" in log, f"{hook} has not been called"
8989

9090

91+
def _assert_hook_called_with_config_settings(
92+
project_dir: Path, hook: str, config_settings: Dict[str, str]
93+
) -> None:
94+
log = project_dir.joinpath("log.txt").read_text()
95+
assert f":{hook} called" in log, f"{hook} has not been called"
96+
assert (
97+
f":{hook} called with config_settings={config_settings}" in log
98+
), f"{hook} has not been called with the expected config settings:\n{log}"
99+
100+
91101
def _assert_hook_not_called(project_dir: Path, hook: str) -> None:
92102
log = project_dir.joinpath("log.txt").read_text()
93103
assert f":{hook} called" not in log, f"{hook} should not have been called"
@@ -119,9 +129,35 @@ def test_install_pep660_basic(tmpdir: Path, script: PipTestEnvironment) -> None:
119129
"--no-build-isolation",
120130
"--editable",
121131
project_dir,
132+
"--config-setting",
133+
"x=y",
134+
)
135+
_assert_hook_called(project_dir, "prepare_metadata_for_build_editable")
136+
_assert_hook_called_with_config_settings(project_dir, "build_editable", {"x": "y"})
137+
assert (
138+
result.test_env.site_packages.joinpath("project.egg-link")
139+
not in result.files_created
140+
), "a .egg-link file should not have been created"
141+
142+
143+
def test_install_pep660_from_reqs_file(
144+
tmpdir: Path, script: PipTestEnvironment
145+
) -> None:
146+
"""
147+
Test with backend that supports build_editable.
148+
"""
149+
project_dir = _make_project(tmpdir, BACKEND_WITH_PEP660, with_setup_py=False)
150+
reqs_file = tmpdir / "requirements.txt"
151+
reqs_file.write_text(f"-e {project_dir.as_uri()} --config-setting x=y\n")
152+
result = script.pip(
153+
"install",
154+
"--no-index",
155+
"--no-build-isolation",
156+
"-r",
157+
reqs_file,
122158
)
123159
_assert_hook_called(project_dir, "prepare_metadata_for_build_editable")
124-
_assert_hook_called(project_dir, "build_editable")
160+
_assert_hook_called_with_config_settings(project_dir, "build_editable", {"x": "y"})
125161
assert (
126162
result.test_env.site_packages.joinpath("project.egg-link")
127163
not in result.files_created

0 commit comments

Comments
 (0)