July 26, 2025
chasten
? Why did we build it?chasten
for a Python projectchasten
enables scalable and structure-aware feedback that effectively supports both instructors and students
chasten
, it’s worth surveying the landscape of linting and checking
pyastgrep
offers a novel way query a program’s AST! Is XPath sufficient? Can this tool support all envisioned use cases? How?
Python Source Code
Abstract Syntax Tree
pyastgrep
Define a Python file with functions
def too_many_args(a, b, c, d, e, f):
def another_function(x, y):
def a_third_function(p, q, r, s, t, u, v):
Find functions with more than 5 arguments
Results from running the query with pyastgrep
pyastgrep
and chasten
toolspyastgrep
grep
-like console outputchasten
pyastgrep
’s APIdatasette
chasten
uses pyastgrep
’s powerful search to build a configurable, project-oriented linter. Developers, researchers, students, and instructors can “chasten
” Python projects and save the results!
dhv
to explore a Python AST!Click these links to preview documentation for referenced tools!
ast
module: Python’s abstract syntax tree modulechasten
chasten
!chasten
Check ID | Check Name | File | Matches |
---|---|---|---|
PERF001 | nested-loops | analyze.py | 1 |
PERF001 | nested-loops | display.py | 7 |
PERF001 | nested-loops | main.py | 0 |
PERF001
)
nested-loops
)
analyze.py
)
1
match)
import ast
import json
import os
import sys
class ForVisitor(ast.NodeVisitor):
"""
An AST visitor that detects doubly-nested for loops.
"""
def __init__(self, filepath):
self.filepath = filepath
self.nested_for_loops = []
self._for_depth = 0
def visit_For(self, node):
"""
Visit a for-loop node in the AST.
"""
self._for_depth += 1
if self._for_depth > 1:
self.nested_for_loops.append({
"file": self.filepath,
"line": node.lineno,
"col": node.col_offset
})
self.generic_visit(node)
self._for_depth -= 1
def analyze_directory(directory):
"""
Analyze all Python files in a directory for doubly-nested for loops.
"""
all_nested_loops = []
for root, _, files in os.walk(directory):
for file in files:
if file.endswith(".py"):
filepath = os.path.join(root, file)
with open(filepath, "r", encoding="utf-8") as source_file:
try:
tree = ast.parse(source_file.read(), filename=filepath)
visitor = ForVisitor(filepath)
visitor.visit(tree)
all_nested_loops.extend(visitor.nested_for_loops)
except SyntaxError as e:
print(f"Could not parse {filepath}: {e}")
return all_nested_loops
def main():
"""
Main function to run the analysis and save the results.
"""
if len(sys.argv) != 2:
print("Usage: python double_loops_detect.py <directory>")
sys.exit(1)
script_dir = os.path.dirname(os.path.abspath(__file__))
target_directory = os.path.join(script_dir, '..', sys.argv[1])
if not os.path.isdir(target_directory):
print(f"Error: '{target_directory}' is not a valid directory.")
sys.exit(1)
results = analyze_directory(target_directory)
output_filename = "nested_loops.json"
with open(output_filename, "w", encoding="utf-8") as f:
json.dump(results, f, indent=2)
print(f"Analysis complete. Found {len(results)} doubly-nested for-loops.")
print(f"Results saved to {output_filename}")
if __name__ == "__main__":
main()
chasten
?The prior program was automatically generated by Gemini 2.5 Pro with gemini-cli
. And, it works! Impressive!
Similar programs can also be generated by GPT4.1 or Claude Sonnet 4 with open-code
. Again, really nice!
npx https://github.com/google-gemini/gemini-cli
npx opencode-ai@latest
Or, use these tools to generate chasten
configurations!
chasten
chasten
’s effectiveness and influence
PyOhio 2025