executing

Identifies the exact AST node a Python stack frame is currently executing, powering rich tracebacks and debugging tools

Library
PyPI
v2.2.1
400stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
59/100Fair
Development Activity60
Maintenance36
Community60
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture82
Code Quality80
Innovation85
Learning Curve65

executing is a small, dependency-free Python library that determines exactly which AST node a given stack frame is executing at the bytecode level. Given a frame or traceback object, executing.Source.executing(frame).node returns the precise ast node for the statement or expression currently running, something Python’s own traceback/inspect modules only approximate by line number.

Because a single source line can contain many sub-expressions (e.g. chained calls, comprehensions, nested function calls), knowing the line alone is often insufficient to say what actually raised an exception or is currently executing. executing solves this by disassembling bytecode and correlating instruction offsets back to AST nodes, and it has become a foundational dependency of several popular debugging and tracing tools, including stack_data, rich (for its tracebacks), icecream, friendly-traceback, and IPython/ipdb.

What You Get

  • executing.Source.executing(frame).node returning the exact ast node object for the frame’s current instruction, memoized so the same call site always returns the same node instance
  • Support for both live frame objects and traceback objects (using the traceback’s associated frame and last instruction rather than tb_frame alone)
  • code_qualname() for retrieving a function’s fully qualified name (module + enclosing scope path) from a frame or code object
  • Integration with the optional asttokens library for extracting exact source text and text ranges for the identified node via .text()/.text_range()
  • A Source class (one instance per filename) designed for subclassing, so tools can attach their own cached attributes to parsed source files

Common Use Cases

  • Building rich tracebacks that highlight the exact sub-expression that raised an exception, not just the line (as used by the rich library)
  • Powering debug-print utilities (like icecream) that need to show both the source expression and its value at a call site
  • Implementing REPL/notebook introspection tools (IPython, ipdb) that need to know precisely what code produced the current frame’s exception
  • Writing custom error-reporting or tracing tools that need expression-level granularity beyond what traceback/linecache provide by default

Under The Hood

Architecture - The core algorithm (executing.py, _position_node_finder.py) disassembles the code object’s bytecode with the standard dis module, walks the AST of the parsed source, and matches instruction offsets/positions to candidate AST nodes, disambiguating cases (like nested calls on one line) using CPython-version-specific bytecode knowledge; results are cached per Source instance keyed by filename so repeated lookups for the same file are cheap. Tech Stack - Pure Python 3 with zero required runtime dependencies (the asttokens integration for text extraction is optional), split across executing.py (~1050 lines) and _position_node_finder.py (~1045 lines) to isolate the Python-version-specific bytecode position-finding logic from the general frame/source API; packaged with pyproject.toml and a uv.lock for reproducible dev environments. Code Quality - The tests/ suite includes test_main.py, test_ipython.py, test_pytest.py, and a mutmut_workflow.py for mutation testing, plus a large corpus of sample source files (tests/samples, tests/small_samples) used to validate node-identification correctness across diverse code shapes and Python versions; the project ships py.typed for static type checking. API Design - The entire public surface is small and stable (Source.executing(frame), .node, .text(), code_qualname()), designed to be embedded inside other debugging libraries rather than used directly by end users, so the API favors predictability and version-compatibility (supporting Python 3.5+ and PyPy) over feature breadth.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search