Skip to content

Commit b74f1ae

Browse files
committed
Require every call_subprocess call-site to pass command_desc
This serves as additional context that can be presented in error messages.
1 parent 8770b48 commit b74f1ae

File tree

9 files changed

+63
-19
lines changed

9 files changed

+63
-19
lines changed

src/pip/_internal/build_env.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ def install_requirements(
189189
finder: "PackageFinder",
190190
requirements: Iterable[str],
191191
prefix_as_string: str,
192-
message: str,
192+
*,
193+
kind: str,
193194
) -> None:
194195
prefix = self._prefixes[prefix_as_string]
195196
assert not prefix.setup
@@ -203,7 +204,7 @@ def install_requirements(
203204
finder,
204205
requirements,
205206
prefix,
206-
message,
207+
kind=kind,
207208
)
208209

209210
@staticmethod
@@ -212,7 +213,8 @@ def _install_requirements(
212213
finder: "PackageFinder",
213214
requirements: Iterable[str],
214215
prefix: _Prefix,
215-
message: str,
216+
*,
217+
kind: str,
216218
) -> None:
217219
args: List[str] = [
218220
sys.executable,
@@ -254,8 +256,13 @@ def _install_requirements(
254256
args.append("--")
255257
args.extend(requirements)
256258
extra_environ = {"_PIP_STANDALONE_CERT": where()}
257-
with open_spinner(message) as spinner:
258-
call_subprocess(args, spinner=spinner, extra_environ=extra_environ)
259+
with open_spinner(f"Installing {kind}") as spinner:
260+
call_subprocess(
261+
args,
262+
command_desc=f"pip subprocess to install {kind}",
263+
spinner=spinner,
264+
extra_environ=extra_environ,
265+
)
259266

260267

261268
class NoOpBuildEnvironment(BuildEnvironment):
@@ -283,6 +290,7 @@ def install_requirements(
283290
finder: "PackageFinder",
284291
requirements: Iterable[str],
285292
prefix_as_string: str,
286-
message: str,
293+
*,
294+
kind: str,
287295
) -> None:
288296
raise NotImplementedError()

src/pip/_internal/distributions/sdist.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def _prepare_build_backend(self, finder: PackageFinder) -> None:
5656

5757
self.req.build_env = BuildEnvironment()
5858
self.req.build_env.install_requirements(
59-
finder, pyproject_requires, "overlay", "Installing build dependencies"
59+
finder, pyproject_requires, "overlay", kind="build dependencies"
6060
)
6161
conflicting, missing = self.req.build_env.check_requirements(
6262
self.req.requirements_to_check
@@ -108,7 +108,7 @@ def _install_build_reqs(self, finder: PackageFinder) -> None:
108108
if conflicting:
109109
self._raise_conflicts("the backend dependencies", conflicting)
110110
self.req.build_env.install_requirements(
111-
finder, missing, "normal", "Installing backend dependencies"
111+
finder, missing, "normal", kind="backend dependencies"
112112
)
113113

114114
def _raise_conflicts(

src/pip/_internal/operations/build/wheel_legacy.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def build_wheel_legacy(
8686
try:
8787
output = call_subprocess(
8888
wheel_args,
89+
command_desc="python setup.py bdist_wheel",
8990
cwd=source_dir,
9091
spinner=spinner,
9192
)

src/pip/_internal/operations/install/editable_legacy.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,6 @@ def install_editable(
4242
with build_env:
4343
call_subprocess(
4444
args,
45+
command_desc="python setup.py develop",
4546
cwd=unpacked_source_directory,
4647
)

src/pip/_internal/utils/subprocess.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,13 @@ def call_subprocess(
110110
cwd: Optional[str] = None,
111111
on_returncode: 'Literal["raise", "warn", "ignore"]' = "raise",
112112
extra_ok_returncodes: Optional[Iterable[int]] = None,
113-
command_desc: Optional[str] = None,
114113
extra_environ: Optional[Mapping[str, Any]] = None,
115114
unset_environ: Optional[Iterable[str]] = None,
116115
spinner: Optional[SpinnerInterface] = None,
117116
log_failed_cmd: Optional[bool] = True,
118117
stdout_only: Optional[bool] = False,
118+
*,
119+
command_desc: str,
119120
) -> str:
120121
"""
121122
Args:
@@ -166,9 +167,6 @@ def call_subprocess(
166167
# and we have a spinner.
167168
use_spinner = not showing_subprocess and spinner is not None
168169

169-
if command_desc is None:
170-
command_desc = format_command_args(cmd)
171-
172170
log_subprocess("Running command %s", command_desc)
173171
env = os.environ.copy()
174172
if extra_environ:
@@ -281,6 +279,7 @@ def runner(
281279
with open_spinner(message) as spinner:
282280
call_subprocess(
283281
cmd,
282+
command_desc=message,
284283
cwd=cwd,
285284
extra_environ=extra_environ,
286285
spinner=spinner,

src/pip/_internal/vcs/git.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,12 @@ def is_immutable_rev_checkout(self, url: str, dest: str) -> bool:
9191
return not is_tag_or_branch
9292

9393
def get_git_version(self) -> Tuple[int, ...]:
94-
version = self.run_command(["version"], show_stdout=False, stdout_only=True)
94+
version = self.run_command(
95+
["version"],
96+
command_desc="git version",
97+
show_stdout=False,
98+
stdout_only=True,
99+
)
95100
match = GIT_VERSION_REGEX.match(version)
96101
if not match:
97102
logger.warning("Can't parse git version: %s", version)

src/pip/_internal/vcs/versioncontrol.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@
3131
is_installable_dir,
3232
rmtree,
3333
)
34-
from pip._internal.utils.subprocess import CommandArgs, call_subprocess, make_command
34+
from pip._internal.utils.subprocess import (
35+
CommandArgs,
36+
call_subprocess,
37+
format_command_args,
38+
make_command,
39+
)
3540
from pip._internal.utils.urls import get_url_scheme
3641

3742
if TYPE_CHECKING:
@@ -634,6 +639,8 @@ def run_command(
634639
command name, and checks that the VCS is available
635640
"""
636641
cmd = make_command(cls.name, *cmd)
642+
if command_desc is None:
643+
command_desc = format_command_args(cmd)
637644
try:
638645
return call_subprocess(
639646
cmd,

src/pip/_internal/wheel_builder.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,9 @@ def _clean_one_legacy(req: InstallRequirement, global_options: List[str]) -> boo
310310

311311
logger.info("Running setup.py clean for %s", req.name)
312312
try:
313-
call_subprocess(clean_args, cwd=req.source_dir)
313+
call_subprocess(
314+
clean_args, command_desc="python setup.py clean", cwd=req.source_dir
315+
)
314316
return True
315317
except Exception:
316318
logger.error("Failed cleaning build dir for %s", req.name)

tests/unit/test_utils_subprocess.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ def test_call_subprocess_stdout_only(
163163
"-c",
164164
"import sys; sys.stdout.write('out\\n'); sys.stderr.write('err\\n')",
165165
],
166+
command_desc="test stdout_only",
166167
stdout_only=stdout_only,
167168
)
168169
assert out in expected
@@ -271,7 +272,11 @@ def test_debug_logging(
271272
"""
272273
log_level = DEBUG
273274
args, spinner = self.prepare_call(caplog, log_level)
274-
result = call_subprocess(args, spinner=spinner)
275+
result = call_subprocess(
276+
args,
277+
command_desc="test debug logging",
278+
spinner=spinner,
279+
)
275280

276281
expected = (
277282
["Hello", "world"],
@@ -301,7 +306,11 @@ def test_info_logging(
301306
"""
302307
log_level = INFO
303308
args, spinner = self.prepare_call(caplog, log_level)
304-
result = call_subprocess(args, spinner=spinner)
309+
result = call_subprocess(
310+
args,
311+
command_desc="test info logging",
312+
spinner=spinner,
313+
)
305314

306315
expected: Tuple[List[str], List[Tuple[str, int, str]]] = (
307316
["Hello", "world"],
@@ -331,7 +340,11 @@ def test_info_logging__subprocess_error(
331340
args, spinner = self.prepare_call(caplog, log_level, command=command)
332341

333342
with pytest.raises(InstallationSubprocessError) as exc:
334-
call_subprocess(args, spinner=spinner)
343+
call_subprocess(
344+
args,
345+
command_desc="test info logging with subprocess error",
346+
spinner=spinner,
347+
)
335348
result = None
336349
exc_message = str(exc.value)
337350
assert exc_message.startswith("Command errored out with exit status 1: ")
@@ -390,7 +403,12 @@ def test_info_logging_with_show_stdout_true(
390403
"""
391404
log_level = INFO
392405
args, spinner = self.prepare_call(caplog, log_level)
393-
result = call_subprocess(args, spinner=spinner, show_stdout=True)
406+
result = call_subprocess(
407+
args,
408+
command_desc="test info logging with show_stdout",
409+
spinner=spinner,
410+
show_stdout=True,
411+
)
394412

395413
expected = (
396414
["Hello", "world"],
@@ -456,6 +474,7 @@ def test_spinner_finish(
456474
try:
457475
call_subprocess(
458476
args,
477+
command_desc="spinner go spinny",
459478
show_stdout=show_stdout,
460479
extra_ok_returncodes=extra_ok_returncodes,
461480
spinner=spinner,
@@ -474,6 +493,7 @@ def test_closes_stdin(self) -> None:
474493
call_subprocess(
475494
[sys.executable, "-c", "input()"],
476495
show_stdout=True,
496+
command_desc="stdin reader",
477497
)
478498

479499

@@ -487,6 +507,7 @@ def test_unicode_decode_error(caplog: pytest.LogCaptureFixture) -> None:
487507
"-c",
488508
"import sys; sys.stdout.buffer.write(b'\\xff')",
489509
],
510+
command_desc="invalid decode output",
490511
show_stdout=True,
491512
)
492513

0 commit comments

Comments
 (0)