Merge pull request #514 from Julian/case-insensitive-sorting
Add a way to do case-insensitive sorting via file-contents-sorter.
diff --git a/pre_commit_hooks/file_contents_sorter.py b/pre_commit_hooks/file_contents_sorter.py
index 76dc4fa..4c1c747 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 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 c8afc2d..9ebb021 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