Skip to content

Instantly share code, notes, and snippets.

@henryiii
Last active September 5, 2022 17:14
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 henryiii/df1a8312f5906816ef6b3a467c3b9f14 to your computer and use it in GitHub Desktop.
Save henryiii/df1a8312f5906816ef6b3a467c3b9f14 to your computer and use it in GitHub Desktop.
flake8 checker for error messages showing up unrendered in the traceback
#!/usr/bin/env python
"""
Flake8 checker for raw literals inside raises.
Requires Python 3.10. This can be run without Flake8 as well. Try:
git ls-files '*.py' | xargs python3 plugins/flake8_errmsg.py
Local use:
[flake8:local-plugins]
extension =
EM1 = flake8_errmsg:ErrMsgASTPlugin
paths =
./plugins/
"""
from __future__ import annotations
import ast
import sys
import traceback
from pathlib import Path
from typing import Iterator, NamedTuple
class Flake8ASTErrorInfo(NamedTuple):
line_number: int
offset: int
msg: str
cls: type # unused
class Visitor(ast.NodeVisitor):
def __init__(self):
self.errors: list[Flake8ASTErrorInfo] = []
def visit_Raise(self, node):
match node.exc:
case ast.Call(args=[ast.Constant(value=str()), *_]):
msg = "EM101 exception must not use a string literal, assign to variable first"
self.errors.append(
Flake8ASTErrorInfo(node.lineno, node.col_offset, msg, type(self))
)
case ast.Call(args=[ast.JoinedStr(), *_]):
msg = "EM102 exception must not use a f-string literal, assign to variable first"
self.errors.append(
Flake8ASTErrorInfo(node.lineno, node.col_offset, msg, type(self))
)
case _:
pass
class ErrMsgASTPlugin:
name = "flake8_errmsg"
version = "0.1.0"
def __init__(self, tree: ast.AST) -> None:
self._tree = tree
def run(self) -> Iterator[Flake8ASTErrorInfo]:
visitor = Visitor()
visitor.visit(self._tree)
yield from visitor.errors
def main(path: str) -> None:
code = Path(path).read_text(encoding="utf-8")
try:
node = ast.parse(code)
except SyntaxError as e:
e.filename = path
print("Traceback:")
traceback.print_exception(e, limit=0)
raise SystemExit(1) from None
plugin = ErrMsgASTPlugin(node)
for err in plugin.run():
print(f"{path}:{err.line_number}:{err.offset} {err.msg}")
if __name__ == "__main__":
for item in sys.argv[1:]:
main(item)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment