1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
#!/usr/bin/env python3
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Fix some flake8 errors by rewriting files for which flake8 emitted
an error/warning. Usage (from the root dir):
$ python3 -m flake8 --exit-zero | python3 scripts/fix_flake8.py
"""
import sys
import tempfile
import shutil
from collections import defaultdict
from collections import namedtuple
from pprint import pprint as pp # NOQA
ntentry = namedtuple('ntentry', 'msg, issue, lineno, pos, descr')
# =====================================================================
# utils
# =====================================================================
def enter_pdb():
from pdb import set_trace as st # trick GIT commit hook
sys.stdin = open('/dev/tty')
st()
def read_lines(fname):
with open(fname, 'rt') as f:
return f.readlines()
def read_line(fname, lineno):
with open(fname, 'rt') as f:
for i, line in enumerate(f, 1):
if i == lineno:
return line
raise ValueError("lineno too big")
def write_file(fname, newlines):
with tempfile.NamedTemporaryFile('wt', delete=False) as f:
for line in newlines:
f.write(line)
shutil.move(f.name, fname)
# =====================================================================
# handlers
# =====================================================================
def handle_f401(fname, lineno):
""" This is 'module imported but not used'
Able to handle this case:
import os
...but not this:
from os import listdir
"""
line = read_line(fname, lineno).strip()
if line.startswith('import '):
return True
else:
mods = line.partition(' import ')[2] # everything after import
return ',' not in mods
# =====================================================================
# converters
# =====================================================================
def remove_lines(fname, entries):
"""Check if we should remove lines, then do it.
Return the numner of lines removed.
"""
to_remove = []
for entry in entries:
msg, issue, lineno, pos, descr = entry
# 'module imported but not used'
if issue == 'F401' and handle_f401(fname, lineno):
to_remove.append(lineno)
# 'blank line(s) at end of file'
elif issue == 'W391':
lines = read_lines(fname)
i = len(lines) - 1
while lines[i] == '\n':
to_remove.append(i + 1)
i -= 1
# 'too many blank lines'
elif issue == 'E303':
howmany = descr.replace('(', '').replace(')', '')
howmany = int(howmany[-1])
for x in range(lineno - howmany, lineno):
to_remove.append(x)
if to_remove:
newlines = []
for i, line in enumerate(read_lines(fname), 1):
if i not in to_remove:
newlines.append(line)
print("removing line(s) from %s" % fname)
write_file(fname, newlines)
return len(to_remove)
def add_lines(fname, entries):
"""Check if we should remove lines, then do it.
Return the numner of lines removed.
"""
EXPECTED_BLANK_LINES = (
'E302', # 'expected 2 blank limes, found 1'
'E305') # ìexpected 2 blank lines after class or fun definition'
to_add = {}
for entry in entries:
msg, issue, lineno, pos, descr = entry
if issue in EXPECTED_BLANK_LINES:
howmany = 2 if descr.endswith('0') else 1
to_add[lineno] = howmany
if to_add:
newlines = []
for i, line in enumerate(read_lines(fname), 1):
if i in to_add:
newlines.append('\n' * to_add[i])
newlines.append(line)
print("adding line(s) to %s" % fname)
write_file(fname, newlines)
return len(to_add)
# =====================================================================
# main
# =====================================================================
def build_table():
table = defaultdict(list)
for line in sys.stdin:
line = line.strip()
if not line:
break
fields = line.split(':')
fname, lineno, pos = fields[:3]
issue = fields[3].split()[0]
descr = fields[3].strip().partition(' ')[2]
lineno, pos = int(lineno), int(pos)
table[fname].append(ntentry(line, issue, lineno, pos, descr))
return table
def main():
table = build_table()
# remove lines (unused imports)
removed = 0
for fname, entries in table.items():
removed += remove_lines(fname, entries)
if removed:
print("%s lines were removed from some file(s); please re-run" %
removed)
return
# add lines (missing \n between functions/classes)
added = 0
for fname, entries in table.items():
added += add_lines(fname, entries)
if added:
print("%s lines were added from some file(s); please re-run" %
added)
return
main()
|