Skip to content

Instantly share code, notes, and snippets.

@mrbusche
Created February 25, 2025 23:02
Show Gist options
  • Save mrbusche/5e705d8e87c0207ac1cc1bafef169517 to your computer and use it in GitHub Desktop.
Save mrbusche/5e705d8e87c0207ac1cc1bafef169517 to your computer and use it in GitHub Desktop.
missing_exc_info.py
#!/usr/bin/env python3
import ast
import os
import sys
class LoggingVisitor(ast.NodeVisitor):
def __init__(self, source):
self.source = source
self.issues = []
self.in_except = False
def visit_ExceptHandler(self, node):
prev = self.in_except
self.in_except = True
self.generic_visit(node)
self.in_except = prev
def visit_Call(self, node):
if self.in_except and isinstance(node.func, ast.Attribute) and node.func.attr == "error":
if not any(kw.arg == "exc_info" for kw in node.keywords):
snippet = ast.get_source_segment(self.source, node)
self.issues.append((node.lineno, snippet))
self.generic_visit(node)
def check_file(filename):
try:
with open(filename, "r", encoding="utf-8") as f:
source = f.read()
tree = ast.parse(source, filename=filename)
except Exception:
return []
visitor = LoggingVisitor(source)
visitor.visit(tree)
return visitor.issues
def main(path):
found = False
if os.path.isfile(path):
issues = check_file(path)
for lineno, snippet in issues:
found = True
print(f"{path}:{lineno}: Missing exc_info in:\n {snippet}")
else:
for root, dirs, files in os.walk(path):
# Skip directories named ".venv"
dirs[:] = [d for d in dirs if d != ".venv"]
for file in files:
if file.endswith(".py"):
filename = os.path.join(root, file)
for lineno, snippet in check_file(filename):
found = True
print(f"{filename}:{lineno}: Missing exc_info in:\n {snippet}")
if not found:
print("No issues found.")
return found
if __name__ == "__main__":
issues_found = main(sys.argv[1])
sys.exit(1 if issues_found else 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment