def rejects_invalid_ast(): with raises(TypeError) as exc_info: build_ast_schema(None) # type: ignore assert str(exc_info.value) == "Must provide valid Document AST." with raises(TypeError) as exc_info: build_ast_schema({}) # type: ignore assert str(exc_info.value) == "Must provide valid Document AST."
def unknown_type_in_union_list(): body = dedent(""" union TestUnion = Bar type Query { testUnion: TestUnion } """) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) assert "Type 'Bar' not found in document." in msg
def rejects_invalid_sdl(): doc = parse(""" type Query { foo: String @unknown } """) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) assert msg == "Unknown directive 'unknown'."
def unknown_type_in_interface_list(): body = dedent(""" type Query implements Bar { field: String } """) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) assert "Type 'Bar' not found in document." in msg
def does_not_consider_fragment_names(): body = dedent(""" schema { query: Foo } fragment Foo on Type { field } """) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) assert msg == "Specified query type 'Foo' not found in document."
def unknown_query_type(): body = dedent(""" schema { query: Wat } type Hello { str: String } """) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) assert msg == "Specified query type 'Wat' not found in document."
def does_not_consider_operation_names(): body = dedent(""" schema { query: Foo } type Hello { str: String } """) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) assert msg == "Specified query type 'Foo' not found in document."
def unknown_type_referenced(): body = dedent(""" schema { query: Hello } type Hello { bar: Bar } """) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) assert "Type 'Bar' not found in document." in msg
def forbids_duplicate_type_definitions(): body = dedent(""" schema { query: Repeated } type Repeated { id: Int } type Repeated { id: String } """) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) assert msg == "Type 'Repeated' was defined more than once."
def cycle_sdl(sdl: str) -> str: """Full cycle test. This function does a full cycle of going from a string with the contents of the SDL, parsed in a schema AST, materializing that schema AST into an in-memory GraphQLSchema, and then finally printing that GraphQL into the SDÖ. """ ast = parse(sdl) schema = build_ast_schema(ast) return print_schema(schema)
def allows_only_a_single_subscription_type(): body = dedent(""" schema { query: Hello subscription: Hello subscription: Yellow } type Hello { bar: String } type Yellow { isColor: Boolean } """) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) assert msg == 'Must provide only one subscription type in schema.'
def maintains_skip_and_include_directives(): body = dedent(""" type Query { str: String } """) schema = build_ast_schema(parse(body)) assert len(schema.directives) == 3 assert schema.get_directive('skip') is GraphQLSkipDirective assert schema.get_directive('include') is GraphQLIncludeDirective assert schema.get_directive('deprecated') is GraphQLDeprecatedDirective
def unknown_subscription_type(): body = dedent(""" schema { query: Hello mutation: Wat subscription: Awesome } type Hello { str: String } type Wat { str: String } """) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) assert msg == "Specified subscription type 'Awesome' not found in document."
def can_use_built_schema_for_limited_execution(): schema = build_ast_schema( parse(""" type Query { str: String } """)) data = namedtuple('Data', 'str')(123) result = graphql_sync(schema, '{ str }', data) assert result == ({'str': '123'}, None)
def can_use_built_schema_for_limited_execution(): schema = build_ast_schema( parse(""" type Query { str: String } """)) data = namedtuple("Data", "str")(123) result = graphql_sync(schema, "{ str }", data) assert result == ({"str": "123"}, None)
def can_use_built_schema_for_limited_execution(): schema = build_ast_schema( parse(""" type Query { str: String } """)) root_value = namedtuple("Data", "str")(123) # type: ignore result = graphql_sync(schema=schema, source="{ str }", root_value=root_value) assert result == ({"str": "123"}, None)
def overriding_skip_directive_excludes_built_in_one(): body = dedent(""" directive @skip on FIELD type Query { str: String } """) schema = build_ast_schema(parse(body)) assert len(schema.directives) == 3 assert schema.get_directive('skip') is not GraphQLSkipDirective assert schema.get_directive('skip') is not None assert schema.get_directive('include') is GraphQLIncludeDirective assert schema.get_directive('deprecated') is GraphQLDeprecatedDirective
def adding_directives_maintains_skip_and_include_directives(): body = dedent(""" directive @foo(arg: Int) on FIELD type Query { str: String } """) schema = build_ast_schema(parse(body)) assert len(schema.directives) == 4 assert schema.get_directive('skip') is GraphQLSkipDirective assert schema.get_directive('include') is GraphQLIncludeDirective assert schema.get_directive('deprecated') is GraphQLDeprecatedDirective assert schema.get_directive('foo') is not None
def supports_deprecated_directive(): body = dedent( """ enum MyEnum { VALUE OLD_VALUE @deprecated OTHER_VALUE @deprecated(reason: "Terrible reasons") } type Query { field1: String @deprecated field2: Int @deprecated(reason: "Because I said so") enum: MyEnum } """ ) output = cycle_output(body) assert output == body ast = parse(body) schema = build_ast_schema(ast) my_enum = schema.get_type("MyEnum") my_enum = cast(GraphQLEnumType, my_enum) value = my_enum.values["VALUE"] assert value.is_deprecated is False old_value = my_enum.values["OLD_VALUE"] assert old_value.is_deprecated is True assert old_value.deprecation_reason == "No longer supported" other_value = my_enum.values["OTHER_VALUE"] assert other_value.is_deprecated is True assert other_value.deprecation_reason == "Terrible reasons" root_fields = schema.get_type("Query").fields field1 = root_fields["field1"] assert field1.is_deprecated is True assert field1.deprecation_reason == "No longer supported" field2 = root_fields["field2"] assert field2.is_deprecated is True assert field2.deprecation_reason == "Because I said so"
def overriding_directives_excludes_specified(): body = dedent(""" directive @skip on FIELD directive @include on FIELD directive @deprecated on FIELD_DEFINITION type Query { str: String } """) schema = build_ast_schema(parse(body)) assert len(schema.directives) == 3 get_directive = schema.get_directive assert get_directive('skip') is not GraphQLSkipDirective assert get_directive('skip') is not None assert get_directive('include') is not GraphQLIncludeDirective assert get_directive('include') is not None assert get_directive('deprecated') is not GraphQLDeprecatedDirective assert get_directive('deprecated') is not None
def correctly_assign_ast_nodes(): schema_ast = parse( dedent(""" schema { query: Query } type Query { testField(testArg: TestInput): TestUnion } input TestInput { testInputField: TestEnum } enum TestEnum { TEST_VALUE } union TestUnion = TestType interface TestInterface { interfaceField: String } type TestType implements TestInterface { interfaceField: String } scalar TestScalar directive @test(arg: TestScalar) on FIELD """)) schema = build_ast_schema(schema_ast) query = schema.get_type("Query") query = cast(GraphQLObjectType, query) test_input = schema.get_type("TestInput") test_input = cast(GraphQLInputObjectType, test_input) test_enum = schema.get_type("TestEnum") test_enum = cast(GraphQLEnumType, test_enum) test_union = schema.get_type("TestUnion") test_interface = schema.get_type("TestInterface") test_interface = cast(GraphQLInterfaceType, test_interface) test_type = schema.get_type("TestType") test_scalar = schema.get_type("TestScalar") test_directive = schema.get_directive("test") restored_schema_ast = DocumentNode(definitions=[ schema.ast_node, query.ast_node, test_input.ast_node, test_enum.ast_node, test_union.ast_node, test_interface.ast_node, test_type.ast_node, test_scalar.ast_node, test_directive.ast_node, ]) assert print_ast(restored_schema_ast) == print_ast(schema_ast) test_field = query.fields["testField"] assert print_ast(test_field.ast_node) == ( "testField(testArg: TestInput): TestUnion") assert print_ast( test_field.args["testArg"].ast_node) == "testArg: TestInput" assert print_ast(test_input.fields["testInputField"].ast_node) == ( "testInputField: TestEnum") assert print_ast( test_enum.values["TEST_VALUE"].ast_node) == "TEST_VALUE" assert print_ast(test_interface.fields["interfaceField"].ast_node) == ( "interfaceField: String") assert print_ast( test_directive.args["arg"].ast_node) == "arg: TestScalar"
def match_order_of_default_types_and_directives(): schema = GraphQLSchema() sdl_schema = build_ast_schema(DocumentNode(definitions=[])) assert sdl_schema.directives == schema.directives assert sdl_schema.type_map == schema.type_map
def get_schema_with_macros(macro_registry): """Get a new GraphQLSchema with fields where macro edges can be used. Preconditions: 1. No macro in the registry has the same name as a field on the vertex where it applies. 2. Members of a union type do not have outgoing macros with the same name. An easy way to satisfy the preconditions is to create the macro_registry using create_macro_registry, and only update it with register_macro_edge, which does all the necessary validation. Postconditions: 1. Every GraphQLQuery that uses macros from this registry appropriately should successfully type-check against the schema generated from this function. 2. A GraphQLQuery that uses macros not present in the registry, or uses valid macros but on types they are not defined at should fail schema validation with the schema generated from this function. 3. This function is total -- A valid macro registry should not fail to create a GraphQL schema with macros. Args: macro_registry: MacroRegistry object containing a schema and macro descriptors we want to add to the schema. Returns: GraphQLSchema with additional fields where macro edges can be used. """ # The easiest way to manipulate the schema is through its AST. The easiest # way to get an AST is to print it and parse it. schema_ast = parse(print_schema(macro_registry.schema_without_macros)) fields_by_definition_name = {} for definition in schema_ast.definitions: if isinstance(definition, (ObjectTypeDefinitionNode, InterfaceTypeDefinitionNode)): # Cast to list (from FrozenList) to allow for updates. fields_by_definition_name[definition.name.value] = list(definition.fields) for class_name, macros_for_class in six.iteritems(macro_registry.macro_edges_at_class): for macro_edge_name, macro_edge_descriptor in six.iteritems(macros_for_class): list_type_at_target = ListTypeNode( type=NamedTypeNode(name=NameNode(value=macro_edge_descriptor.target_class_name)) ) arguments = [] directives = [DirectiveNode(name=NameNode(value=MacroEdgeDirective.name))] fields_by_definition_name[class_name].append( FieldDefinitionNode( name=NameNode(value=macro_edge_name), arguments=arguments, type=list_type_at_target, directives=directives, ) ) new_definitions = [] for definition in schema_ast.definitions: # Create new (Object)/(Interface)TypeDefinitionNode based on the updated fields. if isinstance(definition, ObjectTypeDefinitionNode): new_definitions.append( ObjectTypeDefinitionNode( interfaces=definition.interfaces, description=definition.description, name=definition.name, directives=definition.directives, loc=definition.loc, fields=FrozenList(fields_by_definition_name[definition.name.value]), ) ) elif isinstance(definition, InterfaceTypeDefinitionNode): new_definitions.append( InterfaceTypeDefinitionNode( description=definition.description, name=definition.name, directives=definition.directives, loc=definition.loc, fields=FrozenList(fields_by_definition_name[definition.name.value]), ) ) else: new_definitions.append(definition) new_schema_ast = DocumentNode(definitions=new_definitions) return build_ast_schema(new_schema_ast)
def correctly_assign_ast_nodes(): sdl = dedent( """ schema { query: Query } type Query { testField(testArg: TestInput): TestUnion } input TestInput { testInputField: TestEnum } enum TestEnum { TEST_VALUE } union TestUnion = TestType interface TestInterface { interfaceField: String } type TestType implements TestInterface { interfaceField: String } scalar TestScalar directive @test(arg: TestScalar) on FIELD """ ) ast = parse(sdl, no_location=True) schema = build_ast_schema(ast) query = assert_object_type(schema.get_type("Query")) test_input = assert_input_object_type(schema.get_type("TestInput")) test_enum = assert_enum_type(schema.get_type("TestEnum")) test_union = assert_union_type(schema.get_type("TestUnion")) test_interface = assert_interface_type(schema.get_type("TestInterface")) test_type = assert_object_type(schema.get_type("TestType")) test_scalar = assert_scalar_type(schema.get_type("TestScalar")) test_directive = assert_directive(schema.get_directive("test")) restored_schema_ast = DocumentNode( definitions=[ schema.ast_node, query.ast_node, test_input.ast_node, test_enum.ast_node, test_union.ast_node, test_interface.ast_node, test_type.ast_node, test_scalar.ast_node, test_directive.ast_node, ], loc=None, ) assert restored_schema_ast == ast test_field = query.fields["testField"] assert print_node(test_field.ast_node) == ( "testField(testArg: TestInput): TestUnion" ) assert print_node(test_field.args["testArg"].ast_node) == "testArg: TestInput" assert print_node(test_input.fields["testInputField"].ast_node) == ( "testInputField: TestEnum" ) test_enum_value = test_enum.values["TEST_VALUE"] assert test_enum_value assert print_node(test_enum_value.ast_node) == "TEST_VALUE" assert print_node(test_interface.fields["interfaceField"].ast_node) == ( "interfaceField: String" ) assert print_ast(test_directive.args["arg"].ast_node) == "arg: TestScalar"
def correctly_assign_ast_nodes(): schema_ast = parse( dedent(""" schema { query: Query } type Query { testField(testArg: TestInput): TestUnion } input TestInput { testInputField: TestEnum } enum TestEnum { TEST_VALUE } union TestUnion = TestType interface TestInterface { interfaceField: String } type TestType implements TestInterface { interfaceField: String } scalar TestScalar directive @test(arg: TestScalar) on FIELD """)) schema = build_ast_schema(schema_ast) query = schema.get_type('Query') query = cast(GraphQLObjectType, query) test_input = schema.get_type('TestInput') test_input = cast(GraphQLInputObjectType, test_input) test_enum = schema.get_type('TestEnum') test_enum = cast(GraphQLEnumType, test_enum) test_union = schema.get_type('TestUnion') test_interface = schema.get_type('TestInterface') test_interface = cast(GraphQLInterfaceType, test_interface) test_type = schema.get_type('TestType') test_scalar = schema.get_type('TestScalar') test_directive = schema.get_directive('test') restored_schema_ast = DocumentNode(definitions=[ schema.ast_node, query.ast_node, test_input.ast_node, test_enum.ast_node, test_union.ast_node, test_interface.ast_node, test_type.ast_node, test_scalar.ast_node, test_directive.ast_node ]) assert print_ast(restored_schema_ast) == print_ast(schema_ast) test_field = query.fields['testField'] assert print_ast(test_field.ast_node) == ( 'testField(testArg: TestInput): TestUnion') assert print_ast( test_field.args['testArg'].ast_node) == ('testArg: TestInput') assert print_ast(test_input.fields['testInputField'].ast_node) == ( 'testInputField: TestEnum') assert print_ast( test_enum.values['TEST_VALUE'].ast_node) == ('TEST_VALUE') assert print_ast(test_interface.fields['interfaceField'].ast_node) == ( 'interfaceField: String') assert print_ast( test_directive.args['arg'].ast_node) == ('arg: TestScalar')