Skip to content

Instantly share code, notes, and snippets.

@charliermarsh
Created May 17, 2023 14:46
Show Gist options
  • Save charliermarsh/3f2855f33960c92306c91d003b6237dc to your computer and use it in GitHub Desktop.
Save charliermarsh/3f2855f33960c92306c91d003b6237dc to your computer and use it in GitHub Desktop.
from __future__ import annotations
import os
import subprocess
SELECT = [
"E111",
"E112",
"E113",
"E114",
"E115",
"E116",
"E117",
"E201",
"E202",
"E203",
"E211",
"E221",
"E222",
"E223",
"E224",
"E225",
"E226",
"E227",
"E228",
"E231",
"E251",
"E252",
"E261",
"E262",
"E265",
"E266",
"E271",
"E272",
"E273",
"E274",
"E275",
]
def take_after(s: str) -> str:
"""Given filename:204:22, return everything after the first colon."""
s = s.split(":", 1)[1]
s = s.replace(
"`# `",
"'# '",
)
s = s.replace(
"`#`",
"'#'",
)
s = s.replace(
"for block comment",
"before block comment",
)
s = s.replace(
"Insert at least two spaces before an inline comment",
"at least two spaces before inline comment",
)
return s
def take_comparable(s: str) -> str:
s = s.lower()
# Ignore location, I guess? The issue here is really for "Over-indented (comment")
# where we use the start of the indentation, but pycodestyle uses the start of the
# comment.
if "over-indented" in s:
s = s.split(":", 2)[-1]
return s
def case_insensitive_compare(a: list[str], b: list[str]) -> bool:
return [take_comparable(line) for line in a] == [
take_comparable(line) for line in b
]
def pycodestyle(fname: str) -> list[str]:
output = subprocess.getoutput(f"pycodestyle {fname} --select {','.join(SELECT)}")
if output:
return [take_after(line) for line in output.split("\n") if ":" in line]
else:
return []
def ruff(fname: str) -> list[str]:
output = subprocess.getoutput(
f"./target/debug/ruff {fname} --select {','.join(SELECT)} --no-cache"
)
if output:
return [take_after(line) for line in output.split("\n") if ":" in line]
else:
return []
if __name__ == "__main__":
dirname = "../scipy/scipy"
# Walk over every file in the directory.
seen = False
for root, dirs, files in os.walk(dirname):
for filename in files:
# If the file is a python file, check if it contains a docstring.
if filename.endswith(".py"):
filepath = os.path.join(root, filename)
# Local optimization: skip until you see a specific failing file...
if False:
if filepath == "../scipy/scipy/stats/tests/__init__.py":
seen = True
if not seen:
continue
# Run pycodestyle on the file.
pycodestyle_errors = pycodestyle(filepath)
ruff_errors = ruff(filepath)
if case_insensitive_compare(pycodestyle_errors, ruff_errors):
print(f"OK: {filepath}")
else:
print(f"File: {filepath}")
# Print the first error that differs.
for i in range(min(len(pycodestyle_errors), len(ruff_errors))):
if pycodestyle_errors[i].lower() != ruff_errors[i].lower():
print(f"pycodestyle: {pycodestyle_errors[i]}")
print(f"ruff: {ruff_errors[i]}")
break
# Print the remaining errors.
if len(pycodestyle_errors) > len(ruff_errors):
for error in pycodestyle_errors[len(ruff_errors) :]:
print(f"pycodestyle: {error}")
else:
for error in ruff_errors[len(pycodestyle_errors) :]:
print(f"ruff: {error}")
exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment