diff --git a/pre_commit_hooks/file_contents_sorter.py b/pre_commit_hooks/file_contents_sorter.py index 76dc4fa1..89134698 100644 --- a/pre_commit_hooks/file_contents_sorter.py +++ b/pre_commit_hooks/file_contents_sorter.py @@ -10,6 +10,8 @@ conflicts and keep the file nicely ordered. """ import argparse +from typing import Any +from typing import Callable from typing import IO from typing import Optional from typing import Sequence @@ -18,9 +20,15 @@ FAIL = 1 -def sort_file_contents(f: IO[bytes]) -> int: +def sort_file_contents( + f: IO[bytes], + key : Optional[Callable[[bytes], Any]], +) -> int: before = list(f) - after = sorted(line.strip(b'\n\r') for line in before if line.strip()) + after = sorted( + (line.strip(b'\n\r') for line in before if line.strip()), + key=key, + ) before_string = b''.join(before) after_string = b'\n'.join(after) + b'\n' @@ -37,13 +45,20 @@ def sort_file_contents(f: IO[bytes]) -> int: def main(argv: Optional[Sequence[str]] = None) -> int: parser = argparse.ArgumentParser() parser.add_argument('filenames', nargs='+', help='Files to sort') + parser.add_argument( + '--ignore-case', + action='store_const', + const=bytes.lower, + default=None, + help='fold lower case to upper case characters', + ) args = parser.parse_args(argv) retv = PASS for arg in args.filenames: with open(arg, 'rb+') as file_obj: - ret_for_file = sort_file_contents(file_obj) + ret_for_file = sort_file_contents(file_obj, key=args.ignore_case) if ret_for_file: print(f'Sorting {arg}') diff --git a/tests/file_contents_sorter_test.py b/tests/file_contents_sorter_test.py index c8afc2d8..49cd52dc 100644 --- a/tests/file_contents_sorter_test.py +++ b/tests/file_contents_sorter_test.py @@ -6,28 +6,52 @@ @pytest.mark.parametrize( - ('input_s', 'expected_retval', 'output'), + ('input_s', 'argv', 'expected_retval', 'output'), ( - (b'', FAIL, b'\n'), - (b'lonesome\n', PASS, b'lonesome\n'), - (b'missing_newline', FAIL, b'missing_newline\n'), - (b'newline\nmissing', FAIL, b'missing\nnewline\n'), - (b'missing\nnewline', FAIL, b'missing\nnewline\n'), - (b'alpha\nbeta\n', PASS, b'alpha\nbeta\n'), - (b'beta\nalpha\n', FAIL, b'alpha\nbeta\n'), - (b'C\nc\n', PASS, b'C\nc\n'), - (b'c\nC\n', FAIL, b'C\nc\n'), - (b'mag ical \n tre vor\n', FAIL, b' tre vor\nmag ical \n'), - (b'@\n-\n_\n#\n', FAIL, b'#\n-\n@\n_\n'), - (b'extra\n\n\nwhitespace\n', FAIL, b'extra\nwhitespace\n'), - (b'whitespace\n\n\nextra\n', FAIL, b'extra\nwhitespace\n'), + (b'', [], FAIL, b'\n'), + (b'lonesome\n', [], PASS, b'lonesome\n'), + (b'missing_newline', [], FAIL, b'missing_newline\n'), + (b'newline\nmissing', [], FAIL, b'missing\nnewline\n'), + (b'missing\nnewline', [], FAIL, b'missing\nnewline\n'), + (b'alpha\nbeta\n', [], PASS, b'alpha\nbeta\n'), + (b'beta\nalpha\n', [], FAIL, b'alpha\nbeta\n'), + (b'C\nc\n', [], PASS, b'C\nc\n'), + (b'c\nC\n', [], FAIL, b'C\nc\n'), + (b'mag ical \n tre vor\n', [], FAIL, b' tre vor\nmag ical \n'), + (b'@\n-\n_\n#\n', [], FAIL, b'#\n-\n@\n_\n'), + (b'extra\n\n\nwhitespace\n', [], FAIL, b'extra\nwhitespace\n'), + (b'whitespace\n\n\nextra\n', [], FAIL, b'extra\nwhitespace\n'), + ( + b'fee\nFie\nFoe\nfum\n', + [], + FAIL, + b'Fie\nFoe\nfee\nfum\n', + ), + ( + b'Fie\nFoe\nfee\nfum\n', + [], + PASS, + b'Fie\nFoe\nfee\nfum\n', + ), + ( + b'fee\nFie\nFoe\nfum\n', + ["--ignore-case"], + PASS, + b'fee\nFie\nFoe\nfum\n', + ), + ( + b'Fie\nFoe\nfee\nfum\n', + ["--ignore-case"], + FAIL, + b'fee\nFie\nFoe\nfum\n', + ), ), ) -def test_integration(input_s, expected_retval, output, tmpdir): +def test_integration(input_s, argv, expected_retval, output, tmpdir): path = tmpdir.join('file.txt') path.write_binary(input_s) - output_retval = main([str(path)]) + output_retval = main([str(path)] + argv) assert path.read_binary() == output assert output_retval == expected_retval