0
# Operator Utilities
1
2
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.
3
4
## Capabilities
5
6
### Operator Symbol Extraction
7
8
Extract string representations of Python operators from AST operator nodes.
9
10
```python { .api }
11
def get_op_symbol(obj, fmt='%s'):
12
"""
13
Return symbol string for an AST operator node.
14
15
Parameters:
16
- obj: AST operator node (BinOp, UnaryOp, BoolOp, Compare, etc.)
17
- fmt: str, format string for the symbol (default: '%s')
18
19
Returns:
20
str: String containing the operator symbol
21
22
Raises:
23
KeyError: If the operator type is not recognized
24
"""
25
```
26
27
**Usage Example:**
28
29
```python
30
import ast
31
import astor
32
33
# Parse expression with various operators
34
code = "a + b * c - d / e and f or g"
35
tree = ast.parse(code, mode='eval')
36
37
# Extract operator symbols
38
for node in ast.walk(tree):
39
if hasattr(node, 'op'):
40
symbol = astor.get_op_symbol(node.op)
41
print(f"{type(node.op).__name__}: {symbol}")
42
elif hasattr(node, 'ops'):
43
for op in node.ops:
44
symbol = astor.get_op_symbol(op)
45
print(f"{type(op).__name__}: {symbol}")
46
47
# Custom formatting
48
code = "x ** y"
49
tree = ast.parse(code, mode='eval')
50
binop_node = tree.body
51
52
symbol = astor.get_op_symbol(binop_node.op, fmt='[%s]')
53
print(f"Formatted symbol: {symbol}") # [**]
54
```
55
56
### Operator Precedence
57
58
Get precedence values for Python operators to ensure correct parenthesization in generated code.
59
60
```python { .api }
61
def get_op_precedence(obj):
62
"""
63
Return precedence value for an AST operator node.
64
65
Parameters:
66
- obj: AST operator node
67
68
Returns:
69
int: Integer precedence value (higher numbers = higher precedence)
70
71
Raises:
72
KeyError: If the operator type is not recognized
73
"""
74
```
75
76
**Usage Example:**
77
78
```python
79
import ast
80
import astor
81
82
# Parse complex expression
83
code = "a + b * c"
84
tree = ast.parse(code, mode='eval')
85
86
# Check precedence to understand grouping
87
binop = tree.body # BinOp for 'a + (b * c)'
88
add_prec = astor.get_op_precedence(binop.op) # Add
89
mult_prec = astor.get_op_precedence(binop.right.op) # Mult
90
91
print(f"Addition precedence: {add_prec}")
92
print(f"Multiplication precedence: {mult_prec}")
93
print(f"Multiplication has higher precedence: {mult_prec > add_prec}")
94
```
95
96
### Operator Symbol Data
97
98
Complete mapping from AST operator types to their string symbols.
99
100
```python { .api }
101
symbol_data: dict
102
```
103
104
This dictionary contains the complete mapping of all Python operators:
105
106
```python
107
import astor
108
109
# Explore all available operators
110
print("Binary operators:")
111
for op_type, symbol in astor.symbol_data.items():
112
if 'op' in op_type.__name__.lower():
113
print(f" {op_type.__name__}: {symbol}")
114
115
# Check specific operators
116
import ast
117
print(f"Add symbol: {astor.symbol_data[ast.Add]}") # +
118
print(f"Mult symbol: {astor.symbol_data[ast.Mult]}") # *
119
print(f"And symbol: {astor.symbol_data[ast.And]}") # and
120
print(f"Or symbol: {astor.symbol_data[ast.Or]}") # or
121
```
122
123
### Precedence Constants
124
125
Class containing precedence values for all Python operators.
126
127
```python { .api }
128
class Precedence:
129
"""
130
Container for operator precedence constants.
131
132
Contains precedence values for all Python operators following
133
Python's operator precedence rules.
134
"""
135
```
136
137
**Available Precedence Constants:**
138
139
```python
140
import astor
141
142
# Access precedence constants
143
print(f"Comma precedence: {astor.Precedence.Comma}") # Lowest
144
print(f"Or precedence: {astor.Precedence.Or}")
145
print(f"And precedence: {astor.Precedence.And}")
146
print(f"Not precedence: {astor.Precedence.Not}")
147
print(f"In precedence: {astor.Precedence.In}")
148
print(f"Compare precedence: {astor.Precedence.Comp}")
149
print(f"BitOr precedence: {astor.Precedence.BitOr}")
150
print(f"BitXor precedence: {astor.Precedence.BitXor}")
151
print(f"BitAnd precedence: {astor.Precedence.BitAnd}")
152
print(f"Shift precedence: {astor.Precedence.Shift}")
153
print(f"Add precedence: {astor.Precedence.Add}")
154
print(f"Mult precedence: {astor.Precedence.Mult}")
155
print(f"UAdd precedence: {astor.Precedence.UAdd}")
156
print(f"Power precedence: {astor.Precedence.Pow}") # Highest
157
```
158
159
## Advanced Operator Handling
160
161
### Expression Parenthesization
162
163
Using operator precedence to determine when parentheses are needed in generated expressions.
164
165
**Usage Example:**
166
167
```python
168
import ast
169
import astor
170
171
def needs_parens(parent_op, child_op, is_right=False):
172
"""Check if child operation needs parentheses."""
173
parent_prec = astor.get_op_precedence(parent_op)
174
child_prec = astor.get_op_precedence(child_op)
175
176
# Lower precedence needs parentheses
177
if child_prec < parent_prec:
178
return True
179
180
# Same precedence on right side of non-associative operators
181
if child_prec == parent_prec and is_right:
182
# Check for right-associative operators (like **)
183
return type(parent_op).__name__ not in ['Pow']
184
185
return False
186
187
# Example usage
188
code = "a - b + c" # Parsed as (a - b) + c
189
tree = ast.parse(code, mode='eval')
190
binop = tree.body
191
192
# Check if we need parentheses for sub-expressions
193
left_needs_parens = needs_parens(binop.op, binop.left.op, is_right=False)
194
print(f"Left side needs parentheses: {left_needs_parens}")
195
```
196
197
### Custom Operator Formatting
198
199
Using the formatting capabilities for specialized code generation.
200
201
**Usage Example:**
202
203
```python
204
import ast
205
import astor
206
207
def format_operator_with_spaces(op_node):
208
"""Format operator with surrounding spaces."""
209
symbol = astor.get_op_symbol(op_node, fmt=' %s ')
210
return symbol
211
212
# Parse and format expression
213
code = "a+b*c"
214
tree = ast.parse(code, mode='eval')
215
216
# Manually format with spacing
217
def add_spaces_to_binops(node):
218
if isinstance(node, ast.BinOp):
219
left = add_spaces_to_binops(node.left)
220
right = add_spaces_to_binops(node.right)
221
op_symbol = format_operator_with_spaces(node.op)
222
return f"{left}{op_symbol}{right}"
223
elif isinstance(node, ast.Name):
224
return node.id
225
elif isinstance(node, ast.Constant):
226
return str(node.value)
227
return str(node)
228
229
formatted = add_spaces_to_binops(tree.body)
230
print(formatted) # "a + b * c"
231
```
232
233
## Deprecated Operator Functions
234
235
For backward compatibility, astor provides deprecated aliases for operator functions:
236
237
```python { .api }
238
# Deprecated aliases (use get_op_symbol instead)
239
def get_boolop(obj): ... # → get_op_symbol
240
def get_binop(obj): ... # → get_op_symbol
241
def get_cmpop(obj): ... # → get_op_symbol
242
def get_unaryop(obj): ... # → get_op_symbol
243
def get_anyop(obj): ... # → get_op_symbol
244
245
# Deprecated alias (use symbol_data instead)
246
all_symbols: dict # → symbol_data
247
```
248
249
These functions are maintained for compatibility but should not be used in new code. Use `get_op_symbol()` and `symbol_data` instead.