Skip to content

Commit 7905594

Browse files
committed
Don't UnicodeDecodeError on non-ascii not-found hooks. Resolves pre-commit#207.
1 parent 20c546a commit 7905594

File tree

5 files changed

+35
-12
lines changed

5 files changed

+35
-12
lines changed

pre_commit/five.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,11 @@ def n(s):
2020
return s
2121
else:
2222
return s.decode('UTF-8')
23+
24+
25+
def to_text(s):
26+
return s if isinstance(s, text) else s.decode('UTF-8')
27+
28+
29+
def to_bytes(s):
30+
return s if isinstance(s, bytes) else s.encode('UTF-8')

pre_commit/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import pkg_resources
88

99
from pre_commit import color
10+
from pre_commit import five
1011
from pre_commit.commands.autoupdate import autoupdate
1112
from pre_commit.commands.clean import clean
1213
from pre_commit.commands.install_uninstall import install
@@ -25,6 +26,7 @@
2526

2627
def main(argv=None):
2728
argv = argv if argv is not None else sys.argv[1:]
29+
argv = [five.to_text(arg) for arg in argv]
2830
parser = argparse.ArgumentParser()
2931

3032
# http://stackoverflow.com/a/8521644/812183

pre_commit/output.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,8 @@ def get_hook_message(
7777
)
7878

7979

80-
def sys_stdout_write_wrapper(s, stream=sys.stdout):
81-
"""Python 2.6 chokes on unicode being passed to sys.stdout.write.
80+
stdout_byte_stream = getattr(sys.stdout, 'buffer', sys.stdout)
8281

83-
This is an adapter because PY2 is ok with bytes and PY3 requires text.
84-
"""
85-
assert type(s) is five.text
86-
if five.PY2: # pragma: no cover (PY2)
87-
s = s.encode('UTF-8')
88-
stream.write(s)
82+
83+
def sys_stdout_write_wrapper(s, stream=stdout_byte_stream):
84+
stream.write(five.to_bytes(s))

tests/commands/install_uninstall_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def _get_commit_output(
105105
cmd_output('git', 'add', touch_file)
106106
# Don't want to write to home directory
107107
home = home or tmpdir_factory.get()
108-
env = dict(env_base, **{'PRE_COMMIT_HOME': home})
108+
env = dict(env_base, PRE_COMMIT_HOME=home)
109109
return cmd_output(
110110
'git', 'commit', '-m', 'Commit!', '--allow-empty',
111111
# git commit puts pre-commit to stderr
@@ -414,7 +414,7 @@ def test_installed_from_venv(tmpdir_factory):
414414
def _get_push_output(tmpdir_factory):
415415
# Don't want to write to home directory
416416
home = tmpdir_factory.get()
417-
env = dict(os.environ, **{'PRE_COMMIT_HOME': home})
417+
env = dict(os.environ, PRE_COMMIT_HOME=home)
418418
return cmd_output(
419419
'git', 'push', 'origin', 'HEAD:new_branch',
420420
# git commit puts pre-commit to stderr

tests/commands/run_test.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
import os.path
77
import subprocess
8+
import sys
89

910
import mock
1011
import pytest
@@ -274,6 +275,22 @@ def test_multiple_hooks_same_id(
274275
assert output.count('Bash hook') == 2
275276

276277

278+
def test_non_ascii_hook_id(
279+
repo_with_passing_hook, mock_out_store_directory, tmpdir_factory,
280+
):
281+
with cwd(repo_with_passing_hook):
282+
install(Runner(repo_with_passing_hook))
283+
# Don't want to write to home directory
284+
env = dict(os.environ, PRE_COMMIT_HOME=tmpdir_factory.get())
285+
_, stdout, _ = cmd_output(
286+
sys.executable, '-m', 'pre_commit.main', 'run', '☃',
287+
env=env, retcode=None,
288+
)
289+
assert 'UnicodeDecodeError' not in stdout
290+
# Doesn't actually happen, but a reasonable assertion
291+
assert 'UnicodeEncodeError' not in stdout
292+
293+
277294
def test_stdout_write_bug_py26(
278295
repo_with_failing_hook, mock_out_store_directory, tmpdir_factory,
279296
):
@@ -289,7 +306,7 @@ def test_stdout_write_bug_py26(
289306
install(Runner(repo_with_failing_hook))
290307

291308
# Don't want to write to home directory
292-
env = dict(os.environ, **{'PRE_COMMIT_HOME': tmpdir_factory.get()})
309+
env = dict(os.environ, PRE_COMMIT_HOME=tmpdir_factory.get())
293310
# Have to use subprocess because pytest monkeypatches sys.stdout
294311
_, stdout, _ = cmd_output(
295312
'git', 'commit', '-m', 'Commit!',
@@ -329,7 +346,7 @@ def test_lots_of_files(mock_out_store_directory, tmpdir_factory):
329346
install(Runner(git_path))
330347

331348
# Don't want to write to home directory
332-
env = dict(os.environ, **{'PRE_COMMIT_HOME': tmpdir_factory.get()})
349+
env = dict(os.environ, PRE_COMMIT_HOME=tmpdir_factory.get())
333350
cmd_output(
334351
'git', 'commit', '-m', 'Commit!',
335352
# git commit puts pre-commit to stderr

0 commit comments

Comments
 (0)