示例#1
0
 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."
示例#2
0
 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
示例#3
0
 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'."
示例#4
0
 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
示例#5
0
    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."
示例#6
0
    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."
示例#7
0
    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."
示例#8
0
    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
示例#9
0
    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."
示例#10
0
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)
示例#11
0
    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.'
示例#12
0
 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."
示例#14
0
    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)
示例#15
0
    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)
示例#16
0
    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)
示例#17
0
    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
示例#18
0
    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
示例#19
0
    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"
示例#20
0
    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"
示例#22
0
    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
示例#23
0
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)
示例#24
0
    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"
示例#25
0
    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')