Skip to content

Commit 24d7817

Browse files
committed
Bring visitor_keys back
Replicates graphql/graphql-js@0091421
1 parent 018c1a2 commit 24d7817

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed

src/graphql/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@
187187
ParallelVisitor,
188188
Visitor,
189189
VisitorAction,
190+
VisitorKeyMap,
190191
BREAK,
191192
SKIP,
192193
REMOVE,
@@ -553,6 +554,7 @@
553554
"TypeInfoVisitor",
554555
"Visitor",
555556
"VisitorAction",
557+
"VisitorKeyMap",
556558
"BREAK",
557559
"SKIP",
558560
"REMOVE",

src/graphql/language/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
Visitor,
2424
ParallelVisitor,
2525
VisitorAction,
26+
VisitorKeyMap,
2627
BREAK,
2728
SKIP,
2829
REMOVE,
@@ -126,6 +127,7 @@
126127
"Visitor",
127128
"ParallelVisitor",
128129
"VisitorAction",
130+
"VisitorKeyMap",
129131
"BREAK",
130132
"SKIP",
131133
"REMOVE",

src/graphql/language/visitor.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"Visitor",
2222
"ParallelVisitor",
2323
"VisitorAction",
24+
"VisitorKeyMap",
2425
"visit",
2526
"BREAK",
2627
"SKIP",
@@ -51,8 +52,10 @@ class VisitorActionEnum(Enum):
5152
REMOVE = VisitorActionEnum.REMOVE
5253
IDLE = None
5354

55+
VisitorKeyMap = Dict[str, Tuple[str, ...]]
56+
5457
# Default map from visitor kinds to their traversable node attributes:
55-
QUERY_DOCUMENT_KEYS: Dict[str, Tuple[str, ...]] = {
58+
QUERY_DOCUMENT_KEYS: VisitorKeyMap = {
5659
"name": (),
5760
"document": ("definitions",),
5861
"operation_definition": (
@@ -76,11 +79,6 @@ class VisitorActionEnum(Enum):
7679
"directives",
7780
"selection_set",
7881
),
79-
"int_value": (),
80-
"float_value": (),
81-
"string_value": (),
82-
"boolean_value": (),
83-
"enum_value": (),
8482
"list_value": ("values",),
8583
"object_value": ("fields",),
8684
"object_field": ("name", "value"),
@@ -212,7 +210,9 @@ class Stack(NamedTuple):
212210
prev: Any # 'Stack' (python/mypy/issues/731)
213211

214212

215-
def visit(root: Node, visitor: Visitor) -> Any:
213+
def visit(
214+
root: Node, visitor: Visitor, visitor_keys: Optional[VisitorKeyMap] = None
215+
) -> Any:
216216
"""Visit each node in an AST.
217217
218218
:func:`~.visit` will walk through an AST using a depth-first traversal, calling the
@@ -227,11 +227,16 @@ def visit(root: Node, visitor: Visitor) -> Any:
227227
When using :func:`~.visit` to edit an AST, the original AST will not be modified,
228228
and a new version of the AST with the changes applied will be returned from the
229229
visit function.
230+
231+
To customize the node attributes to be used for traversal, you can provide a
232+
dictionary visitor_keys mapping node kinds to node attributes.
230233
"""
231234
if not isinstance(root, Node):
232235
raise TypeError(f"Not an AST Node: {inspect(root)}.")
233236
if not isinstance(visitor, Visitor):
234237
raise TypeError(f"Not an AST Visitor: {inspect(visitor)}.")
238+
if visitor_keys is None:
239+
visitor_keys = QUERY_DOCUMENT_KEYS
235240
stack: Any = None
236241
in_array = isinstance(root, list)
237242
keys: Tuple[Node, ...] = (root,)
@@ -326,7 +331,7 @@ def visit(root: Node, visitor: Visitor) -> Any:
326331
else:
327332
stack = Stack(in_array, idx, keys, edits, stack)
328333
in_array = isinstance(node, list)
329-
keys = node if in_array else QUERY_DOCUMENT_KEYS.get(node.kind, ())
334+
keys = node if in_array else visitor_keys.get(node.kind, ())
330335
idx = -1
331336
edits = []
332337
if parent:

tests/language/test_visitor.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
SKIP,
1818
ParallelVisitor,
1919
Visitor,
20+
VisitorKeyMap,
2021
)
2122
from graphql.pyutils import FrozenList
2223

@@ -588,6 +589,41 @@ def leave(node, *_args):
588589
["leave", "document", None],
589590
]
590591

592+
def visits_only_the_specified_kind_in_visitor_key_map():
593+
visited = []
594+
595+
visitor_key_map: VisitorKeyMap = {
596+
"document": ("definitions",),
597+
"operation_definition": ("name",),
598+
}
599+
600+
class TestVisitor(Visitor):
601+
@staticmethod
602+
def enter(node, *_args):
603+
visited.append(["enter", node.kind, get_value(node)])
604+
605+
@staticmethod
606+
def leave(node, *_args):
607+
visited.append(["leave", node.kind, get_value(node)])
608+
609+
example_document_ast = parse(
610+
"""
611+
query ExampleOperation {
612+
someField
613+
}
614+
"""
615+
)
616+
617+
visit(example_document_ast, TestVisitor(), visitor_key_map)
618+
assert visited == [
619+
["enter", "document", None],
620+
["enter", "operation_definition", None],
621+
["enter", "name", "ExampleOperation"],
622+
["leave", "name", "ExampleOperation"],
623+
["leave", "operation_definition", None],
624+
["leave", "document", None],
625+
]
626+
591627
def cannot_define_visitor_with_unknown_ast_nodes():
592628
with raises(TypeError) as exc_info:
593629

0 commit comments

Comments
 (0)