Read/rewrite/write Python ASTs
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Utilities for working with Python operators, including symbol extraction and precedence handling for proper expression formatting. This module provides comprehensive support for AST operator nodes and ensures correct parenthesization in generated source code.
Extract string representations of Python operators from AST operator nodes.
def get_op_symbol(obj, fmt='%s'):
"""
Return symbol string for an AST operator node.
Parameters:
- obj: AST operator node (BinOp, UnaryOp, BoolOp, Compare, etc.)
- fmt: str, format string for the symbol (default: '%s')
Returns:
str: String containing the operator symbol
Raises:
KeyError: If the operator type is not recognized
"""Usage Example:
import ast
import astor
# Parse expression with various operators
code = "a + b * c - d / e and f or g"
tree = ast.parse(code, mode='eval')
# Extract operator symbols
for node in ast.walk(tree):
if hasattr(node, 'op'):
symbol = astor.get_op_symbol(node.op)
print(f"{type(node.op).__name__}: {symbol}")
elif hasattr(node, 'ops'):
for op in node.ops:
symbol = astor.get_op_symbol(op)
print(f"{type(op).__name__}: {symbol}")
# Custom formatting
code = "x ** y"
tree = ast.parse(code, mode='eval')
binop_node = tree.body
symbol = astor.get_op_symbol(binop_node.op, fmt='[%s]')
print(f"Formatted symbol: {symbol}") # [**]Get precedence values for Python operators to ensure correct parenthesization in generated code.
def get_op_precedence(obj):
"""
Return precedence value for an AST operator node.
Parameters:
- obj: AST operator node
Returns:
int: Integer precedence value (higher numbers = higher precedence)
Raises:
KeyError: If the operator type is not recognized
"""Usage Example:
import ast
import astor
# Parse complex expression
code = "a + b * c"
tree = ast.parse(code, mode='eval')
# Check precedence to understand grouping
binop = tree.body # BinOp for 'a + (b * c)'
add_prec = astor.get_op_precedence(binop.op) # Add
mult_prec = astor.get_op_precedence(binop.right.op) # Mult
print(f"Addition precedence: {add_prec}")
print(f"Multiplication precedence: {mult_prec}")
print(f"Multiplication has higher precedence: {mult_prec > add_prec}")Complete mapping from AST operator types to their string symbols.
symbol_data: dictThis dictionary contains the complete mapping of all Python operators:
import astor
# Explore all available operators
print("Binary operators:")
for op_type, symbol in astor.symbol_data.items():
if 'op' in op_type.__name__.lower():
print(f" {op_type.__name__}: {symbol}")
# Check specific operators
import ast
print(f"Add symbol: {astor.symbol_data[ast.Add]}") # +
print(f"Mult symbol: {astor.symbol_data[ast.Mult]}") # *
print(f"And symbol: {astor.symbol_data[ast.And]}") # and
print(f"Or symbol: {astor.symbol_data[ast.Or]}") # orClass containing precedence values for all Python operators.
class Precedence:
"""
Container for operator precedence constants.
Contains precedence values for all Python operators following
Python's operator precedence rules.
"""Available Precedence Constants:
import astor
# Access precedence constants
print(f"Comma precedence: {astor.Precedence.Comma}") # Lowest
print(f"Or precedence: {astor.Precedence.Or}")
print(f"And precedence: {astor.Precedence.And}")
print(f"Not precedence: {astor.Precedence.Not}")
print(f"In precedence: {astor.Precedence.In}")
print(f"Compare precedence: {astor.Precedence.Comp}")
print(f"BitOr precedence: {astor.Precedence.BitOr}")
print(f"BitXor precedence: {astor.Precedence.BitXor}")
print(f"BitAnd precedence: {astor.Precedence.BitAnd}")
print(f"Shift precedence: {astor.Precedence.Shift}")
print(f"Add precedence: {astor.Precedence.Add}")
print(f"Mult precedence: {astor.Precedence.Mult}")
print(f"UAdd precedence: {astor.Precedence.UAdd}")
print(f"Power precedence: {astor.Precedence.Pow}") # HighestUsing operator precedence to determine when parentheses are needed in generated expressions.
Usage Example:
import ast
import astor
def needs_parens(parent_op, child_op, is_right=False):
"""Check if child operation needs parentheses."""
parent_prec = astor.get_op_precedence(parent_op)
child_prec = astor.get_op_precedence(child_op)
# Lower precedence needs parentheses
if child_prec < parent_prec:
return True
# Same precedence on right side of non-associative operators
if child_prec == parent_prec and is_right:
# Check for right-associative operators (like **)
return type(parent_op).__name__ not in ['Pow']
return False
# Example usage
code = "a - b + c" # Parsed as (a - b) + c
tree = ast.parse(code, mode='eval')
binop = tree.body
# Check if we need parentheses for sub-expressions
left_needs_parens = needs_parens(binop.op, binop.left.op, is_right=False)
print(f"Left side needs parentheses: {left_needs_parens}")Using the formatting capabilities for specialized code generation.
Usage Example:
import ast
import astor
def format_operator_with_spaces(op_node):
"""Format operator with surrounding spaces."""
symbol = astor.get_op_symbol(op_node, fmt=' %s ')
return symbol
# Parse and format expression
code = "a+b*c"
tree = ast.parse(code, mode='eval')
# Manually format with spacing
def add_spaces_to_binops(node):
if isinstance(node, ast.BinOp):
left = add_spaces_to_binops(node.left)
right = add_spaces_to_binops(node.right)
op_symbol = format_operator_with_spaces(node.op)
return f"{left}{op_symbol}{right}"
elif isinstance(node, ast.Name):
return node.id
elif isinstance(node, ast.Constant):
return str(node.value)
return str(node)
formatted = add_spaces_to_binops(tree.body)
print(formatted) # "a + b * c"For backward compatibility, astor provides deprecated aliases for operator functions:
# Deprecated aliases (use get_op_symbol instead)
def get_boolop(obj): ... # → get_op_symbol
def get_binop(obj): ... # → get_op_symbol
def get_cmpop(obj): ... # → get_op_symbol
def get_unaryop(obj): ... # → get_op_symbol
def get_anyop(obj): ... # → get_op_symbol
# Deprecated alias (use symbol_data instead)
all_symbols: dict # → symbol_dataThese functions are maintained for compatibility but should not be used in new code. Use get_op_symbol() and symbol_data instead.
Install with Tessl CLI
npx tessl i tessl/pypi-astor