Created
September 4, 2015 08:05
-
-
Save jerrykan/177cf9d75efd27941efe to your computer and use it in GitHub Desktop.
A very simplistic script to check for flake8 errors in the lines of a diff produced from `git diff`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
A very simplistic script to check for flake8 errors in the lines of a diff | |
produced from `git diff`. This is useful if you have files with lots of flake8 | |
errors, but you only want to know about the errors in the lines you have | |
altered. | |
""" | |
import sys | |
import subprocess | |
def system(*args, **kwargs): | |
stdin = kwargs.pop('input', None) | |
kwargs.setdefault('stdin', subprocess.PIPE) | |
kwargs.setdefault('stdout', subprocess.PIPE) | |
proc = subprocess.Popen(args, **kwargs) | |
out, err = proc.communicate(input=stdin) | |
return out | |
def git_diff(*args): | |
diff = system('git', 'diff', *args) | |
return diff.strip().split("\n") | |
def flake8_output(file_list, *args): | |
errors = [] | |
prefix = len('stdin') | |
for filename in file_list: | |
if '--cached' in args: | |
# run the cached version of the file through flake8 | |
input_file = system('git', 'show', ':' + filename) | |
else: | |
input_file = system('cat', filename) | |
err = system('flake8', '-', input=input_file) | |
errors += [filename + e[prefix:] for e in err.strip().split("\n") if e] | |
return errors | |
def parse_diff(lines): | |
files = {} | |
current_file = None | |
counter = 0 | |
blanks = False | |
for line in lines: | |
if line.startswith('-'): | |
continue | |
if line.startswith('+++'): | |
# starting on a new file | |
current_file = line[6:].strip() | |
files[current_file] = [] | |
continue | |
if line.startswith('diff'): | |
# finished with this file | |
current_file = None | |
continue | |
if current_file is None: | |
# if we are not currently parsing a file, skip the line | |
continue | |
if line.startswith('@@'): | |
# set new starting point | |
counter = -1 | |
base_line = int(line.split()[2].split(',')[0]) | |
continue | |
counter += 1 | |
if line.startswith('+'): | |
files[current_file].append(base_line + counter) | |
elif line == ' ': | |
blanks = True | |
else: | |
l = line.strip() | |
if blanks and (l.startswith('def') or l.startswith('class')): | |
files[current_file].append(base_line + counter) | |
else: | |
blanks = False | |
return files | |
def parse_flake8(lines): | |
errors = [] | |
for line in lines: | |
parts = line.split(':') | |
errors.append((parts[0].strip(), int(parts[1]), line)) | |
return sorted(errors) | |
def main(): | |
# get list of changed files and lines | |
args = sys.argv[1:] | |
diff = git_diff(*args) | |
changed_files = parse_diff(diff) | |
# get list of flake8 errors for the changed files | |
py_files = [f for f in changed_files.keys() if f.endswith('.py')] | |
output = flake8_output(py_files, *args) | |
flake8_errors = parse_flake8(output) | |
# check changed lines for errors | |
errors = [err for filename, lineno, err in flake8_errors | |
if lineno in changed_files[filename]] | |
# if errors found, print them and exit with error code | |
if errors: | |
print "Aborting commit due to flake8 errors:" | |
for err in errors: | |
print err | |
sys.exit(1) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Mind sharing a usage example