API reference

This page is a compact reference for Pyccolo’s public API. The narrative pages under Concepts are the best way to learn the library; this appendix is for looking things up.

Everything documented here is importable from the top-level pyccolo package (conventionally imported as pyc).

Tracers

class pyccolo.BaseTracer(*args, **kwargs)[source]
should_instrument_file(filename: str) bool
classmethod activate_guard(guard: str | int | AST) None
classmethod deactivate_guard(guard: str | int | AST) None
defined_file = '/home/docs/checkouts/readthedocs.org/user_builds/pyccolo/envs/stable/lib/python3.12/site-packages/pyccolo/tracer.py'
classmethod stmt_only_has_ancestor_types(node_or_id: int | AST, ancestor_types: Tuple[Type[AST], ...])[source]
classmethod is_outer_stmt(node_or_id, exclude_outer_stmt_types=None)[source]
classmethod is_initial_frame_stmt(node_or_id: int | AST)[source]
class pyccolo.NoopTracer(*args, **kwargs)[source]

Registering handlers

pyccolo.register_handler(event: TraceEvent | Type[AST] | Tuple[TraceEvent | Type[AST], ...], when: Callable[[...], bool] | Predicate | None = None, reentrant: bool = False, static: bool = False, use_raw_node_id: bool = False, guard: Callable[[AST], str] | None = None, exempt_from_guards: bool = False)[source]
pyccolo.register_raw_handler(event: TraceEvent | Type[AST] | Tuple[TraceEvent | Type[AST], ...], **kwargs)[source]
pyccolo.skip_when_tracing_disabled(handler)[source]

Every member of TraceEvent is also re-exported as a module-level decorator, so @pyc.before_stmt is sugar for register_handler(pyc.before_stmt) and accepts the same keyword arguments (when=, reentrant=, …).

Running instrumented code

pyccolo.exec(code: str | Module | stmt, *args, **kwargs) Dict[str, Any][source]
pyccolo.eval(code: str | expr | Expression, *args, **kwargs) Any[source]
pyccolo.execute(*args, **kwargs) Dict[str, Any][source]
pyccolo.parse(code: str, mode: str = 'exec', instrument: bool = True) Module | Expression[source]
pyccolo.instrumented(tracers: List[BaseTracer], mutate: bool = False) Callable[[Callable[[...], Any]], Callable[[...], Any]][source]
pyccolo.tracer() BaseTracer[source]
pyccolo.instance() BaseTracer[source]

Tracing contexts

pyccolo.tracing_context(tracers=None, *args, **kwargs)[source]
pyccolo.tracing_enabled(tracers=None, **kwargs)[source]
pyccolo.tracing_disabled(tracers=None, **kwargs)[source]
pyccolo.multi_context(cms)[source]

Source-to-source

pyccolo.transform(code: str, tracers: List[BaseTracer] | None = None, positions: None = None, pure: bool = False) str[source]
pyccolo.transform(code: str, tracers: List[BaseTracer] | None, positions: List[Tuple[int, int]], pure: bool = False) Tuple[str, List[Position]]
pyccolo.transform(code: str, *, positions: List[Tuple[int, int]], pure: bool = False) Tuple[str, List[Position]]
pyccolo.untransform(tree: AST, tracers: List[BaseTracer] | None = None, positions: None = None, pure: bool = False) str[source]
pyccolo.untransform(tree: AST, tracers: List[BaseTracer] | None, positions: List[Tuple[int, int]], pure: bool = False) Tuple[str, List[Position]]
pyccolo.untransform(tree: AST, *, positions: List[Tuple[int, int]], pure: bool = False) Tuple[str, List[Position]]
pyccolo.is_pure_transform() bool[source]

True while a pure=True transform/untransform is running on this thread / async context. Cooperating CustomRewrite.rewrite / paired-delimiter emit callbacks must not mutate execution-relevant state (e.g. process-global registries the runtime later reads) when this is set – the transformed code is being inspected, not executed.

Predicates

class pyccolo.Predicate(condition: Callable[[AST], bool], use_raw_node_id: Literal[False], static: bool = True)[source]
class pyccolo.Predicate(condition: Callable[[int], bool], use_raw_node_id: Literal[True], static: bool = False)
class pyccolo.Predicate(condition: Callable[[...], bool], use_raw_node_id: bool = False, static: bool = False)
class pyccolo.predicate.CompositePredicate(base_predicates: ~typing.Sequence[~pyccolo.predicate.Predicate], reducer=<built-in function any>)[source]

Syntax augmentation

class pyccolo.AugmentationSpec(aug_type, token, replacement, close_token, close_replacement, name_pattern, body_func_wrapper, custom)[source]
aug_type: AugmentationType

