# node_visitor

URL: /kida/api/analysis/node_visitor/
Section: analysis
Description: Unified AST Visitor and Transformer base classes.

Provides ``NodeVisitor`` and ``NodeTransformer`` with automatic
``visit_<Type>`` dispatch, eliminating the need for every analysis module
to implement its own traversal logic.

Adding a new AST node type requires zero changes to visitor code —
``generic_visit`` uses ``Node.iter_child_nodes()`` (backed by
``__dataclass_fields__`` introspection) to discover children automatically.

Usage::

    class MyAnalyzer(NodeVisitor):
        def visit_Name(self, node: Name) -> None:
            print(f"Found name: {node.name}")

        def visit_Filter(self, node: Filter) -> None:
            print(f"Found filter: {node.name}")
            self.generic_visit(node)  # visit children too

    class MyOptimizer(NodeTransformer):
        def visit_Const(self, node: Const) -> Node:
            if isinstance(node.value, str):
                return Const(lineno=node.lineno, col_offset=node.col_offset,
                             value=node.value.upper())
            return node

---

> For a complete page index, fetch /kida/llms.txt.

Open LLM text
(/kida/api/analysis/node_visitor/index.txt)

Share with AI

Ask Claude
(https://claude.ai/new?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fanalysis%2Fnode_visitor%2Findex.txt)

Ask ChatGPT
(https://chatgpt.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fanalysis%2Fnode_visitor%2Findex.txt)

Ask Gemini
(https://gemini.google.com/app?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fanalysis%2Fnode_visitor%2Findex.txt)

Ask Copilot
(https://copilot.microsoft.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fanalysis%2Fnode_visitor%2Findex.txt)

Module

#
`analysis.node_visitor`

Unified AST Visitor and Transformer base classes.

Provides`NodeVisitor` and `NodeTransformer`with automatic
`visit_<Type>`dispatch, eliminating the need for every analysis module
to implement its own traversal logic.

Adding a new AST node type requires zero changes to visitor code —
`generic_visit` uses `Node.iter_child_nodes()`(backed by
`__dataclass_fields__`introspection) to discover children automatically.

Usage::

```
class MyAnalyzer(NodeVisitor):
    def visit_Name(self, node: Name) -> None:
        print(f"Found name: {node.name}")

    def visit_Filter(self, node: Filter) -> None:
        print(f"Found filter: {node.name}")
        self.generic_visit(node)  # visit children too

class MyOptimizer(NodeTransformer):
    def visit_Const(self, node: Const) -> Node:
        if isinstance(node.value, str):
            return Const(lineno=node.lineno, col_offset=node.col_offset,
                         value=node.value.upper())
        return node
```

2Classes

## Classes

`NodeVisitor`

4

▼

Walk a Kida AST calling ``visit_<Type>`` methods on each node.

For every node encountered, ``visit…

Walk a Kida AST calling`visit_<Type>`methods on each node.

For every node encountered,`visit()` checks for a `visit_<Type>`
method (where`<Type>` is `type(node).__name__`) and calls it.
If no specific method exists,`generic_visit()`is called, which
visits all child nodes.

Subclasses override`visit_<Type>`to handle specific node types.
Call`self.generic_visit(node)`inside a handler to also visit children.

#### Attributes

Name
Type
Description

`_dispatch_cache`

`ClassVar[dict[type, Any]]`

—

#### Methods

`visit`

1

`Any`

▼

Dispatch to ``visit_`` or ``generic_visit``.

`def visit(self, node: Node) -> Any`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`Any`

`generic_visit`

1

▼

Visit all child nodes (default handler).

`def generic_visit(self, node: Node) -> None`

##### Parameters

Name
Type
Description

`node`
`—`

Internal Methods
1

▼

`__init_subclass__`

1

▼

`def __init_subclass__(cls, **kwargs: Any) -> None`

##### Parameters

Name
Type
Description

`**kwargs`
`—`

`NodeTransformer`

7

▼

Walk a Kida AST and rebuild nodes when ``visit_<Type>`` returns a replacement.

Similar to ``NodeVi…

Walk a Kida AST and rebuild nodes when`visit_<Type>`returns a replacement.

Similar to`NodeVisitor`but each handler returns a (possibly new) node.
`generic_visit()`visits all child fields; if any child changes, the
parent node is reconstructed via`dataclasses.replace()`.

Subclasses override`visit_<Type>`to transform specific node types.
Returning`None`from a handler removes the node from its parent's body.

#### Attributes

Name
Type
Description

`_dispatch_cache`

`ClassVar[dict[type, Any]]`

—

#### Methods

`visit`

1

`Node | None`

▼

Dispatch to ``visit_`` or ``generic_visit``.

`def visit(self, node: Node) -> Node | None`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`Node | None`

`generic_visit`

1

`Node`

▼

Rebuild *node* if any child field changed after visiting.

`def generic_visit(self, node: Node) -> Node`

##### Parameters

Name
Type
Description

`node`
`—`

##### Returns

`Node`

Internal Methods
4

▼

`__init_subclass__`

1

▼

`def __init_subclass__(cls, **kwargs: Any) -> None`

##### Parameters

Name
Type
Description

`**kwargs`
`—`

`_visit_field`

1

`Any`

▼

Visit a single field value, returning updated value if changed.

`def _visit_field(self, value: Any) -> Any`

##### Parameters

Name
Type
Description

`value`
`—`

##### Returns

`Any`

`_visit_sequence`

1

`Sequence[Any]`

▼

Visit a sequence, handling nested tuples (elif_, cases, etc.).

`def _visit_sequence(self, seq: Sequence[Any]) -> Sequence[Any]`

##### Parameters

Name
Type
Description

`seq`
`—`

##### Returns

`Sequence[Any]`

`_visit_dict`

1

`dict[str, Any]`

▼

Visit dict values (kwargs, slots, embed blocks, etc.).

`def _visit_dict(self, mapping: dict[str, Any]) -> dict[str, Any]`

##### Parameters

Name
Type
Description

`mapping`
`—`

##### Returns

`dict[str, Any]`
