def supports_traversal_of_selection_sets(): visited = [] human_type = test_schema.get_type("Human") assert human_type is not None type_info = TypeInfo(test_schema, None, human_type) ast = parse("{ name, pets { name } }") operation_node = ast.definitions[0] assert isinstance(operation_node, OperationDefinitionNode) class TestVisitor(Visitor): @staticmethod def enter(node: Node, *_args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() visited.append( ( "enter", node.kind, node.value if isinstance(node, NameNode) else None, str(parent_type), str(type_), ) ) @staticmethod def leave(node: Node, *_args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() visited.append( ( "leave", node.kind, node.value if isinstance(node, NameNode) else None, str(parent_type), str(type_), ) ) visit(operation_node.selection_set, TypeInfoVisitor(type_info, TestVisitor())) assert visited == [ ("enter", "selection_set", None, "Human", "Human"), ("enter", "field", None, "Human", "String"), ("enter", "name", "name", "Human", "String"), ("leave", "name", "name", "Human", "String"), ("leave", "field", None, "Human", "String"), ("enter", "field", None, "Human", "[Pet]"), ("enter", "name", "pets", "Human", "[Pet]"), ("leave", "name", "pets", "Human", "[Pet]"), ("enter", "selection_set", None, "Pet", "[Pet]"), ("enter", "field", None, "Pet", "String"), ("enter", "name", "name", "Pet", "String"), ("leave", "name", "name", "Pet", "String"), ("leave", "field", None, "Pet", "String"), ("leave", "selection_set", None, "Pet", "[Pet]"), ("leave", "field", None, "Human", "[Pet]"), ("leave", "selection_set", None, "Human", "Human"), ]
def supports_traversal_of_input_values(): visited = [] schema = build_schema(""" input ComplexInput { stringListField: [String] } """) complex_input_type = schema.get_type("ComplexInput") assert complex_input_type is not None type_info = TypeInfo(schema, complex_input_type) ast = parse_value('{ stringListField: ["foo"] }') class TestVisitor(Visitor): @staticmethod def enter(node: Node, *_args): type_ = type_info.get_input_type() visited.append(( "enter", node.kind, node.value if isinstance(node, NameNode) else None, str(type_), )) @staticmethod def leave(node: Node, *_args): type_ = type_info.get_input_type() visited.append(( "leave", node.kind, node.value if isinstance(node, NameNode) else None, str(type_), )) visit(ast, TypeInfoVisitor(type_info, TestVisitor())) assert visited == [ ("enter", "object_value", None, "ComplexInput"), ("enter", "object_field", None, "[String]"), ("enter", "name", "stringListField", "[String]"), ("leave", "name", "stringListField", "[String]"), ("enter", "list_value", None, "String"), ("enter", "string_value", None, "String"), ("leave", "string_value", None, "String"), ("leave", "list_value", None, "String"), ("leave", "object_field", None, "[String]"), ("leave", "object_value", None, "ComplexInput"), ]
def supports_traversal_of_input_values(): visited = [] complex_input_type = test_schema.get_type("ComplexInput") assert complex_input_type is not None type_info = TypeInfo(test_schema, None, complex_input_type) ast = parse_value('{ stringListField: ["foo"] }') # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): def enter(self, node: Node, *_args): type_ = type_info.get_input_type() visited.append(( "enter", node.kind, node.value if isinstance(node, NameNode) else None, str(type_), )) def leave(self, node: Node, *_args): type_ = type_info.get_input_type() visited.append(( "leave", node.kind, node.value if isinstance(node, NameNode) else None, str(type_), )) visit(ast, TypeInfoVisitor(type_info, TestVisitor())) assert visited == [ ("enter", "object_value", None, "ComplexInput"), ("enter", "object_field", None, "[String]"), ("enter", "name", "stringListField", "[String]"), ("leave", "name", "stringListField", "[String]"), ("enter", "list_value", None, "String"), ("enter", "string_value", None, "String"), ("leave", "string_value", None, "String"), ("leave", "list_value", None, "String"), ("leave", "object_field", None, "[String]"), ("leave", "object_value", None, "ComplexInput"), ]
def visit_document(document_ast: DocumentNode, schema): if not document_ast or not isinstance(document_ast, DocumentNode): raise TypeError("You must provide a document node.") # If the schema used for validation is invalid, throw an error. type_info = TypeInfo(schema) context = ValidationContext(schema, document_ast, type_info) # This uses a specialized visitor which runs multiple visitors in parallel, # while maintaining the visitor skip and break API. # Visit the whole document with each instance of all provided rules. # A single document can have multiple Fragments, and we assume a single Query all_types = set() for def_ast in document_ast.definitions: visitor = AllTypesVisitor(context) visit(def_ast, TypeInfoVisitor(type_info, visitor)) all_types.update(visitor.types) return all_types
def provide_exact_same_arguments_to_wrapped_visitor(): ast = parse("{ human(id: 4) { name, pets { ... { name } }, unknown } }") class TestVisitor(Visitor): def __init__(self): self.args = [] def enter(self, *args): self.args.append(("enter", *args)) def leave(self, *args): self.args.append(("leave", *args)) test_visitor = TestVisitor() visit(ast, test_visitor) type_info = TypeInfo(test_schema) wrapped_visitor = TestVisitor() visit(ast, TypeInfoVisitor(type_info, wrapped_visitor)) assert test_visitor.args == wrapped_visitor.args
def supports_different_operation_types(): schema = build_schema( """ schema { query: QueryRoot mutation: MutationRoot subscription: SubscriptionRoot } type QueryRoot { foo: String } type MutationRoot { bar: String } type SubscriptionRoot { baz: String } """ ) ast = parse( """ query { foo } mutation { bar } subscription { baz } """ ) class TestVisitor(Visitor): def __init__(self): self.root_types = {} def enter_operation_definition(self, node: OperationDefinitionNode, *_args): self.root_types[node.operation.value] = str(type_info.get_type()) type_info = TypeInfo(schema) test_visitor = TestVisitor() assert visit(ast, TypeInfoVisitor(type_info, test_visitor)) assert test_visitor.root_types == { "query": "QueryRoot", "mutation": "MutationRoot", "subscription": "SubscriptionRoot", }
def maintains_type_info_during_edit(): visited = [] type_info = TypeInfo(test_schema) ast = parse("{ human(id: 4) { name, pets }, alien }") class TestVisitor(Visitor): @staticmethod def enter(*args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] visited.append( ( "enter", node.kind, node.value if node.kind == "name" else None, str(parent_type) if parent_type else None, str(type_) if type_ else None, str(input_type) if input_type else None, ) ) # Make a query valid by adding missing selection sets. if ( node.kind == "field" and not node.selection_set and is_composite_type(get_named_type(type_)) ): return FieldNode( alias=node.alias, name=node.name, arguments=node.arguments, directives=node.directives, selection_set=SelectionSetNode( selections=[FieldNode(name=NameNode(value="__typename"))] ), ) @staticmethod def leave(*args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] visited.append( ( "leave", node.kind, node.value if node.kind == "name" else None, str(parent_type) if parent_type else None, str(type_) if type_ else None, str(input_type) if input_type else None, ) ) edited_ast = visit(ast, TypeInfoVisitor(type_info, TestVisitor())) assert ast == parse("{ human(id: 4) { name, pets }, alien }") assert print_ast(edited_ast) == print_ast( parse( "{ human(id: 4) { name, pets { __typename } }," " alien { __typename } }" ) ) assert visited == [ ("enter", "document", None, None, None, None), ("enter", "operation_definition", None, None, "QueryRoot", None), ("enter", "selection_set", None, "QueryRoot", "QueryRoot", None), ("enter", "field", None, "QueryRoot", "Human", None), ("enter", "name", "human", "QueryRoot", "Human", None), ("leave", "name", "human", "QueryRoot", "Human", None), ("enter", "argument", None, "QueryRoot", "Human", "ID"), ("enter", "name", "id", "QueryRoot", "Human", "ID"), ("leave", "name", "id", "QueryRoot", "Human", "ID"), ("enter", "int_value", None, "QueryRoot", "Human", "ID"), ("leave", "int_value", None, "QueryRoot", "Human", "ID"), ("leave", "argument", None, "QueryRoot", "Human", "ID"), ("enter", "selection_set", None, "Human", "Human", None), ("enter", "field", None, "Human", "String", None), ("enter", "name", "name", "Human", "String", None), ("leave", "name", "name", "Human", "String", None), ("leave", "field", None, "Human", "String", None), ("enter", "field", None, "Human", "[Pet]", None), ("enter", "name", "pets", "Human", "[Pet]", None), ("leave", "name", "pets", "Human", "[Pet]", None), ("enter", "selection_set", None, "Pet", "[Pet]", None), ("enter", "field", None, "Pet", "String!", None), ("enter", "name", "__typename", "Pet", "String!", None), ("leave", "name", "__typename", "Pet", "String!", None), ("leave", "field", None, "Pet", "String!", None), ("leave", "selection_set", None, "Pet", "[Pet]", None), ("leave", "field", None, "Human", "[Pet]", None), ("leave", "selection_set", None, "Human", "Human", None), ("leave", "field", None, "QueryRoot", "Human", None), ("enter", "field", None, "QueryRoot", "Alien", None), ("enter", "name", "alien", "QueryRoot", "Alien", None), ("leave", "name", "alien", "QueryRoot", "Alien", None), ("enter", "selection_set", None, "Alien", "Alien", None), ("enter", "field", None, "Alien", "String!", None), ("enter", "name", "__typename", "Alien", "String!", None), ("leave", "name", "__typename", "Alien", "String!", None), ("leave", "field", None, "Alien", "String!", None), ("leave", "selection_set", None, "Alien", "Alien", None), ("leave", "field", None, "QueryRoot", "Alien", None), ("leave", "selection_set", None, "QueryRoot", "QueryRoot", None), ("leave", "operation_definition", None, None, "QueryRoot", None), ("leave", "document", None, None, None, None), ]
def maintains_type_info_during_visit(): visited = [] type_info = TypeInfo(test_schema) ast = parse("{ human(id: 4) { name, pets { ... { name } }, unknown } }") class TestVisitor(Visitor): @staticmethod def enter(*args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] visited.append( ( "enter", node.kind, node.value if node.kind == "name" else None, str(parent_type) if parent_type else None, str(type_) if type_ else None, str(input_type) if input_type else None, ) ) @staticmethod def leave(*args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] visited.append( ( "leave", node.kind, node.value if node.kind == "name" else None, str(parent_type) if parent_type else None, str(type_) if type_ else None, str(input_type) if input_type else None, ) ) visit(ast, TypeInfoVisitor(type_info, TestVisitor())) assert visited == [ ("enter", "document", None, None, None, None), ("enter", "operation_definition", None, None, "QueryRoot", None), ("enter", "selection_set", None, "QueryRoot", "QueryRoot", None), ("enter", "field", None, "QueryRoot", "Human", None), ("enter", "name", "human", "QueryRoot", "Human", None), ("leave", "name", "human", "QueryRoot", "Human", None), ("enter", "argument", None, "QueryRoot", "Human", "ID"), ("enter", "name", "id", "QueryRoot", "Human", "ID"), ("leave", "name", "id", "QueryRoot", "Human", "ID"), ("enter", "int_value", None, "QueryRoot", "Human", "ID"), ("leave", "int_value", None, "QueryRoot", "Human", "ID"), ("leave", "argument", None, "QueryRoot", "Human", "ID"), ("enter", "selection_set", None, "Human", "Human", None), ("enter", "field", None, "Human", "String", None), ("enter", "name", "name", "Human", "String", None), ("leave", "name", "name", "Human", "String", None), ("leave", "field", None, "Human", "String", None), ("enter", "field", None, "Human", "[Pet]", None), ("enter", "name", "pets", "Human", "[Pet]", None), ("leave", "name", "pets", "Human", "[Pet]", None), ("enter", "selection_set", None, "Pet", "[Pet]", None), ("enter", "inline_fragment", None, "Pet", "Pet", None), ("enter", "selection_set", None, "Pet", "Pet", None), ("enter", "field", None, "Pet", "String", None), ("enter", "name", "name", "Pet", "String", None), ("leave", "name", "name", "Pet", "String", None), ("leave", "field", None, "Pet", "String", None), ("leave", "selection_set", None, "Pet", "Pet", None), ("leave", "inline_fragment", None, "Pet", "Pet", None), ("leave", "selection_set", None, "Pet", "[Pet]", None), ("leave", "field", None, "Human", "[Pet]", None), ("enter", "field", None, "Human", None, None), ("enter", "name", "unknown", "Human", None, None), ("leave", "name", "unknown", "Human", None, None), ("leave", "field", None, "Human", None, None), ("leave", "selection_set", None, "Human", "Human", None), ("leave", "field", None, "QueryRoot", "Human", None), ("leave", "selection_set", None, "QueryRoot", "QueryRoot", None), ("leave", "operation_definition", None, None, "QueryRoot", None), ("leave", "document", None, None, None, None), ]
def test_visit_all_ast_nodes_in_parallel(benchmark, big_schema_sdl): # noqa: F811 document_ast = parse(big_schema_sdl) visitor = DummyVisitor() parallel_visitor = ParallelVisitor([visitor] * 50) benchmark(lambda: visit(document_ast, parallel_visitor))
def test_visit_all_ast_nodes(benchmark, big_schema_sdl): # noqa: F811 document_ast = parse(big_schema_sdl) visitor = DummyVisitor() benchmark(lambda: visit(document_ast, visitor))