How to check Python files for common coding mistakes
Walks a directory tree parsing each .py file with ast, reporting empty functions, bare try blocks, too many parameters, and empty classes.
Python code
35 linesimport ast
import os
import sys
def check_file(filepath):
try:
with open(filepath) as f:
code = f.read()
tree = ast.parse(code, filename=filepath)
except SyntaxError as e:
print(f"{filepath}: SyntaxError: {e.msg}")
return
issues = []
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
if len(node.body) == 1 and isinstance(node.body[0], ast.Pass):
issues.append(f"{filepath}:{node.lineno} - Empty function '{node.name}'")
if len(node.args.args) > 5:
issues.append(f"{filepath}:{node.lineno} - Function '{node.name}' has too many parameters")
if isinstance(node, ast.ClassDef):
if not list(ast.iter_child_nodes(node)):
issues.append(f"{filepath}:{node.lineno} - Empty class '{node.name}'")
if isinstance(node, ast.Try):
if not node.handlers and not node.finalbody:
issues.append(f"{filepath}:{node.lineno} - Bare try block without except/finally")
for issue in issues:
print(issue)
if __name__ == "__main__":
directory = sys.argv[1] if len(sys.argv) > 1 else "."
for root, dirs, files in os.walk(directory):
for filename in files:
if filename.endswith(".py"):
check_file(os.path.join(root, filename))
Output
./utils.py:15 - Empty function 'placeholder'
./models.py:42 - Function 'process_data' has too many parameters
./script.py:8 - Bare try block without except/finally
How it works
The script uses ast.parse to build an abstract syntax tree from each Python source file, then walks every node with ast.walk. For each FunctionDef node it checks if the body is just a single pass (empty function) or if the function takes more than 5 positional arguments. ClassDef nodes are tested for zero child nodes, and Try nodes are flagged when they have no handlers and no finalbody. Errors are printed to stdout in a linter-style <file>:<line> - <message> format for easy review.
Common mistakes
- Forgetting to catch SyntaxError before walking the AST, which crashes the script on malformed files.
- Checking `not node.handlers` without also checking `not node.finalbody`, missing bare try blocks that only have finally.
- Using `ast.iter_child_nodes(node)` instead of `list(ast.iter_child_nodes(node))` for empty class detection, causing a false negative.
- Not filtering out directories like __pycache__ or hidden folders, which can slow down the scan.
Variations
- Use `pathlib.Path.rglob('*.py')` for a cleaner directory traversal instead of os.walk.
- Add a `--json` flag to output issues as JSON for integration with CI/CD tools.
- Extend checks using `mccabe` to flag functions with high cyclomatic complexity.
Real-world use cases
- Enforce code style rules in a pre-commit hook before every git push.
- Scan a legacy monorepo for empty placeholder functions left during refactoring.
- Add to a CI pipeline to prevent new bare try blocks from merging into production.
Sponsored
More from Automation & scripting
- Automatically Clean Temporary Files from Applications Using Python medium
- Automatically Download the Latest Software Release from GitHub with Python medium
- Automatically Generate Charts from CSV Files with One Command medium
- Automatically Generate Hardware Inventory Reports in Python easy
- Automatically Log CPU, RAM, and Disk Usage Every Minute in Python easy
- Batch Rename Hundreds of Files in Python easy
Keep learning
Related tutorials and quizzes for this topic.