Get the currently executing AST node of a frame, and other information
npx @tessl/cli install tessl/pypi-executing@2.2.0Get 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.
pip install executingimport executingFor pytest compatibility checking:
from executing import is_pytest_compatibleimport executing
import inspect
def example_function():
# Get the currently executing AST node
frame = inspect.currentframe()
node = executing.Source.executing(frame).node
if node:
# Get the source code of the executing node
source_text = executing.Source.executing(frame).text()
print(f"Currently executing: {source_text}")
# Get the qualified name of the current function
qualname = executing.Source.executing(frame).code_qualname()
print(f"Function qualname: {qualname}")
else:
print("Could not identify the executing node")
# Usage with traceback objects
try:
some_function()
except Exception:
import sys
tb = sys.exc_info()[2]
node = executing.Source.executing(tb).node
if node:
print(f"Exception occurred at: {executing.Source.executing(tb).text()}")The executing library works by analyzing bytecode instructions and matching them to AST nodes through compilation tricks:
The library supports identifying Call, Attribute, Subscript, BinOp, UnaryOp, and Compare AST node types through clever bytecode inspection and AST modification techniques.
Get information about what a frame is currently executing, including the AST node being executed and associated metadata.
class Source:
@classmethod
def executing(cls, frame_or_tb) -> "Executing":
"""
Returns an Executing object representing the operation
currently executing in the given frame or traceback object.
Parameters:
- frame_or_tb: types.FrameType or types.TracebackType
Returns:
Executing object with node, source, and metadata
"""
@classmethod
def for_frame(cls, frame, use_cache=True) -> "Source":
"""
Returns the Source object corresponding to the file the frame is executing in.
Parameters:
- frame: types.FrameType - the frame to analyze
- use_cache: bool - whether to use cached Source instances
Returns:
Source object for the frame's file
"""
@classmethod
def for_filename(cls, filename, module_globals=None, use_cache=True) -> "Source":
"""
Returns Source object for a specific filename.
Parameters:
- filename: str or Path - path to the source file
- module_globals: dict, optional - module globals for linecache
- use_cache: bool - whether to use cached instances
Returns:
Source object for the specified file
"""Analyze source files and extract information about AST nodes, statements, and code structure.
class Source:
def statements_at_line(self, lineno) -> Set[ast.stmt]:
"""
Returns the statement nodes overlapping the given line.
Parameters:
- lineno: int - line number to analyze
Returns:
Set of AST statement nodes at the specified line
"""
def asttokens(self) -> "ASTTokens":
"""
Returns an ASTTokens object for getting the source of specific AST nodes.
Requires asttokens library to be installed separately.
Returns:
ASTTokens object for source code analysis
"""
def asttext(self) -> "ASTText":
"""
Returns an ASTText object for getting the source of specific AST nodes.
Requires asttokens library to be installed separately.
Returns:
ASTText object for source code analysis
"""
def code_qualname(self, code) -> str:
"""
Imitates the __qualname__ attribute of functions for code objects.
Parameters:
- code: types.CodeType - code object to analyze
Returns:
Qualified name string for the code object
"""Access detailed information about the currently executing operation, including source text and qualified names.
class Executing:
def code_qualname(self) -> str:
"""
Returns the qualified name of the function being executed.
Returns:
String representing the function's qualified name
"""
def text(self) -> str:
"""
Returns the source code text of the executing node.
Requires asttokens library to be installed separately.
Returns:
Source code string of the executing AST node
"""
def text_range(self) -> Tuple[int, int]:
"""
Returns the character range of the executing node in the source.
Requires asttokens library to be installed separately.
Returns:
Tuple of (start_pos, end_pos) character positions
"""Helper functions for working with iterables and checking compatibility with testing frameworks.
def only(it: Iterable[T]) -> T:
"""
Extract single value from iterable, raising NotOneValueFound if not exactly one.
Parameters:
- it: Iterable[T] - iterable to extract value from
Returns:
T - The single value from the iterable
Raises:
NotOneValueFound - if iterable contains zero or multiple values
"""
def is_pytest_compatible() -> bool:
"""
Returns True if executing can be used for expressions inside assert statements
which are rewritten by pytest. Requires Python 3.11+ and pytest 8.3.4+.
Returns:
Boolean indicating pytest compatibility
"""
cache = lru_cache(maxsize=None)
"""LRU cache with no size limit for performance optimization."""
future_flags: int
"""
Sum of all __future__ compiler flags.
This is calculated as:
sum(getattr(__future__, fname).compiler_flag for fname in __future__.all_feature_names)
Used internally for compiling code with the same future imports as the original code.
"""Static methods for handling source code encoding and text processing.
class Source:
@staticmethod
def decode_source(source) -> str:
"""
Decode source code from bytes or return string as-is.
Parameters:
- source: str or bytes - source code to decode
Returns:
Decoded source code as string
"""
@staticmethod
def detect_encoding(source) -> str:
"""
Detect encoding of source code bytes.
Parameters:
- source: bytes - source code bytes
Returns:
Encoding name as string
"""class Executing:
"""
Information about the operation a frame is currently executing.
Attributes:
- frame: types.FrameType - the frame being analyzed
- source: Source - Source object for the frame's file
- node: ast.AST or None - AST node being executed
- statements: Set[ast.stmt] - set of statement nodes
- decorator: ast.AST or None - decorator expression being called (if applicable)
"""
class Source:
"""
The source code of a single file and associated metadata.
Attributes:
- filename: str - source filename
- text: str - complete source text
- lines: List[str] - list of source lines
- tree: ast.Module or None - AST parsed from text (None if invalid Python)
"""
class NotOneValueFound(Exception):
"""
Raised when expected exactly one value but got zero or multiple.
Attributes:
- values: Sequence - values found when multiple (empty when zero)
"""
class KnownIssue(Exception):
"""
Raised in case of a known problem, mostly because of CPython bugs.
Executing.node gets set to None in this case.
"""
class VerifierFailure(Exception):
"""
Thrown for an unexpected mapping from instruction to AST node.
Executing.node gets set to None in this case.
Attributes:
- node: object - the AST node that failed verification
- instruction: object - the bytecode instruction that failed verification
"""The executing library handles various edge cases and potential issues:
None for tree attribute in Source objectsNone for node attribute in Executing objectsasttokens will raise ImportError if not installedAlways check if the returned node is not None before using it, as node identification may fail in complex cases or with certain bytecode optimizations.
The executing library can currently identify these AST node types:
func(), obj.method())obj.attr)lst[0], dict['key'])x + y, a * b) - excludes and/or-x, not condition) - not has limited supporta < b, x == y) - excludes chained comparisonsThe library works by modifying AST nodes with sentinel values and analyzing the resulting bytecode changes to determine which node corresponds to the current instruction.