11from graphql .core .language .ast import Field , Name , SelectionSet
22from 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
44
55from .fixtures import KITCHEN_SINK
66
@@ -50,7 +50,8 @@ def enter(self, node, *args):
5050 selections = []
5151 if selection_set :
5252 selections = selection_set .selections
53- new_selection_set = SelectionSet (selections = [added_field ] + selections )
53+ new_selection_set = SelectionSet (
54+ selections = [added_field ] + selections )
5455 return Field (name = None , selection_set = new_selection_set )
5556 if node is added_field :
5657 self .did_visit_added_field = True
@@ -67,12 +68,14 @@ def test_allows_skipping_a_subtree():
6768 class TestVisitor (Visitor ):
6869
6970 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 )])
7173 if isinstance (node , Field ) and node .name .value == 'b' :
7274 return False
7375
7476 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 )])
7679
7780 visit (ast , TestVisitor ())
7881
@@ -102,12 +105,14 @@ def test_allows_early_exit_while_visiting():
102105 class TestVisitor (Visitor ):
103106
104107 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 )])
106110 if isinstance (node , Name ) and node .value == 'x' :
107111 return BREAK
108112
109113 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 )])
111116
112117 visit (ast , TestVisitor ())
113118
@@ -135,13 +140,16 @@ def test_allows_a_named_functions_visitor_api():
135140 class TestVisitor (Visitor ):
136141
137142 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 )])
139145
140146 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 )])
142149
143150 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 )])
145153
146154 visit (ast , TestVisitor ())
147155
@@ -476,3 +484,97 @@ def leave(self, node, key, parent, *args):
476484 ['leave' , 'OperationDefinition' , 4 , None ],
477485 ['leave' , 'Document' , None , None ]
478486 ]
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