Skip to content

Instantly share code, notes, and snippets.

@jerrykan
Created September 4, 2015 08:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jerrykan/177cf9d75efd27941efe to your computer and use it in GitHub Desktop.
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`
#!/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()
@bngcebetsha
Copy link

Mind sharing a usage example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment