0
# Executing
1
2
Get information about what a frame is currently doing, particularly the AST node being executed. This mini-library enables Python developers to determine which AST node is currently executing in a frame, obtain the source code of that node, and get the qualname of the current function. Designed for debugging tools, development utilities, and introspection libraries.
3
4
## Package Information
5
6
- **Package Name**: executing
7
- **Package Type**: pypi
8
- **Language**: Python
9
- **Installation**: `pip install executing`
10
11
## Core Imports
12
13
```python
14
import executing
15
```
16
17
For pytest compatibility checking:
18
19
```python
20
from executing import is_pytest_compatible
21
```
22
23
## Basic Usage
24
25
```python
26
import executing
27
import inspect
28
29
def example_function():
30
# Get the currently executing AST node
31
frame = inspect.currentframe()
32
node = executing.Source.executing(frame).node
33
34
if node:
35
# Get the source code of the executing node
36
source_text = executing.Source.executing(frame).text()
37
print(f"Currently executing: {source_text}")
38
39
# Get the qualified name of the current function
40
qualname = executing.Source.executing(frame).code_qualname()
41
print(f"Function qualname: {qualname}")
42
else:
43
print("Could not identify the executing node")
44
45
# Usage with traceback objects
46
try:
47
some_function()
48
except Exception:
49
import sys
50
tb = sys.exc_info()[2]
51
node = executing.Source.executing(tb).node
52
if node:
53
print(f"Exception occurred at: {executing.Source.executing(tb).text()}")
54
```
55
56
## Architecture
57
58
The executing library works by analyzing bytecode instructions and matching them to AST nodes through compilation tricks:
59
60
- **Source**: Manages source code files and their AST representations, caching instances by filename
61
- **Executing**: Represents information about what operation a frame is currently executing
62
- **Node Matching**: Uses bytecode analysis with sentinel transformations to identify which AST node corresponds to the current instruction
63
- **AST Enhancement**: Adds parent references to AST nodes for navigation and analysis
64
65
The library supports identifying Call, Attribute, Subscript, BinOp, UnaryOp, and Compare AST node types through clever bytecode inspection and AST modification techniques.
66
67
## Capabilities
68
69
### Frame Analysis
70
71
Get information about what a frame is currently executing, including the AST node being executed and associated metadata.
72
73
```python { .api }
74
class Source:
75
@classmethod
76
def executing(cls, frame_or_tb) -> "Executing":
77
"""
78
Returns an Executing object representing the operation
79
currently executing in the given frame or traceback object.
80
81
Parameters:
82
- frame_or_tb: types.FrameType or types.TracebackType
83
84
Returns:
85
Executing object with node, source, and metadata
86
"""
87
88
@classmethod
89
def for_frame(cls, frame, use_cache=True) -> "Source":
90
"""
91
Returns the Source object corresponding to the file the frame is executing in.
92
93
Parameters:
94
- frame: types.FrameType - the frame to analyze
95
- use_cache: bool - whether to use cached Source instances
96
97
Returns:
98
Source object for the frame's file
99
"""
100
101
@classmethod
102
def for_filename(cls, filename, module_globals=None, use_cache=True) -> "Source":
103
"""
104
Returns Source object for a specific filename.
105
106
Parameters:
107
- filename: str or Path - path to the source file
108
- module_globals: dict, optional - module globals for linecache
109
- use_cache: bool - whether to use cached instances
110
111
Returns:
112
Source object for the specified file
113
"""
114
```
115
116
### Source Code Analysis
117
118
Analyze source files and extract information about AST nodes, statements, and code structure.
119
120
```python { .api }
121
class Source:
122
def statements_at_line(self, lineno) -> Set[ast.stmt]:
123
"""
124
Returns the statement nodes overlapping the given line.
125
126
Parameters:
127
- lineno: int - line number to analyze
128
129
Returns:
130
Set of AST statement nodes at the specified line
131
"""
132
133
def asttokens(self) -> "ASTTokens":
134
"""
135
Returns an ASTTokens object for getting the source of specific AST nodes.
136
Requires asttokens library to be installed separately.
137
138
Returns:
139
ASTTokens object for source code analysis
140
"""
141
142
def asttext(self) -> "ASTText":
143
"""
144
Returns an ASTText object for getting the source of specific AST nodes.
145
Requires asttokens library to be installed separately.
146
147
Returns:
148
ASTText object for source code analysis
149
"""
150
151
def code_qualname(self, code) -> str:
152
"""
153
Imitates the __qualname__ attribute of functions for code objects.
154
155
Parameters:
156
- code: types.CodeType - code object to analyze
157
158
Returns:
159
Qualified name string for the code object
160
"""
161
```
162
163
### Execution Information
164
165
Access detailed information about the currently executing operation, including source text and qualified names.
166
167
```python { .api }
168
class Executing:
169
def code_qualname(self) -> str:
170
"""
171
Returns the qualified name of the function being executed.
172
173
Returns:
174
String representing the function's qualified name
175
"""
176
177
def text(self) -> str:
178
"""
179
Returns the source code text of the executing node.
180
Requires asttokens library to be installed separately.
181
182
Returns:
183
Source code string of the executing AST node
184
"""
185
186
def text_range(self) -> Tuple[int, int]:
187
"""
188
Returns the character range of the executing node in the source.
189
Requires asttokens library to be installed separately.
190
191
Returns:
192
Tuple of (start_pos, end_pos) character positions
193
"""
194
```
195
196
### Utility Functions
197
198
Helper functions for working with iterables and checking compatibility with testing frameworks.
199
200
```python { .api }
201
def only(it: Iterable[T]) -> T:
202
"""
203
Extract single value from iterable, raising NotOneValueFound if not exactly one.
204
205
Parameters:
206
- it: Iterable[T] - iterable to extract value from
207
208
Returns:
209
T - The single value from the iterable
210
211
Raises:
212
NotOneValueFound - if iterable contains zero or multiple values
213
"""
214
215
def is_pytest_compatible() -> bool:
216
"""
217
Returns True if executing can be used for expressions inside assert statements
218
which are rewritten by pytest. Requires Python 3.11+ and pytest 8.3.4+.
219
220
Returns:
221
Boolean indicating pytest compatibility
222
"""
223
224
cache = lru_cache(maxsize=None)
225
"""LRU cache with no size limit for performance optimization."""
226
227
future_flags: int
228
"""
229
Sum of all __future__ compiler flags.
230
231
This is calculated as:
232
sum(getattr(__future__, fname).compiler_flag for fname in __future__.all_feature_names)
233
234
Used internally for compiling code with the same future imports as the original code.
235
"""
236
```
237
238
### Source Utilities
239
240
Static methods for handling source code encoding and text processing.
241
242
```python { .api }
243
class Source:
244
@staticmethod
245
def decode_source(source) -> str:
246
"""
247
Decode source code from bytes or return string as-is.
248
249
Parameters:
250
- source: str or bytes - source code to decode
251
252
Returns:
253
Decoded source code as string
254
"""
255
256
@staticmethod
257
def detect_encoding(source) -> str:
258
"""
259
Detect encoding of source code bytes.
260
261
Parameters:
262
- source: bytes - source code bytes
263
264
Returns:
265
Encoding name as string
266
"""
267
```
268
269
## Types
270
271
```python { .api }
272
class Executing:
273
"""
274
Information about the operation a frame is currently executing.
275
276
Attributes:
277
- frame: types.FrameType - the frame being analyzed
278
- source: Source - Source object for the frame's file
279
- node: ast.AST or None - AST node being executed
280
- statements: Set[ast.stmt] - set of statement nodes
281
- decorator: ast.AST or None - decorator expression being called (if applicable)
282
"""
283
284
class Source:
285
"""
286
The source code of a single file and associated metadata.
287
288
Attributes:
289
- filename: str - source filename
290
- text: str - complete source text
291
- lines: List[str] - list of source lines
292
- tree: ast.Module or None - AST parsed from text (None if invalid Python)
293
"""
294
295
class NotOneValueFound(Exception):
296
"""
297
Raised when expected exactly one value but got zero or multiple.
298
299
Attributes:
300
- values: Sequence - values found when multiple (empty when zero)
301
"""
302
303
class KnownIssue(Exception):
304
"""
305
Raised in case of a known problem, mostly because of CPython bugs.
306
Executing.node gets set to None in this case.
307
"""
308
309
class VerifierFailure(Exception):
310
"""
311
Thrown for an unexpected mapping from instruction to AST node.
312
Executing.node gets set to None in this case.
313
314
Attributes:
315
- node: object - the AST node that failed verification
316
- instruction: object - the bytecode instruction that failed verification
317
"""
318
```
319
320
## Error Handling
321
322
The executing library handles various edge cases and potential issues:
323
324
- **Invalid Python code**: Returns `None` for `tree` attribute in Source objects
325
- **Unidentifiable nodes**: Returns `None` for `node` attribute in Executing objects
326
- **Missing dependencies**: Methods requiring `asttokens` will raise ImportError if not installed
327
- **Bytecode analysis failures**: Gracefully handles cases where AST-to-bytecode matching fails
328
329
Always check if the returned `node` is not `None` before using it, as node identification may fail in complex cases or with certain bytecode optimizations.
330
331
## Supported AST Node Types
332
333
The executing library can currently identify these AST node types:
334
335
- **Call**: Function and method calls (e.g., `func()`, `obj.method()`)
336
- **Attribute**: Attribute access (e.g., `obj.attr`)
337
- **Subscript**: Indexing and slicing (e.g., `lst[0]`, `dict['key']`)
338
- **BinOp**: Binary operations (e.g., `x + y`, `a * b`) - excludes `and`/`or`
339
- **UnaryOp**: Unary operations (e.g., `-x`, `not condition`) - `not` has limited support
340
- **Compare**: Comparison operations (e.g., `a < b`, `x == y`) - excludes chained comparisons
341
342
The library works by modifying AST nodes with sentinel values and analyzing the resulting bytecode changes to determine which node corresponds to the current instruction.