Provides a wrapper that traces sub-process output, if captured.
Before:
import subprocess
result = subprocess.run(
"echo error message >&2 && exit 1", shell=True, capture_output=True, check=True
)
Since the stderr output of the sub-process has been captured, we only see the command and exit code:
$ python t.py
Traceback (most recent call last):
File "t.py", line 3, in <module>
result = subprocess.run(
File "lib/python3.8/subprocess.py", line 512, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command 'echo error message >&2 && exit 1' returned non-zero exit status 1.
After:
import subprocess
from subprocess_check import output_in_errors
with output_in_errors():
result = subprocess.run(
"echo error message >&2 && exit 1", shell=True, capture_output=True, check=True
)
The stdout/stderr is traced right next to the exit code and command:
$ python t.py
Traceback (most recent call last):
File "t.py", line 6, in <module>
result = subprocess.run(
File "lib/python3.8/site-packages/subprocess_check/_util.py", line 108, in wrap_subprocess_exception
raise CalledProcessErrorWithOutput(exc_value).with_traceback(tb) from None
File "lib/python3.8/subprocess.py", line 512, in run
raise CalledProcessError(retcode, process.args,
subprocess_check._util.CalledProcessErrorWithOutput: Command 'echo error message >&2 && exit 1' returned non-zero exit status 1. Output captured:
stdout: None
stderr:
error message
- Manual error handling/formatting:
- ➕ customizable formatting
- ➕ no dependencies
- ➖ ad-hoc code may not be tested as thoroughly
- Don't capture stderr:
- ➕ no dependencies
- ➖ output to terminal in non-error case may be verbose, if sub-process stderr outputs regardless
- ➖ if the error is re-raised after other operations, which output corresponds to the failed sub-process may not be nearby, or obvious
- Wrap subprocess.run instead of using a context manager
- ➕ no need to pass
capture_output=True, check=True
- ➖ IDEs do not understand "transparent function wrappers" well, so autocomplete and type hints are compromised
- ➕ no need to pass