Alias for field number 0

token: str

Alias for field number 1

replacement: str

Alias for field number 2

close_token: str | None

Alias for field number 3

close_replacement: str | None

Alias for field number 4

name_pattern: str | None

Alias for field number 5

body_func_wrapper: str | None

Alias for field number 6

custom: CustomRewrite | None

Alias for field number 7

class pyccolo.AugmentationType(*values)[source]
prefix = 'prefix'
suffix = 'suffix'
dot_prefix = 'dot_prefix'
dot_suffix = 'dot_suffix'
binop = 'binop'
boolop = 'boolop'
call = 'call'
subscript = 'subscript'
custom = 'custom'
class pyccolo.CustomRewrite[source]

Drives a AugmentationType.custom spec. A cooperating tracer that needs a context-sensitive surface rewrite (one the static token/paired passes can’t express – e.g. a token whose meaning depends on the preceding token, or a per-occurrence choice between two lowerings) implements these three methods so the rewrite participates in pyccolo’s position-remapping and untransform machinery uniformly, instead of bolting on a parallel resugaring path.

Subclassing is optional (the methods are duck-typed); it just documents intent.

rewrite(code: str, register: Callable[[int, int], None]) Tuple[str, List[Tuple[int, int, int]]][source]

Forward-rewrite code -> (new_code, edits).

edits are (start, end, new_len) triples in code’s input absolute offsets – sorted ascending and disjoint, the same shape replace_tokens_and_get_augmented_positions() builds – so the caller can remap tracked positions through them with remap_through_edits(). For each rewritten occurrence whose resulting AST node should be reverse-handled by untransform, call register(line, col) with the 1-indexed line / 0-indexed col of the node’s anchor in ``new_code`` (the location range_for() will re-derive on the parsed node).

range_for(node: AST) Range | None[source]

Anchor Range of a rewritten node (mirrors the built-in _get_<aug_type>_range_for helpers), or None if node is not one this rewrite produced. Used both to bind the registered position forward and to locate the node during untransform.

reverse(node: AST, spec: AugmentationSpec, aug_range: Range, code: str, line_starts: List[int]) Tuple[int, int, str] | None[source]

Reverse (resugar) splice (start, end, new_text) on valid code, or None to leave node untouched. A single whole-span edit suffices; the caller applies edits right-to-left.

class pyccolo.AstRewriter(tracers: List[BaseTracer], path: str, module_id: int | None = None)[source]
visit(node: AST, instrument: bool = True)[source]

Visit a node.

State

class pyccolo.TraceStack(manager: _InternalBaseTracer)[source]
push()[source]

Checks at the end of the context that everything requiring manual init was manually inited.

Return-value sentinels

Handlers use these sentinels to express intents that a bare return cannot (see The model: events and handlers):

  • pyccolo.Null — override the instrumented value with None (as opposed to “no override”, which is what returning None means).

  • pyccolo.Skip — stop running further handlers for the current event on this tracer.

  • pyccolo.SkipAll — abort the entire tracer stack for the current event.

  • pyccolo.Pass — an explicit “do nothing / no override” marker.

The event taxonomy

class pyccolo.trace_events.TraceEvent(*values)[source]

All events are members of pyccolo.trace_events.TraceEvent, each re-exported as pyc.<name>. The complete list (100+ events) is defined in pyccolo/trace_events.py. Grouped by what they instrument:

  • Statements: before_stmt, after_stmt, after_module_stmt, after_expr_stmt.

  • Names & assignments: load_name, after_assign_rhs, before_augassign_rhs / after_augassign_rhs.

  • Attributes: before_attribute_load / after_attribute_load, before_attribute_store, before_attribute_del.

  • Subscripts: before_subscript_load / after_subscript_load, before_subscript_store, before_subscript_del, _load_saved_slice.

  • Literals: after_int, after_float, after_complex, after_string, after_bytes, after_list_literal, after_dict_literal, after_set_literal, after_tuple_literal, ellipsis.

  • Operators: before_binop / after_binop, before_unaryop / after_unaryop, before_boolop / after_boolop, before_compare / after_compare, and the *_arg variants.

  • Comprehensions & calls: the comprehension events, before_call / after_call, and the argument events.

  • Control flow: the loop events (before_for_loop_body, after_for_loop_iter, after_while_loop_iter, …), after_if_test, after_while_test.

  • Functions: before_function_body, after_function_execution, before_lambda / after_lambda_body.

  • Imports & module lifecycle: before_import, init_module, exit_module.

  • ``sys``-level events (see Compatibility with sys.settrace): call, line, return_, exception, opcode.