mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
Callable alias: fixed capturing stdout in case of redirect (#5527)
### Motivation Closes #5512. The issue was introduced in #4445. It's needed to add checking the redirect case. ### Before ```xsh cd /tmp @aliases.register('a') def _a(): print("1-hello") echo 2-hello a > o.txt # 2-hello cat o.txt # 1-hello ``` ### After ```xsh cd /tmp @aliases.register('a') def _a(): print("1-hello") echo 2-hello a > o.txt cat o.txt # 1-hello # 2-hello ``` ## For community ⬇️ **Please click the 👍 reaction instead of leaving a `+1` or 👍 comment** --------- Co-authored-by: a <1@1.1> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
6b30c3aae3
commit
61a77ac3ce
3 changed files with 61 additions and 8 deletions
23
news/callias_capture_redirect.rst
Normal file
23
news/callias_capture_redirect.rst
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
**Added:**
|
||||||
|
|
||||||
|
* <news item>
|
||||||
|
|
||||||
|
**Changed:**
|
||||||
|
|
||||||
|
* <news item>
|
||||||
|
|
||||||
|
**Deprecated:**
|
||||||
|
|
||||||
|
* <news item>
|
||||||
|
|
||||||
|
**Removed:**
|
||||||
|
|
||||||
|
* <news item>
|
||||||
|
|
||||||
|
**Fixed:**
|
||||||
|
|
||||||
|
* Callable alias: fixed capturing stdout in case of redirect e.g. `a > file` (#5527).
|
||||||
|
|
||||||
|
**Security:**
|
||||||
|
|
||||||
|
* <news item>
|
|
@ -150,6 +150,25 @@ def test_capture_always(
|
||||||
assert exp in capfd.readouterr().out
|
assert exp in capfd.readouterr().out
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_on_windows
|
||||||
|
@pytest.mark.flaky(reruns=3, reruns_delay=2)
|
||||||
|
def test_callias_captured_redirect(xonsh_session, tmpdir):
|
||||||
|
@xonsh_session.aliases.register("a")
|
||||||
|
def _a(a, i, o, e):
|
||||||
|
print("print_stdout")
|
||||||
|
xonsh_session.subproc_captured_stdout(["echo", "cap_stdout"])
|
||||||
|
xonsh_session.subproc_captured_object(["echo", "cap_object"])
|
||||||
|
xonsh_session.subproc_captured_hiddenobject(["echo", "hiddenobject"])
|
||||||
|
xonsh_session.subproc_uncaptured(["echo", "uncaptured"])
|
||||||
|
print("print_error", file=e)
|
||||||
|
|
||||||
|
f = tmpdir / "capture.txt"
|
||||||
|
cmd = (["a", (">", str(f))],)
|
||||||
|
specs = cmds_to_specs(cmd, captured="hiddenobject")
|
||||||
|
_run_command_pipeline(specs, cmd).end()
|
||||||
|
assert f.read_text(encoding="utf-8") == "print_stdout\nhiddenobject\n"
|
||||||
|
|
||||||
|
|
||||||
@skip_if_on_windows
|
@skip_if_on_windows
|
||||||
@pytest.mark.parametrize("captured", ["stdout", "object"])
|
@pytest.mark.parametrize("captured", ["stdout", "object"])
|
||||||
@pytest.mark.parametrize("interactive", [True, False])
|
@pytest.mark.parametrize("interactive", [True, False])
|
||||||
|
|
|
@ -1021,19 +1021,30 @@ def cmds_to_specs(cmds, captured=False, envs=None):
|
||||||
|
|
||||||
# Apply boundary conditions
|
# Apply boundary conditions
|
||||||
if not XSH.env.get("XONSH_CAPTURE_ALWAYS"):
|
if not XSH.env.get("XONSH_CAPTURE_ALWAYS"):
|
||||||
# Make sure sub-specs are always captured.
|
# Make sure sub-specs are always captured in case:
|
||||||
# I.e. ![some_alias | grep x] $(some_alias)
|
# `![some_alias | grep x]`, `$(some_alias)`, `some_alias > file`.
|
||||||
specs_to_capture = specs if captured in STDOUT_CAPTURE_KINDS else specs[:-1]
|
last = spec
|
||||||
for spec in specs_to_capture:
|
is_redirected_stdout = bool(last.stdout)
|
||||||
if spec.env is None:
|
specs_to_capture = (
|
||||||
spec.env = {"XONSH_CAPTURE_ALWAYS": True}
|
specs
|
||||||
else:
|
if captured in STDOUT_CAPTURE_KINDS or is_redirected_stdout
|
||||||
spec.env.setdefault("XONSH_CAPTURE_ALWAYS", True)
|
else specs[:-1]
|
||||||
|
)
|
||||||
|
_set_specs_capture_always(specs_to_capture)
|
||||||
|
|
||||||
_update_last_spec(specs[-1])
|
_update_last_spec(specs[-1])
|
||||||
return specs
|
return specs
|
||||||
|
|
||||||
|
|
||||||
|
def _set_specs_capture_always(specs_to_capture):
|
||||||
|
"""Set XONSH_CAPTURE_ALWAYS for all specs."""
|
||||||
|
for spec in specs_to_capture:
|
||||||
|
if spec.env is None:
|
||||||
|
spec.env = {"XONSH_CAPTURE_ALWAYS": True}
|
||||||
|
else:
|
||||||
|
spec.env.setdefault("XONSH_CAPTURE_ALWAYS", True)
|
||||||
|
|
||||||
|
|
||||||
def _shell_set_title(cmds):
|
def _shell_set_title(cmds):
|
||||||
if XSH.env.get("XONSH_INTERACTIVE") and XSH.shell is not None:
|
if XSH.env.get("XONSH_INTERACTIVE") and XSH.shell is not None:
|
||||||
# context manager updates the command information that gets
|
# context manager updates the command information that gets
|
||||||
|
|
Loading…
Add table
Reference in a new issue