Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/1293.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix run command with bash substitution (e.g. `pipx run <(pbpaste)`)
9 changes: 6 additions & 3 deletions src/pipx/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,15 @@
def maybe_script_content(app: str, is_path: bool) -> Optional[Union[str, Path]]:
# If the app is a script, return its content.
# Return None if it should be treated as a package name.

# Look for a local file first.
# Look for a local file first
app_path = Path(app)
if app_path.is_file():
return app_path
elif is_path:
# In case it's a named pipe, read it out to pass to the interpreter
if app_path.is_fifo():
return app_path.read_text(encoding="utf-8")

if is_path:
raise PipxError(f"The specified path {app} does not exist")

# Check for a URL
Expand Down
29 changes: 29 additions & 0 deletions tests/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,35 @@ def test_run_script_by_relative_name(caplog, pipx_temp_env, monkeypatch, tmp_pat
assert out.read_text() == test_str


@mock.patch("os.execvpe", new=execvpe_mock)
@pytest.mark.skipif(sys.platform.startswith("win"), reason="uses file descriptor")
def test_run_script_by_file_descriptor(caplog, pipx_temp_env, monkeypatch, tmp_path):
read_fd, write_fd = os.pipe()
out = tmp_path / "output.txt"
test_str = "Hello, world!"

os.write(
write_fd,
textwrap.dedent(
f"""
from pathlib import Path
Path({repr(str(out))}).write_text({repr(test_str)})
"""
)
.strip()
.encode("utf-8"),
)
os.close(write_fd)

with monkeypatch.context() as m:
m.chdir(tmp_path)
try:
run_pipx_cli_exit(["run", f"/dev/fd/{read_fd}"])
finally:
os.close(read_fd)
assert out.read_text() == test_str


@pytest.mark.skipif(not sys.platform.startswith("win"), reason="uses windows version format")
@mock.patch("os.execvpe", new=execvpe_mock)
def test_run_with_windows_python_version(caplog, pipx_temp_env, tmp_path):
Expand Down