Skip to content

Instantly share code, notes, and snippets.

@jerrykan
Last active September 26, 2015 14:14
Show Gist options
  • Save jerrykan/4fa9c04c7aad5ed647e2 to your computer and use it in GitHub Desktop.
Save jerrykan/4fa9c04c7aad5ed647e2 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
"""
A very simplistic script to check for flake8 errors in the lines of a file that
are to be committed. 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():
diff = system('git', 'diff', '--cached')
return diff.strip().split("\n")
def flake8_output(file_list):
errors = []
prefix = len('stdin')
for filename in file_list:
# run the cached version of the file through flake8
cached_file = system('git', 'show', ':' + filename)
err = system('flake8', '-', input=cached_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
diff = git_diff()
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)
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