Skip to content

Commit 18a0784

Browse files
henryiiiflying-sheeppre-commit-ci[bot]
authored
fix: nicer tracebacks in run mode on scripts (#1191)
Co-authored-by: Philipp A. <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 6918c4d commit 18a0784

File tree

3 files changed

+34
-7
lines changed

3 files changed

+34
-7
lines changed

changelog.d/1191.fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Report correct filename in tracebacks with `pipx run <scriptname>`

src/pipx/commands/run.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import urllib.request
99
from pathlib import Path
1010
from shutil import which
11-
from typing import List, NoReturn, Optional
11+
from typing import List, NoReturn, Optional, Union
1212

1313
from packaging.requirements import InvalidRequirement, Requirement
1414

@@ -42,14 +42,14 @@
4242
{app_lines}"""
4343

4444

45-
def maybe_script_content(app: str, is_path: bool) -> Optional[str]:
45+
def maybe_script_content(app: str, is_path: bool) -> Optional[Union[str, Path]]:
4646
# If the app is a script, return its content.
4747
# Return None if it should be treated as a package name.
4848

4949
# Look for a local file first.
5050
app_path = Path(app)
5151
if app_path.is_file():
52-
return app_path.read_text(encoding="utf-8")
52+
return app_path
5353
elif is_path:
5454
raise PipxError(f"The specified path {app} does not exist")
5555

@@ -71,7 +71,7 @@ def maybe_script_content(app: str, is_path: bool) -> Optional[str]:
7171

7272

7373
def run_script(
74-
content: str,
74+
content: Union[str, Path],
7575
app_args: List[str],
7676
python: str,
7777
pip_args: List[str],
@@ -81,7 +81,7 @@ def run_script(
8181
) -> NoReturn:
8282
requirements = _get_requirements_from_script(content)
8383
if requirements is None:
84-
exec_app([python, "-c", content, *app_args])
84+
python_path = Path(python)
8585
else:
8686
# Note that the environment name is based on the identified
8787
# requirements, and *not* on the script name. This is deliberate, as
@@ -99,7 +99,12 @@ def run_script(
9999
venv = Venv(venv_dir, python=python, verbose=verbose)
100100
venv.create_venv(venv_args, pip_args)
101101
venv.install_unmanaged_packages(requirements, pip_args)
102-
exec_app([venv.python_path, "-c", content, *app_args])
102+
python_path = venv.python_path
103+
104+
if isinstance(content, Path):
105+
exec_app([python_path, content, *app_args])
106+
else:
107+
exec_app([python_path, "-c", content, *app_args])
103108

104109

105110
def run_package(
@@ -323,11 +328,14 @@ def _http_get_request(url: str) -> str:
323328
INLINE_SCRIPT_METADATA = re.compile(r"(?m)^# /// (?P<type>[a-zA-Z0-9-]+)$\s(?P<content>(^#(| .*)$\s)+)^# ///$")
324329

325330

326-
def _get_requirements_from_script(content: str) -> Optional[List[str]]:
331+
def _get_requirements_from_script(content: Union[str, Path]) -> Optional[List[str]]:
327332
"""
328333
Supports inline script metadata.
329334
"""
330335

336+
if isinstance(content, Path):
337+
content = content.read_text(encoding="utf-8")
338+
331339
name = "script"
332340

333341
# Windows is currently getting un-normalized line endings, so normalize

tests/test_run.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,24 @@ def test_run_with_requirements_old(caplog, pipx_temp_env, tmp_path):
243243
run_pipx_cli_exit(["run", script.as_uri()])
244244

245245

246+
@mock.patch("os.execvpe", new=execvpe_mock)
247+
def test_run_correct_traceback(capfd, pipx_temp_env, tmp_path):
248+
script = tmp_path / "test.py"
249+
script.write_text(
250+
textwrap.dedent(
251+
"""
252+
raise RuntimeError("Should fail")
253+
"""
254+
).strip()
255+
)
256+
257+
with pytest.raises(SystemExit):
258+
run_pipx_cli(["run", str(script)])
259+
260+
captured = capfd.readouterr()
261+
assert "test.py" in captured.err
262+
263+
246264
@mock.patch("os.execvpe", new=execvpe_mock)
247265
def test_run_with_args(caplog, pipx_temp_env, tmp_path):
248266
script = tmp_path / "test.py"

0 commit comments

Comments
 (0)