-
-
Save AlexRiina/d8dfd39d2c6c4b121c8776070a2272dc to your computer and use it in GitHub Desktop.
""" | |
Add `# noqa: FXXX` comments to all lines with violations from flake8 | |
""" | |
# MIT License | |
# | |
# Copyright (c) 2022 Alex Riina | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a copy | |
# of this software and associated documentation files (the "Software"), to deal | |
# in the Software without restriction, including without limitation the rights | |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
# copies of the Software, and to permit persons to whom the Software is | |
# furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in all | |
# copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
# SOFTWARE. | |
import sys | |
import argparse | |
import fileinput | |
from itertools import groupby | |
from collections import defaultdict | |
parser = argparse.ArgumentParser( | |
description=__doc__, | |
usage="flake8 $(git ls-files **/*.py) | noqaer.py - [--dry-run]", | |
epilog=""" | |
Intended to be used once in lieu of manually fixing all flake8 violatios so | |
flake8 passes 100% and can be added to a build.""", | |
) | |
parser.add_argument("errors", type=argparse.FileType("r"), help="errors from flake8") | |
parser.add_argument("--dry-run", action="store_true") | |
args = parser.parse_args() | |
def parse_flake8_errors(error_lines): | |
for error_line in error_lines: | |
filename, line_number, col, message = error_line.strip().split(":", 3) | |
error_code, message = message.strip().split(" ", 1) | |
yield filename, int(line_number), error_code | |
for filename, error_tuples in groupby( | |
parse_flake8_errors(args.errors), key=lambda error_tuple: error_tuple[0] | |
): | |
errors = defaultdict(set) | |
for _, line_number, code in error_tuples: | |
errors[line_number].add(code) | |
with fileinput.input(files=[filename], inplace=not args.dry_run) as fp: | |
for line_number, line in enumerate(fp, start=1): | |
if line_number not in errors: | |
# line already has a newline, so don't add an extra | |
print(line, end="") | |
elif "noqa" in line or line.strip().endswith("\\"): | |
print("skipping {}:{}".format(filename, line_number), file=sys.stderr) | |
print(line, end="") | |
else: | |
# note the fileinput inplace captures output and writes back to the file | |
print(line.rstrip("\n") + " # noqa: " + ", ".join(errors[line_number])) |
@sigmavirus24 I hadn't heard of that project but my inclination is to avoid adding any external dependencies so this can be audited and run very easily. I do like the idea of reducing the split
and strips
though and think the script could be rewritten to use an explicit flake8 --format ...
.
With something like flake8 --format '%(path)s:%(row)d:%(col)d:%(code)s'
some of the strips can go away and this could even use csv.reader
(if someone is dealing with a gnarly error message that breaks this script and reads this: '%(path)s:%(row)d:%(col)d:%(code)s x'
looks like be good enough).
I'm not planning to change this gist since I've run the code on my repo and we're unlikely to declare a "jubilee" for any other flake8 errors but please feel free to fork this repo and make any changes you like (just added a license).
@AlexRiina have you considered suggesting folks use
flake8-json
so you have structured data that you can parse more easily?