"Query AST elements 🌲 by using CSS Selector-like 💅 syntax."
Summary
pip install ast-selector
Query all functions that raises at least an exception:
from ast_selector import AstSelector
tree = load_python_code_as_ast_tree()
query = "FunctionDef Raise $FunctionDef"
functions_raising_exceptions = AstSelector(query, tree).all()
Simply use the AST type. Note it should have the proper casing.
AstSelector("FunctionDef", tree).all() # Any Ast.FunctionDef
AstSelector("Raise", tree).all() # Any ast.Raise
AstSelector("Expr", tree).all() # Any ast.Expr
You can filter property types by writing like: [Prop is Type]
.
Condition: Any ast.Expr
that contains .value
prop and that prop is an instance of ast.Call
Result: List of ast.Expr
that fulfills the condition.
AstSelector("Expr[value is Call]", tree).all()
You can navigate as you filter the elements you want by using .prop
.
Condition: Any ast.Expr
that contains .value
prop and that prop is an instance of ast.Call
, take .value
.
Result: List of ast.Call
that fulfills the condition.
AstSelector("Expr[value is Call].value", tree).all()
You can filter property values by writing like: [Prop = Value]
.
Condition: Any ast.FunctionDef
, take returns
as long as it contains id
equals to int
.
Result: List of ast.Name
that fulfills the condition.
AstSelector("FunctionDef.returns[id=int]", tree).all()
You can keep appending [Cond1][Cond2][Cond3]
as you wish:
Condition: Any ast.Raise
that has exc
of type ast.Call
AND that has cause
as None
.
Result: List of ast.Raise
that fulfills the condition.
AstSelector("Raise[exc is Call][cause is None]", tree).all()
You can keep drilling down, but take a previous value as your result by using $[Placeholder]
syntax:
Condition: Any ast.FunctionDef
, take returns
as long as it has id
equals to int
, then take the original FunctionDef
.
Result: List of ast.FunctionDef
that fulfills the condition.
AstSelector("FunctionDef.returns[id=int] $FunctionDef", tree).all()
You can keep filtering and drilling references as you would normally.
Drill $Expr
and take args
as result:
AstSelector("Expr[value is Call].value[func is Attribute].func[attr = exception] $Expr.value.args", tree).all()
Drill $FunctionDef
(redundant) and filter functions named main_int
as result:
AstSelector("FunctionDef.returns[id=int] $FunctionDef[name=main_int]", tree).all()
AstSelector(query, tree).count()
# Raises exception if None
AstSelector(query, tree).first()
AstSelector(query, tree).exists()
Thank you for considering making AST Selector better for everyone!
Refer to Contributing docs.
See CHANGELOG.
MIT
It's extremely hard to keep hacking on open source like that while keeping a full-time job. I thank God from the bottom of my heart for both the inspiration and the energy.