Skip to content

Commit 01be171

Browse files
committed
Don't crash on un-stringable exceptions
1 parent 0a8ba31 commit 01be171

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

pre_commit/error_handler.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,24 @@ class FatalError(RuntimeError):
1414
pass
1515

1616

17+
def _exception_to_bytes(exc: BaseException) -> bytes:
18+
with contextlib.suppress(TypeError):
19+
return bytes(exc) # type: ignore
20+
with contextlib.suppress(Exception):
21+
return str(exc).encode()
22+
return f'<unprintable {type(exc).__name__} object>'.encode()
23+
24+
1725
def _log_and_exit(msg: str, exc: BaseException, formatted: str) -> None:
18-
error_msg = f'{msg}: {type(exc).__name__}: {exc}'
19-
output.write_line(error_msg)
26+
error_msg = f'{msg}: {type(exc).__name__}: '.encode()
27+
error_msg += _exception_to_bytes(exc)
28+
output.write_line_b(error_msg)
2029
log_path = os.path.join(Store().directory, 'pre-commit.log')
2130
output.write_line(f'Check the log at {log_path}')
2231

2332
with open(log_path, 'wb') as log:
2433
_log_line = functools.partial(output.write_line, stream=log)
34+
_log_line_b = functools.partial(output.write_line_b, stream=log)
2535

2636
_log_line('### version information')
2737
_log_line()
@@ -39,7 +49,7 @@ def _log_and_exit(msg: str, exc: BaseException, formatted: str) -> None:
3949
_log_line('### error information')
4050
_log_line()
4151
_log_line('```')
42-
_log_line(error_msg)
52+
_log_line_b(error_msg)
4353
_log_line('```')
4454
_log_line()
4555
_log_line('```')

tests/error_handler_test.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pytest
77

88
from pre_commit import error_handler
9+
from pre_commit.util import CalledProcessError
910
from testing.util import cmd_output_mocked_pre_commit_home
1011

1112

@@ -135,6 +136,22 @@ def test_error_handler_non_ascii_exception(mock_store_dir):
135136
raise ValueError('☃')
136137

137138

139+
def test_error_handler_non_utf8_exception(mock_store_dir):
140+
with pytest.raises(SystemExit):
141+
with error_handler.error_handler():
142+
raise CalledProcessError(1, ('exe',), 0, b'error: \xa0\xe1', b'')
143+
144+
145+
def test_error_handler_non_stringable_exception(mock_store_dir):
146+
class C(Exception):
147+
def __str__(self):
148+
raise RuntimeError('not today!')
149+
150+
with pytest.raises(SystemExit):
151+
with error_handler.error_handler():
152+
raise C()
153+
154+
138155
def test_error_handler_no_tty(tempdir_factory):
139156
pre_commit_home = tempdir_factory.get()
140157
ret, out, _ = cmd_output_mocked_pre_commit_home(

0 commit comments

Comments
 (0)