Merge pull request #514 from Julian/case-insensitive-sorting

Add a way to do case-insensitive sorting via file-contents-sorter.
This commit is contained in:
Anthony Sottile 2020-08-26 18:59:21 -07:00 committed by GitHub
commit 31d41ff291
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 19 deletions

View file

@ -10,6 +10,8 @@ this hook on that file should reduce the instances of git merge
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 @@ PASS = 0
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}')

View file

@ -6,28 +6,52 @@ from pre_commit_hooks.file_contents_sorter import PASS
@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