11# -*- coding: UTF-8 -*-
22from __future__ import unicode_literals
33
4+ import functools
45import io
56import os
67import os .path
1617from pre_commit .commands .run import get_changed_files
1718from pre_commit .commands .run import run
1819from pre_commit .ordereddict import OrderedDict
20+ from pre_commit .output import sys_stdout_write_wrapper
1921from pre_commit .runner import Runner
2022from pre_commit .util import cmd_output
2123from pre_commit .util import cwd
@@ -44,7 +46,7 @@ def stage_a_file():
4446
4547
4648def get_write_mock_output (write_mock ):
47- return '' .join (call [0 ][0 ] for call in write_mock .call_args_list )
49+ return b '' .join (call [0 ][0 ] for call in write_mock . write .call_args_list )
4850
4951
5052def _get_opts (
@@ -76,7 +78,8 @@ def _get_opts(
7678def _do_run (repo , args , environ = {}):
7779 runner = Runner (repo )
7880 write_mock = mock .Mock ()
79- ret = run (runner , args , write = write_mock , environ = environ )
81+ write_fn = functools .partial (sys_stdout_write_wrapper , stream = write_mock )
82+ ret = run (runner , args , write = write_fn , environ = environ )
8083 printed = get_write_mock_output (write_mock )
8184 return ret , printed
8285
@@ -97,32 +100,43 @@ def test_run_all_hooks_failing(
97100 _test_run (
98101 repo_with_failing_hook ,
99102 {},
100- ('Failing hook' , 'Failed' , 'hookid: failing_hook' , 'Fail\n foo.py\n ' ),
103+ (
104+ b'Failing hook' ,
105+ b'Failed' ,
106+ b'hookid: failing_hook' ,
107+ b'Fail\n foo.py\n ' ,
108+ ),
101109 1 ,
102110 True ,
103111 )
104112
105113
114+ def test_arbitrary_bytes_hook (tmpdir_factory , mock_out_store_directory ):
115+ git_path = make_consuming_repo (tmpdir_factory , 'arbitrary_bytes_repo' )
116+ with cwd (git_path ):
117+ _test_run (git_path , {}, (b'\xe2 \x98 \x83 \xb2 \n ' ,), 1 , True )
118+
119+
106120@pytest .mark .parametrize (
107121 ('options' , 'outputs' , 'expected_ret' , 'stage' ),
108122 (
109- ({}, ('Bash hook' , 'Passed' ), 0 , True ),
110- ({'verbose' : True }, ('foo.py\n Hello World' ,), 0 , True ),
111- ({'hook' : 'bash_hook' }, ('Bash hook' , 'Passed' ), 0 , True ),
112- ({'hook' : 'nope' }, ('No hook with id `nope`' ,), 1 , True ),
123+ ({}, (b 'Bash hook' , b 'Passed' ), 0 , True ),
124+ ({'verbose' : True }, (b 'foo.py\n Hello World' ,), 0 , True ),
125+ ({'hook' : 'bash_hook' }, (b 'Bash hook' , b 'Passed' ), 0 , True ),
126+ ({'hook' : 'nope' }, (b 'No hook with id `nope`' ,), 1 , True ),
113127 (
114128 {'all_files' : True , 'verbose' : True },
115- ('foo.py' ),
129+ (b 'foo.py', ),
116130 0 ,
117131 True ,
118132 ),
119133 (
120134 {'files' : ('foo.py' ,), 'verbose' : True },
121- ('foo.py' ),
135+ (b 'foo.py', ),
122136 0 ,
123137 True ,
124138 ),
125- ({}, ('Bash hook' , '(no files to check)' , 'Skipped' ), 0 , False ),
139+ ({}, (b 'Bash hook' , b '(no files to check)' , b 'Skipped' ), 0 , False ),
126140 )
127141)
128142def test_run (
@@ -150,7 +164,7 @@ def test_origin_source_error_msg(
150164):
151165 args = _get_opts (origin = origin , source = source )
152166 ret , printed = _do_run (repo_with_passing_hook , args )
153- warning_msg = 'Specify both --origin and --source.'
167+ warning_msg = b 'Specify both --origin and --source.'
154168 if expect_failure :
155169 assert ret == 1
156170 assert warning_msg in printed
@@ -183,7 +197,7 @@ def test_no_stash(
183197 args = _get_opts (no_stash = no_stash , all_files = all_files )
184198 ret , printed = _do_run (repo_with_passing_hook , args )
185199 assert ret == 0
186- warning_msg = '[WARNING] Unstaged files detected.'
200+ warning_msg = b '[WARNING] Unstaged files detected.'
187201 if expect_stash :
188202 assert warning_msg in printed
189203 else :
@@ -200,7 +214,7 @@ def test_has_unmerged_paths(output, expected):
200214def test_merge_conflict (in_merge_conflict , mock_out_store_directory ):
201215 ret , printed = _do_run (in_merge_conflict , _get_opts ())
202216 assert ret == 1
203- assert 'Unmerged files. Resolve before committing.' in printed
217+ assert b 'Unmerged files. Resolve before committing.' in printed
204218
205219
206220def test_merge_conflict_modified (in_merge_conflict , mock_out_store_directory ):
@@ -211,13 +225,15 @@ def test_merge_conflict_modified(in_merge_conflict, mock_out_store_directory):
211225
212226 ret , printed = _do_run (in_merge_conflict , _get_opts ())
213227 assert ret == 1
214- assert 'Unmerged files. Resolve before committing.' in printed
228+ assert b 'Unmerged files. Resolve before committing.' in printed
215229
216230
217231def test_merge_conflict_resolved (in_merge_conflict , mock_out_store_directory ):
218232 cmd_output ('git' , 'add' , '.' )
219233 ret , printed = _do_run (in_merge_conflict , _get_opts ())
220- for msg in ('Checking merge-conflict files only.' , 'Bash hook' , 'Passed' ):
234+ for msg in (
235+ b'Checking merge-conflict files only.' , b'Bash hook' , b'Passed' ,
236+ ):
221237 assert msg in printed
222238
223239
@@ -242,22 +258,22 @@ def test_skip_hook(repo_with_passing_hook, mock_out_store_directory):
242258 ret , printed = _do_run (
243259 repo_with_passing_hook , _get_opts (), {'SKIP' : 'bash_hook' },
244260 )
245- for msg in ('Bash hook' , 'Skipped' ):
261+ for msg in (b 'Bash hook' , b 'Skipped' ):
246262 assert msg in printed
247263
248264
249265def test_hook_id_not_in_non_verbose_output (
250266 repo_with_passing_hook , mock_out_store_directory
251267):
252268 ret , printed = _do_run (repo_with_passing_hook , _get_opts (verbose = False ))
253- assert '[bash_hook]' not in printed
269+ assert b '[bash_hook]' not in printed
254270
255271
256272def test_hook_id_in_verbose_output (
257273 repo_with_passing_hook , mock_out_store_directory ,
258274):
259275 ret , printed = _do_run (repo_with_passing_hook , _get_opts (verbose = True ))
260- assert '[bash_hook] Bash hook' in printed
276+ assert b '[bash_hook] Bash hook' in printed
261277
262278
263279def test_multiple_hooks_same_id (
@@ -272,7 +288,7 @@ def test_multiple_hooks_same_id(
272288
273289 ret , output = _do_run (repo_with_passing_hook , _get_opts ())
274290 assert ret == 0
275- assert output .count ('Bash hook' ) == 2
291+ assert output .count (b 'Bash hook' ) == 2
276292
277293
278294def test_non_ascii_hook_id (
@@ -383,7 +399,7 @@ def test_local_hook_passes(
383399 _test_run (
384400 repo_with_passing_hook ,
385401 options = {},
386- expected_outputs = ['' ],
402+ expected_outputs = [b '' ],
387403 expected_ret = 0 ,
388404 stage = False
389405 )
@@ -412,7 +428,7 @@ def test_local_hook_fails(
412428 _test_run (
413429 repo_with_passing_hook ,
414430 options = {},
415- expected_outputs = ['' ],
431+ expected_outputs = [b '' ],
416432 expected_ret = 1 ,
417433 stage = False
418434 )
@@ -428,8 +444,8 @@ def test_allow_unstaged_config_option(
428444
429445 args = _get_opts (allow_unstaged_config = True )
430446 ret , printed = _do_run (repo_with_passing_hook , args )
431- assert 'You have an unstaged config file' in printed
432- assert 'have specified the --allow-unstaged-config option.' in printed
447+ assert b 'You have an unstaged config file' in printed
448+ assert b 'have specified the --allow-unstaged-config option.' in printed
433449 assert ret == 0
434450
435451
@@ -446,7 +462,7 @@ def test_no_allow_unstaged_config_option(
446462 modify_config (repo_with_passing_hook )
447463 args = _get_opts (allow_unstaged_config = False )
448464 ret , printed = _do_run (repo_with_passing_hook , args )
449- assert 'Your .pre-commit-config.yaml is unstaged.' in printed
465+ assert b 'Your .pre-commit-config.yaml is unstaged.' in printed
450466 assert ret == 1
451467
452468
@@ -456,7 +472,7 @@ def test_no_stash_suppresses_allow_unstaged_config_option(
456472 modify_config (repo_with_passing_hook )
457473 args = _get_opts (allow_unstaged_config = False , no_stash = True )
458474 ret , printed = _do_run (repo_with_passing_hook , args )
459- assert 'Your .pre-commit-config.yaml is unstaged.' not in printed
475+ assert b 'Your .pre-commit-config.yaml is unstaged.' not in printed
460476
461477
462478def test_all_files_suppresses_allow_unstaged_config_option (
@@ -465,7 +481,7 @@ def test_all_files_suppresses_allow_unstaged_config_option(
465481 modify_config (repo_with_passing_hook )
466482 args = _get_opts (all_files = True )
467483 ret , printed = _do_run (repo_with_passing_hook , args )
468- assert 'Your .pre-commit-config.yaml is unstaged.' not in printed
484+ assert b 'Your .pre-commit-config.yaml is unstaged.' not in printed
469485
470486
471487def test_files_suppresses_allow_unstaged_config_option (
@@ -474,4 +490,4 @@ def test_files_suppresses_allow_unstaged_config_option(
474490 modify_config (repo_with_passing_hook )
475491 args = _get_opts (files = ['.pre-commit-config.yaml' ])
476492 ret , printed = _do_run (repo_with_passing_hook , args )
477- assert 'Your .pre-commit-config.yaml is unstaged.' not in printed
493+ assert b 'Your .pre-commit-config.yaml is unstaged.' not in printed
0 commit comments