Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement set -e alternative #5311

Open
ading2210 opened this issue Mar 24, 2024 · 5 comments
Open

Implement set -e alternative #5311

ading2210 opened this issue Mar 24, 2024 · 5 comments

Comments

@ading2210
Copy link

ading2210 commented Mar 24, 2024

xonfig

$ xonfig
+------------------+-----------------+
| xonsh            | 0.15.1          |
| Python           | 3.11.2          |
| PLY              | 3.11            |
| have readline    | True            |
| prompt toolkit   | None            |
| shell type       | readline        |
| history backend  | json            |
| pygments         | None            |
| on posix         | True            |
| on linux         | True            |
| distro           | unknown         |
| on wsl           | False           |
| on darwin        | False           |
| on windows       | False           |
| on cygwin        | False           |
| on msys2         | False           |
| is superuser     | False           |
| default encoding | utf-8           |
| xonsh encoding   | utf-8           |
| encoding errors  | surrogateescape |
| xontrib          | []              |
| RC file          | []              |
+------------------+-----------------+

Expected Behavior

In bash, doing cmd || true will ignore any errors that the command generates if set -e is on. I would expect that the behavior is similar in Xonsh with $RAISE_SUBPROC_ERROR, which is the equivalent setting.

For example:

bash

bash -c "
set -e
false || true
echo "success"
"
# success

Current Behavior

A subprocess.CalledProcessError is called if any of the commands in the expression fail.

Traceback (if applicable)

xonsh 

$RAISE_SUBPROC_ERROR = True
$XONSH_SHOW_TRACEBACK = True
false || true
# <xonsh-code>:1:0:6 - false || true
# <xonsh-code>:1:0:6 + ![false]
# <xonsh-code>:1:8:14 - false || true
# <xonsh-code>:1:8:14 + ![true]
# xonsh: To log full traceback to a file set: $XONSH_TRACEBACK_LOGFILE = <filename>
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/.local/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/built_ins.py", line 206, in subproc_captured_hiddenobject
    return xonsh.procs.specs.run_subproc(cmds, captured="hiddenobject", envs=envs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/.local/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/procs/specs.py", line 908, in run_subproc
    return _run_specs(specs, cmds)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/.local/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/procs/specs.py", line 943, in _run_specs
    command.end()
  File "/home/user/.local/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/procs/pipelines.py", line 459, in end
    self._end(tee_output=tee_output)
  File "/home/user/.local/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/procs/pipelines.py", line 478, in _end
    self._raise_subproc_error()
  File "/home/user/.local/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/procs/pipelines.py", line 603, in _raise_subproc_error
    raise subprocess.CalledProcessError(rtn, spec.args, output=self.output)
subprocess.CalledProcessError: Command '['false']' returned non-zero exit status 1.

Steps to Reproduce

  1. Open xonsh
  2. Run $RAISE_SUBPROC_ERROR = True
  3. Run false || true

For community

⬇️ Please click the 👍 reaction instead of leaving a +1 or 👍 comment

@anki-code
Copy link
Member

anki-code commented Mar 24, 2024

Indeed, $RAISE_SUBPROC_ERROR is to raise error in any case when any command fails but set -e treat the line as whole:

Exit immediately if a pipeline (see Pipelines), which may consist of a single simple command (see Simple Commands), a list (see Lists of Commands), or a compound command (see Compound Commands) returns a non-zero status.

So we need additional setting e.g. $XONSH_RAISE_SUBPROC_PIPELINE_ERROR to do the same as bash. PR is welcome!

@anki-code anki-code changed the title $RAISE_SUBPROC_ERROR throws an exception even if a logical OR is used Implement set -e alternative Mar 24, 2024
@anki-code
Copy link
Member

anki-code commented Mar 25, 2024

JFYI. For this:

set -e
ls nonono || true     # false || true
echo "success"

the xonsh equvalent for now is this:

$RAISE_SUBPROC_ERROR = True
try:
    ls nonono
except:               # OR except subprocess.CalledProcessError:
    pass
echo "success"

@anki-code
Copy link
Member

anki-code commented Mar 25, 2024

You can create syntax sugar for this using macro call:

import subprocess
def ignore_error(cmd):
    """Ignore failing of the command."""
    try:
        execx(cmd)
    except subprocess.CalledProcessError:
        pass
        
        
$RAISE_SUBPROC_ERROR = False      
ignore_error!(echo 1 and (ls nonono or echo 2))
echo success
# success
        
$RAISE_SUBPROC_ERROR = True        
ignore_error!(echo 1 and (ls nonono or echo 2))
echo success
# success

@ading2210
Copy link
Author

ading2210 commented Mar 25, 2024

I'm aware that I can do a try-except block to ignore errors, though that still doesn't help with the underlying problem of boolean logic being broken with subprocess return codes.

@anki-code anki-code added the error label May 4, 2024
@anki-code
Copy link
Member

anki-code commented May 20, 2024

I figured this out the case.

What bash doing. In fact it implicitly overrides the execution of a logical expression and the execution of process. If we run echo 1 and ls nonono the result of this logical will be treated as "return code" and if it's not 0 and set -e the error will be raised.

In xonsh we have separation between process running and logical expression running. If we run echo 1 and ls nonono we have 2 separate processes and logical expression and RAISE_SUBPROC_ERROR will work on process level.

In fact in this issue was requested an additional mode like RAISE_COMMAND_ERROR that will work for the whole logical expression.

Current behavior:

$RAISE_SUBPROC_ERROR=False
echo 1 and (ls no or echo 2)
# run logical: `echo 1`, `ls no`, `echo 2`.
__xonsh__.history[-1]
# rtn=0
echo 1 and (echo 2 or ls no)
# run logical: `echo 1`, `echo 2`.
__xonsh__.history[-1]
# rtn=0

$RAISE_SUBPROC_ERROR=True
echo 1 and (ls no or echo 2)
# run logical: `echo 1`, `ls no` (raise and stop).
__xonsh__.history[-1]
# rtn=2
echo 1 and (echo 2 or ls no)
# run logical: `echo 1`, `echo 2`.
__xonsh__.history[-1]
# rtn=0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants