Coverage for src/_griffe/agents/nodes/ast.py: 57.32%
60 statements
« prev ^ index » next coverage.py v7.6.2, created at 2024-10-12 01:34 +0200
« prev ^ index » next coverage.py v7.6.2, created at 2024-10-12 01:34 +0200
1# This module contains utilities for navigating AST nodes.
3from __future__ import annotations
5from ast import AST
6from typing import TYPE_CHECKING
8from _griffe.exceptions import LastNodeError
10if TYPE_CHECKING:
11 from collections.abc import Iterator
14def ast_kind(node: AST) -> str:
15 """Return the kind of an AST node.
17 Parameters:
18 node: The AST node.
20 Returns:
21 The node kind.
22 """
23 return node.__class__.__name__.lower()
26def ast_children(node: AST) -> Iterator[AST]:
27 """Return the children of an AST node.
29 Parameters:
30 node: The AST node.
32 Yields:
33 The node children.
34 """
35 for field_name in node._fields:
36 try:
37 field = getattr(node, field_name)
38 except AttributeError:
39 continue
40 if isinstance(field, AST):
41 field.parent = node # type: ignore[attr-defined]
42 yield field
43 elif isinstance(field, list):
44 for child in field:
45 if isinstance(child, AST):
46 child.parent = node # type: ignore[attr-defined]
47 yield child
50def ast_previous_siblings(node: AST) -> Iterator[AST]:
51 """Return the previous siblings of this node, starting from the closest.
53 Parameters:
54 node: The AST node.
56 Yields:
57 The previous siblings.
58 """
59 for sibling in ast_children(node.parent): # type: ignore[attr-defined]
60 if sibling is not node:
61 yield sibling
62 else:
63 return
66def ast_next_siblings(node: AST) -> Iterator[AST]:
67 """Return the next siblings of this node, starting from the closest.
69 Parameters:
70 node: The AST node.
72 Yields:
73 The next siblings.
74 """
75 siblings = ast_children(node.parent) # type: ignore[attr-defined]
76 for sibling in siblings: 76 ↛ 79line 76 didn't jump to line 79 because the loop on line 76 didn't complete
77 if sibling is node:
78 break
79 yield from siblings
82def ast_siblings(node: AST) -> Iterator[AST]:
83 """Return the siblings of this node.
85 Parameters:
86 node: The AST node.
88 Yields:
89 The siblings.
90 """
91 siblings = ast_children(node.parent) # type: ignore[attr-defined]
92 for sibling in siblings:
93 if sibling is not node:
94 yield sibling
95 else:
96 break
97 yield from siblings
100def ast_previous(node: AST) -> AST:
101 """Return the previous sibling of this node.
103 Parameters:
104 node: The AST node.
106 Raises:
107 LastNodeError: When the node does not have previous siblings.
109 Returns:
110 The sibling.
111 """
112 try:
113 *_, last = ast_previous_siblings(node)
114 except ValueError:
115 raise LastNodeError("there is no previous node") from None
116 return last
119def ast_next(node: AST) -> AST:
120 """Return the next sibling of this node.
122 Parameters:
123 node: The AST node.
125 Raises:
126 LastNodeError: When the node does not have next siblings.
128 Returns:
129 The sibling.
130 """
131 try:
132 return next(ast_next_siblings(node))
133 except StopIteration:
134 raise LastNodeError("there is no next node") from None
137def ast_first_child(node: AST) -> AST:
138 """Return the first child of this node.
140 Parameters:
141 node: The AST node.
143 Raises:
144 LastNodeError: When the node does not have children.
146 Returns:
147 The child.
148 """
149 try:
150 return next(ast_children(node))
151 except StopIteration as error:
152 raise LastNodeError("there are no children node") from error
155def ast_last_child(node: AST) -> AST:
156 """Return the lasts child of this node.
158 Parameters:
159 node: The AST node.
161 Raises:
162 LastNodeError: When the node does not have children.
164 Returns:
165 The child.
166 """
167 try:
168 *_, last = ast_children(node)
169 except ValueError as error:
170 raise LastNodeError("there are no children node") from error
171 return last