1
1
from graphql .core .language .ast import Field , Name , SelectionSet
2
2
from graphql .core .language .parser import parse
3
- from graphql .core .language .visitor import BREAK , REMOVE , Visitor , visit
3
+ from graphql .core .language .visitor import BREAK , REMOVE , Visitor , visit , ParallelVisitor
4
4
5
5
from .fixtures import KITCHEN_SINK
6
6
@@ -50,7 +50,8 @@ def enter(self, node, *args):
50
50
selections = []
51
51
if selection_set :
52
52
selections = selection_set .selections
53
- new_selection_set = SelectionSet (selections = [added_field ] + selections )
53
+ new_selection_set = SelectionSet (
54
+ selections = [added_field ] + selections )
54
55
return Field (name = None , selection_set = new_selection_set )
55
56
if node is added_field :
56
57
self .did_visit_added_field = True
@@ -67,12 +68,14 @@ def test_allows_skipping_a_subtree():
67
68
class TestVisitor (Visitor ):
68
69
69
70
def enter (self , node , * args ):
70
- visited .append (['enter' , type (node ).__name__ , getattr (node , 'value' , None )])
71
+ visited .append (
72
+ ['enter' , type (node ).__name__ , getattr (node , 'value' , None )])
71
73
if isinstance (node , Field ) and node .name .value == 'b' :
72
74
return False
73
75
74
76
def leave (self , node , * args ):
75
- visited .append (['leave' , type (node ).__name__ , getattr (node , 'value' , None )])
77
+ visited .append (
78
+ ['leave' , type (node ).__name__ , getattr (node , 'value' , None )])
76
79
77
80
visit (ast , TestVisitor ())
78
81
@@ -102,12 +105,14 @@ def test_allows_early_exit_while_visiting():
102
105
class TestVisitor (Visitor ):
103
106
104
107
def enter (self , node , * args ):
105
- visited .append (['enter' , type (node ).__name__ , getattr (node , 'value' , None )])
108
+ visited .append (
109
+ ['enter' , type (node ).__name__ , getattr (node , 'value' , None )])
106
110
if isinstance (node , Name ) and node .value == 'x' :
107
111
return BREAK
108
112
109
113
def leave (self , node , * args ):
110
- visited .append (['leave' , type (node ).__name__ , getattr (node , 'value' , None )])
114
+ visited .append (
115
+ ['leave' , type (node ).__name__ , getattr (node , 'value' , None )])
111
116
112
117
visit (ast , TestVisitor ())
113
118
@@ -135,13 +140,16 @@ def test_allows_a_named_functions_visitor_api():
135
140
class TestVisitor (Visitor ):
136
141
137
142
def enter_Name (self , node , * args ):
138
- visited .append (['enter' , type (node ).__name__ , getattr (node , 'value' , None )])
143
+ visited .append (
144
+ ['enter' , type (node ).__name__ , getattr (node , 'value' , None )])
139
145
140
146
def enter_SelectionSet (self , node , * args ):
141
- visited .append (['enter' , type (node ).__name__ , getattr (node , 'value' , None )])
147
+ visited .append (
148
+ ['enter' , type (node ).__name__ , getattr (node , 'value' , None )])
142
149
143
150
def leave_SelectionSet (self , node , * args ):
144
- visited .append (['leave' , type (node ).__name__ , getattr (node , 'value' , None )])
151
+ visited .append (
152
+ ['leave' , type (node ).__name__ , getattr (node , 'value' , None )])
145
153
146
154
visit (ast , TestVisitor ())
147
155
@@ -476,3 +484,97 @@ def leave(self, node, key, parent, *args):
476
484
['leave' , 'OperationDefinition' , 4 , None ],
477
485
['leave' , 'Document' , None , None ]
478
486
]
487
+
488
+
489
+ def test_visits_in_pararell_allows_skipping_a_subtree ():
490
+ visited = []
491
+ ast = parse ('{ a, b { x }, c }' )
492
+
493
+ class TestVisitor (Visitor ):
494
+
495
+ def enter (self , node , key , parent , * args ):
496
+ visited .append (
497
+ ['enter' , type (node ).__name__ , getattr (node , 'value' , None )])
498
+ if type (node ).__name__ == 'Field' and node .name .value == 'b' :
499
+ return False
500
+
501
+ def leave (self , node , key , parent , * args ):
502
+ visited .append (
503
+ ['leave' , type (node ).__name__ , getattr (node , 'value' , None )])
504
+
505
+ visit (ast , ParallelVisitor ([TestVisitor ()]))
506
+ assert visited == [
507
+ ['enter' , 'Document' , None ],
508
+ ['enter' , 'OperationDefinition' , None ],
509
+ ['enter' , 'SelectionSet' , None ],
510
+ ['enter' , 'Field' , None ],
511
+ ['enter' , 'Name' , 'a' ],
512
+ ['leave' , 'Name' , 'a' ],
513
+ ['leave' , 'Field' , None ],
514
+ ['enter' , 'Field' , None ],
515
+ ['enter' , 'Field' , None ],
516
+ ['enter' , 'Name' , 'c' ],
517
+ ['leave' , 'Name' , 'c' ],
518
+ ['leave' , 'Field' , None ],
519
+ ['leave' , 'SelectionSet' , None ],
520
+ ['leave' , 'OperationDefinition' , None ],
521
+ ['leave' , 'Document' , None ],
522
+ ]
523
+
524
+
525
+ def test_visits_in_pararell_allows_skipping_different_subtrees ():
526
+ visited = []
527
+ ast = parse ('{ a { x }, b { y} }' )
528
+
529
+ class TestVisitor (Visitor ):
530
+
531
+ def __init__ (self , name ):
532
+ self .name = name
533
+
534
+ def enter (self , node , key , parent , * args ):
535
+ visited .append (["no-{}" .format (self .name ), 'enter' ,
536
+ type (node ).__name__ , getattr (node , 'value' , None )])
537
+ if type (node ).__name__ == 'Field' and node .name .value == self .name :
538
+ return False
539
+
540
+ def leave (self , node , key , parent , * args ):
541
+ visited .append (["no-{}" .format (self .name ), 'leave' ,
542
+ type (node ).__name__ , getattr (node , 'value' , None )])
543
+
544
+ visit (ast , ParallelVisitor ([TestVisitor ('a' ), TestVisitor ('b' )]))
545
+ assert visited == [
546
+ ['no-a' , 'enter' , 'Document' , None ],
547
+ ['no-b' , 'enter' , 'Document' , None ],
548
+ ['no-a' , 'enter' , 'OperationDefinition' , None ],
549
+ ['no-b' , 'enter' , 'OperationDefinition' , None ],
550
+ ['no-a' , 'enter' , 'SelectionSet' , None ],
551
+ ['no-b' , 'enter' , 'SelectionSet' , None ],
552
+ ['no-a' , 'enter' , 'Field' , None ],
553
+ ['no-b' , 'enter' , 'Field' , None ],
554
+ ['no-b' , 'enter' , 'Name' , 'a' ],
555
+ ['no-b' , 'leave' , 'Name' , 'a' ],
556
+ ['no-b' , 'enter' , 'SelectionSet' , None ],
557
+ ['no-b' , 'enter' , 'Field' , None ],
558
+ ['no-b' , 'enter' , 'Name' , 'x' ],
559
+ ['no-b' , 'leave' , 'Name' , 'x' ],
560
+ ['no-b' , 'leave' , 'Field' , None ],
561
+ ['no-b' , 'leave' , 'SelectionSet' , None ],
562
+ ['no-b' , 'leave' , 'Field' , None ],
563
+ ['no-a' , 'enter' , 'Field' , None ],
564
+ ['no-b' , 'enter' , 'Field' , None ],
565
+ ['no-a' , 'enter' , 'Name' , 'b' ],
566
+ ['no-a' , 'leave' , 'Name' , 'b' ],
567
+ ['no-a' , 'enter' , 'SelectionSet' , None ],
568
+ ['no-a' , 'enter' , 'Field' , None ],
569
+ ['no-a' , 'enter' , 'Name' , 'y' ],
570
+ ['no-a' , 'leave' , 'Name' , 'y' ],
571
+ ['no-a' , 'leave' , 'Field' , None ],
572
+ ['no-a' , 'leave' , 'SelectionSet' , None ],
573
+ ['no-a' , 'leave' , 'Field' , None ],
574
+ ['no-a' , 'leave' , 'SelectionSet' , None ],
575
+ ['no-b' , 'leave' , 'SelectionSet' , None ],
576
+ ['no-a' , 'leave' , 'OperationDefinition' , None ],
577
+ ['no-b' , 'leave' , 'OperationDefinition' , None ],
578
+ ['no-a' , 'leave' , 'Document' , None ],
579
+ ['no-b' , 'leave' , 'Document' , None ],
580
+ ]
0 commit comments