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

Python 2: Non-ASCII characters in stderr or stdout during non-zero exit result in exception with no message #463

Closed
mjpieters opened this issue Feb 4, 2019 · 1 comment · Fixed by #467

Comments

@mjpieters
Copy link

mjpieters commented Feb 4, 2019

The sh ErrorReturnCode exception class sets the exception message to a Unicode string, regardless of Python version. That's not really an option in Python 2, but it just happens to work when your Unicode string is ASCII safe.

However, when the process exited with non-ASCII characters on stderr or stdout, then showing the exception in a traceback results in a <exception str() failed> exception message, because the str() call on the exception instance fails.

Demo reproducing the problem, run with Python 2.7:

import sh, sys
print(sys.version_info)
python27 = sh.Command(sys.executable)
python27(c=r"import sys; sys.stderr.write(u'\u2603\n'.encode('utf8')); sys.exit(1)")

This outputs

sys.version_info(major=2, minor=7, micro=15, releaselevel='final', serial=0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../lib/python2.7/site-packages/sh.py", line 1427, in __call__
    return RunningCommand(cmd, call_args, stdin, stdout, stderr)
  File "/.../lib/python2.7/site-packages/sh.py", line 774, in __init__
    self.wait()
  File "/.../lib/python2.7/site-packages/sh.py", line 792, in wait
    self.handle_command_exit_code(exit_code)
  File "/.../lib/python2.7/site-packages/sh.py", line 815, in handle_command_exit_code
    raise exc
sh.ErrorReturnCode_1: <exception str() failed>

When you catch the exception, the .args[0] attribute shows why:

>>> try:
...     python27(c=r"import sys; sys.stderr.write(u'\u2603\n'.encode('utf8')); sys.exit(1)")
... except sh.ErrorReturnCode as exc:
...     print(repr(exc.args[0]))
...     str(exc)
...
u"\n\n  RAN: /.../bin/python -c import sys; sys.stderr.write(u'\\u2603\\n'.encode('utf8')); sys.exit(1)\n\n  STDOUT:\n\n\n  STDERR:\n\u2603\n"
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2603' in position 129: ordinal not in range(128)

So on Python 2, please encode the message to a suitable str object before setting it.

abadger added a commit to abadger/sh that referenced this issue Mar 2, 2019
In Python3, the str type is a text string.  On Python2, the str type is
a byte string.  When we raise exceptions we should use native strings
otherwise Python may end up truncating or omitting the exception
message (on Python2) or mangling them (if a byte string were to be given
on Python3).

Fixes amoffat#463
@amoffat
Copy link
Owner

amoffat commented Apr 24, 2020

Thanks for reporting and taking the time to write a clear sample to reproduce. @abadger's fix will be deployed with the next release.

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

Successfully merging a pull request may close this issue.

2 participants