implemented a basic double quote string fixer

This commit is contained in:
Ken Struys 2015-02-05 19:58:20 -08:00
parent 5fe82b3a37
commit 12f02dfeb8
6 changed files with 154 additions and 1 deletions

View file

@ -36,6 +36,7 @@ Add this to your `.pre-commit-config.yaml`
- `name-tests-test` - Assert that files in tests/ end in _test.py
- `pyflakes` - Run pyflakes on your python files
- `requirements-txt-fixer` - Sorts entries in requirements.txt
- `double-quote-string-fixer` - This hook replaces double quoted strings with single quoted strings
- `trailing-whitespace` - Trims trailing whitespace.
### As a standalone package

View file

@ -79,6 +79,12 @@
entry: requirements-txt-fixer
language: python
files: requirements.*\.txt$
- id: double-quote-string-fixer
name: Fix double quoted strings
description: This hook replaces double quoted strings with single quoted strings
entry: double-quote-string-fixer
language: python
files: \.py$
- id: trailing-whitespace
name: Trim Trailing Whitespace
description: This hook trims trailing whitespace.

View file

@ -0,0 +1,65 @@
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
import argparse
import re
import tokenize
double_quote_starts = tuple(s for s in tokenize.single_quoted if '"' in s)
compiled_tokenize_string = re.compile(tokenize.String)
def handle_match(m):
string = m.group(0)
for double_quote_start in double_quote_starts:
if string.startswith(double_quote_start):
meat = string[len(double_quote_start):-1]
if '"' in meat or "'" in meat:
break
return (
double_quote_start.replace('"', "'") +
string[len(double_quote_start):-1] +
"'"
)
return string
def fix_strings(filename):
return_value = 0
lines = []
with open(filename, 'r') as read_handle:
for line in read_handle:
if '"""' in line:
# Docstrings are hard, fuck it
lines.append(line)
else:
result = re.sub(compiled_tokenize_string, handle_match, line)
lines.append(result)
return_value |= int(result != line)
with open(filename, 'w') as write_handle:
for line in lines:
write_handle.write(line)
return return_value
def main(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument('filenames', nargs='*', help='Filenames to fix')
args = parser.parse_args(argv)
retv = 0
for filename in args.filenames:
return_value = fix_strings(filename)
if return_value != 0:
print('Fixing strings in {0}'.format(filename))
retv |= return_value
return retv

View file

@ -46,6 +46,7 @@ setup(
'debug-statement-hook = pre_commit_hooks.debug_statement_hook:debug_statement_hook',
'end-of-file-fixer = pre_commit_hooks.end_of_file_fixer:end_of_file_fixer',
'name-tests-test = pre_commit_hooks.tests_should_end_in_test:validate_files',
'double-quote-string-fixer = pre_commit_hooks.string_fixer:main',
'requirements-txt-fixer = pre_commit_hooks.requirements_txt_fixer:fix_requirements_txt',
'trailing-whitespace-fixer = pre_commit_hooks.trailing_whitespace_fixer:fix_trailing_whitespace',
],

View file

@ -15,7 +15,7 @@ TESTS = (
('', 0, ''),
# Acceptable
('"foo"', 0, ''),
# Docstrin after code
# Docstring after code
(
'from __future__ import unicode_literals\n'
'"foo"\n',

View file

@ -0,0 +1,80 @@
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
import pytest
from pre_commit_hooks.string_fixer import main
TESTS = (
# Base cases
(
"''",
"''",
0
),
(
'""',
"''",
1
),
(
r'"\'"',
r'"\'"',
0
),
(
r'"\""',
r'"\""',
0
),
(
r"'\"\"'",
r"'\"\"'",
0
),
# String somewhere in the line
(
'x = "foo"',
"x = 'foo'",
1
),
# Test escaped characters
(
r'"\'"',
r'"\'"',
0
),
# Docstring
(
'""" Foo """',
'""" Foo """',
0
),
# Fuck it, won't even try to fix
(
"""
x = " \\n
foo \\n
"\n
""",
"""
x = " \\n
foo \\n
"\n
""",
0
),
)
@pytest.mark.parametrize(('input_s', 'expected_output', 'expected_retval'), TESTS)
def test_rewrite(input_s, expected_output, expected_retval, tmpdir):
tmpfile = tmpdir.join('file.txt')
with open(tmpfile.strpath, 'w') as f:
f.write(input_s)
retval = main([tmpfile.strpath])
assert tmpfile.read() == expected_output
assert retval == expected_retval