Example #1
0
def test_sync_path_collector(starwars_schema):
    class PathCollector:
        def __init__(self):
            self.log = []  # type: List[str]

        def __call__(self, next_, root, ctx, info, **args):
            self.log.append("> %s" % stringify_path(info.path))
            res = next_(root, ctx, info, **args)
            self.log.append("< %s" % stringify_path(info.path))
            return res

    path_collector = PathCollector()
    graphql_blocking(starwars_schema, HERO_QUERY, middlewares=[path_collector])

    assert [
        "> hero",
        "< hero",
        "> hero.id",
        "< hero.id",
        "> hero.name",
        "< hero.name",
        "> hero.friends",
        "< hero.friends",
        "> hero.friends[0].name",
        "< hero.friends[0].name",
        "> hero.friends[1].name",
        "< hero.friends[1].name",
        "> hero.friends[2].name",
        "< hero.friends[2].name",
    ] == path_collector.log
Example #2
0
def test_executing_interface_default_resolve_type():
    schema = build_schema(
        """
        type Query {
            characters: [Character]
        }

        interface Character {
            name: String!
        }

        type Human implements Character {
            name: String!
            totalCredits: Int
        }

        type Droid implements Character {
            name: String!
            primaryFunction: String
        }
        """
    )

    data, _ = graphql_blocking(
        schema,
        """
        {
            characters {
                name
                ... on Human {
                    totalCredits
                }
                ... on Droid {
                    primaryFunction
                }
            }
        }
        """,
        root={
            "characters": [
                {
                    "name": "Han Solo",
                    "totalCredits": 10,
                    "__typename__": "Human",
                },
                {
                    "name": "R2-D2",
                    "primaryFunction": "Astromech",
                    "__typename__": "Droid",
                },
            ]
        },
    )

    assert data == {
        "characters": [
            {"name": "Han Solo", "totalCredits": 10},
            {"name": "R2-D2", "primaryFunction": "Astromech"},
        ]
    }
Example #3
0
def test_simple_field_modifier():
    class UppercaseDirective(SchemaDirective):
        definition = "upper"

        def on_field(self, field_definition):
            return wrap_resolver(field_definition, lambda x: x.upper())

    assert (graphql_blocking(
        build_schema(
            """
                directive @upper on FIELD_DEFINITION

                type Query {
                    foo: String @upper
                }
                """,
            schema_directives=(UppercaseDirective, ),
        ),
        "{ foo }",
        root={
            "foo": "lowerCase"
        },
    ).response() == {
        "data": {
            "foo": "LOWERCASE"
        }
    })
Example #4
0
def test_middlewares_chain(starwars_schema):

    context = collections.defaultdict(int)  # type: ignore

    def add_to_chain(next_, root, ctx, info, **args):
        ctx[tuple(info.path)] += 1
        return next_(root, ctx, info, **args)

    graphql_blocking(
        starwars_schema,
        "{ hero { id } }",
        context=context,
        middlewares=[add_to_chain, add_to_chain, add_to_chain],
    )

    assert {("hero", ): 3, ("hero", "id"): 3} == context
Example #5
0
def test_field_modifier_using_arguments():
    class PowerDirective(SchemaDirective):
        definition = "power"

        def __init__(self, args):
            self.exponent = args["exponent"]

        def on_field(self, field_definition):
            return wrap_resolver(field_definition, lambda x: x**self.exponent)

    assert (graphql_blocking(
        build_schema(
            """
                directive @power(exponent: Int = 2) on FIELD_DEFINITION

                type Query {
                    foo: Int @power
                    bar: Int @power(exponent: 3)
                }
                """,
            schema_directives=(PowerDirective, ),
        ),
        "{ foo, bar }",
        root={
            "foo": 2,
            "bar": 2
        },
    ).response() == {
        "data": {
            "foo": 4,
            "bar": 8
        }
    })
Example #6
0
def test_accepts_strings():
    schema = build_schema(
        """
        type Query {
            str: String
        }
        """
    )
    data, _ = graphql_blocking(schema, "{ str }", root={"str": 123})
    assert data == {"str": "123"}
Example #7
0
def test_resolver_decorator():
    schema = build_schema(SDL)

    @schema.resolver("Query.foo")
    def _resolve_foo(*_):
        return "foo"

    assert (
        "foo" == graphql_blocking(schema, "{ foo }").response()["data"]["foo"]
    )
Example #8
0
def test_resolver_decorator_multiple_applications():
    schema = build_schema(SDL)

    @schema.resolver("Query.bar")
    @schema.resolver("Query.foo")
    def _resolve_foo(*_):
        return "foo"

    assert {"foo": "foo", "bar": "foo"} == graphql_blocking(
        schema, "{ foo, bar }"
    ).response()["data"]
Example #9
0
def graphql_route():
    data = flask.request.json

    result = graphql_blocking(
        schema,
        data["query"],
        variables=data.get("variables", {}),
        operation_name=data.get("operation_name"),
        context=dict(db=database),
    )

    return flask.jsonify(result.response())
Example #10
0
def test_built_schema_is_executable():
    schema = build_schema(
        parse(
            """
            type Query {
                str: String
            }
            """,
            allow_type_system=True,
        )
    )
    data, _ = graphql_blocking(schema, "{ str }", root={"str": 123})
    assert data == {"str": "123"}
Example #11
0
def test_ApolloTracer_on_validation_error(starwars_schema):
    tracer = ApolloTracer()

    graphql_blocking(
        starwars_schema,
        """
        query NestedQuery {
            hero {
                nameasd  # this is the validation error
                friends {
                    name
                    appearsIn
                    friends {
                    name
                    }
                }
            }
        }
        """,
        instrumentation=tracer,
    )

    assert tracer.name == "tracing"
    assert tracer.payload() == {
        "version": 1,
        "startTime": AnyTimestamp(),
        "endTime": AnyTimestamp(),
        "duration": AnyInt(),
        "execution": None,
        "validation": {
            "duration": AnyInt(),
            "startOffset": AnyInt()
        },
        "parsing": {
            "duration": AnyInt(),
            "startOffset": AnyInt()
        },
    }
Example #12
0
def test_ApolloTracer_on_syntax_error(starwars_schema):
    tracer = ApolloTracer()

    graphql_blocking(
        starwars_schema,
        """
        FOO
        """,
        instrumentation=tracer,
    )

    assert tracer.name == "tracing"
    assert tracer.payload() == {
        "version": 1,
        "startTime": AnyTimestamp(),
        "endTime": AnyTimestamp(),
        "duration": AnyInt(),
        "execution": None,
        "validation": None,
        "parsing": {
            "duration": AnyInt(),
            "startOffset": AnyInt()
        },
    }
def test_arguments_and_input_fields_are_handled_correctly(
    schema: Schema,
) -> None:
    def resolver(_root, _ctx, _info, *, arg_one, arg_two=None):
        if arg_two is None:
            arg_two = {"field_one": 0, "field_two": ""}
        return arg_one + arg_two["field_one"]

    schema.register_resolver("Query", "field_with_arguments", resolver)
    new_schema = transform_schema(schema, CamelCaseSchemaTransform())

    result = graphql_blocking(
        new_schema,
        "{ fieldWithArguments(argOne: 42, argTwo: { fieldOne: 42 }) }",
        root={},
    )

    assert result and result.response()["data"] == {"fieldWithArguments": "84"}
Example #14
0
def test_multiple_directives_applied_in_order():
    class PowerDirective(SchemaDirective):
        definition = "power"

        def __init__(self, args):
            self.exponent = args["exponent"]

        def on_field(self, field_definition):
            return wrap_resolver(field_definition, lambda x: x**self.exponent)

    class PlusOneDirective(SchemaDirective):
        definition = "plus_one"

        def on_field(self, field_definition):
            return wrap_resolver(field_definition, lambda x: x + 1)

    assert (graphql_blocking(
        build_schema(
            """
                directive @power(exponent: Int = 2) on FIELD_DEFINITION
                directive @plus_one on FIELD_DEFINITION

                type Query {
                    foo: Int @power @plus_one
                    bar: Int @plus_one @power
                }
                """,
            schema_directives=(
                PowerDirective,
                PlusOneDirective,
            ),
        ),
        "{ foo, bar }",
        root={
            "foo": 2,
            "bar": 2
        },
    ).response() == {
        "data": {
            "foo": 5,
            "bar": 9
        }
    })
Example #15
0
def test_executing_union_default_resolve_type():
    schema = build_schema(
        """
        type Query {
            fruits: [Fruit]
        }

        union Fruit = Apple | Banana

        type Apple {
            color: String
        }

        type Banana {
            length: Int
        }
        """
    )

    data, _ = graphql_blocking(
        schema,
        """
        {
            fruits {
                ... on Apple {
                    color
                }
                ... on Banana {
                    length
                }
            }
        }
        """,
        root={
            "fruits": [
                {"color": "green", "__typename__": "Apple"},
                {"length": 5, "__typename__": "Banana"},
            ]
        },
    )

    assert data == {"fruits": [{"color": "green"}, {"length": 5}]}
def test_default_resolver_still_works(schema: Schema) -> None:
    new_schema = transform_schema(schema, CamelCaseSchemaTransform())
    result = graphql_blocking(
        new_schema, "{ snakeCaseField }", root={"snake_case_field": 42}
    )
    assert result and result.response()["data"] == {"snakeCaseField": 42}
@schema.resolver("Mutation.increment")
def inc(root, *, amount):
    root["counter"] += amount
    return root["counter"]


@schema.resolver("Mutation.decrement")
def dec(root, *, amount):
    root["counter"] -= amount
    return root["counter"]


# 2. Execute queries against the schema

assert graphql_blocking(schema, "{ counter }", root=ROOT).response() == {
    "data": {"counter": 0}
}

assert graphql_blocking(schema, "{ counte }", root=ROOT).response() == {
    "errors": [
        {
            "message": (
                'Cannot query field "counte" on type "Query". Did you '
                'mean "counter"?'
            ),
            "locations": [{"line": 1, "column": 3}],
        }
    ]
}
Example #18
0
def test_register_resolver():
    schema = build_schema(SDL)
    schema.register_resolver("Query", "foo", lambda *_: "foo")
    assert (
        "foo" == graphql_blocking(schema, "{ foo }").response()["data"]["foo"]
    )
Example #19
0
def test_ApolloTracer(starwars_schema):
    tracer = ApolloTracer()

    graphql_blocking(
        starwars_schema,
        """
        query NestedQuery {
            hero {
                name
                friends {
                    name
                    appearsIn
                    friends {
                    name
                    }
                }
            }
        }
        """,
        instrumentation=tracer,
    )

    assert tracer.name == "tracing"
    assert tracer.payload() == {
        "version": 1,
        "startTime": AnyTimestamp(),
        "endTime": AnyTimestamp(),
        "duration": AnyInt(),
        "execution": {
            "resolvers": Any()
        },
        "validation": {
            "duration": AnyInt(),
            "startOffset": AnyInt()
        },
        "parsing": {
            "duration": AnyInt(),
            "startOffset": AnyInt()
        },
    }

    expected_resolvers = [
        {
            "path": ["hero"],
            "parentType": "Query",
            "fieldName": "hero",
            "returnType": "Character",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "name"],
            "parentType": "Droid",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends"],
            "parentType": "Droid",
            "fieldName": "friends",
            "returnType": "[Character]",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 0, "name"],
            "parentType": "Human",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 0, "appearsIn"],
            "parentType": "Human",
            "fieldName": "appearsIn",
            "returnType": "[Episode]",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 0, "friends"],
            "parentType": "Human",
            "fieldName": "friends",
            "returnType": "[Character]",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 0, "friends", 0, "name"],
            "parentType": "Human",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 0, "friends", 1, "name"],
            "parentType": "Human",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 0, "friends", 2, "name"],
            "parentType": "Droid",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 0, "friends", 3, "name"],
            "parentType": "Droid",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 1, "name"],
            "parentType": "Human",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 1, "appearsIn"],
            "parentType": "Human",
            "fieldName": "appearsIn",
            "returnType": "[Episode]",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 1, "friends"],
            "parentType": "Human",
            "fieldName": "friends",
            "returnType": "[Character]",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 1, "friends", 0, "name"],
            "parentType": "Human",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 1, "friends", 1, "name"],
            "parentType": "Human",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 1, "friends", 2, "name"],
            "parentType": "Droid",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 2, "name"],
            "parentType": "Human",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 2, "appearsIn"],
            "parentType": "Human",
            "fieldName": "appearsIn",
            "returnType": "[Episode]",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 2, "friends"],
            "parentType": "Human",
            "fieldName": "friends",
            "returnType": "[Character]",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 2, "friends", 0, "name"],
            "parentType": "Human",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 2, "friends", 1, "name"],
            "parentType": "Human",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 2, "friends", 2, "name"],
            "parentType": "Droid",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
        {
            "path": ["hero", "friends", 2, "friends", 3, "name"],
            "parentType": "Droid",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": AnyInt(),
            "duration": AnyInt(),
        },
    ]

    # Order is not deterministic.
    for r in expected_resolvers:
        assert r in tracer.payload()["execution"]["resolvers"]
Example #20
0
def test_input_values():
    class LimitedLengthScalarType(ScalarType):
        @classmethod
        def wrap(cls, type_: ScalarType, *args: Any, **kwargs: Any) -> Any:
            if isinstance(type_, (NonNullType, ListType)):
                return type(type_)(cls.wrap(type_.type, *args, **kwargs))
            return cls(type_, *args, **kwargs)

        def __init__(self, type, min, max):
            assert isinstance(type, ScalarType)
            self.type = type
            self.min = min
            self.max = max if max is not None else float("inf")
            assert self.min >= 0
            assert self.max >= 0
            self.name = "LimitedLenth%s_%s_%s" % (type.name, self.min,
                                                  self.max)

        def serialize(self, value):
            return self.type.serialize(value)

        def parse(self, value):
            parsed = self.type.parse(value)
            if not isinstance(parsed, str):
                raise ScalarParsingError("Not a string")
            if not (self.min <= len(parsed) <= self.max):
                raise ScalarParsingError(
                    "%s length must be between %s and %s but was %s" %
                    (self.name, self.min, self.max, len(parsed)))
            return parsed

    class LimitedLengthDirective(SchemaDirective):
        definition = "len"

        def __init__(self, args):
            self.min = args["min"]
            self.max = args.get("max")

        def on_argument(self, arg):
            arg.type = LimitedLengthScalarType.wrap(arg.type, self.min,
                                                    self.max)
            return arg

        def on_input_field(self, input_field):
            input_field.type = LimitedLengthScalarType.wrap(
                input_field.type, self.min, self.max)
            return input_field

    schema = build_schema(
        """
        directive @len(min: Int = 0, max: Int)
            on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION

        type Query {
            foo (
                bar: BarInput
                foo: String @len(max: 4)
            ): String
        }

        input BarInput {
            baz: String @len(min: 3)
        }
        """,
        schema_directives=(LimitedLengthDirective, ),
    )

    assert schema.to_string() == dedent("""
        directive @len(min: Int = 0, max: Int) \
on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION

        input BarInput {
            baz: LimitedLenthString_3_inf
        }

        type Query {
            foo(bar: BarInput, foo: LimitedLenthString_0_4): String
        }
        """)

    class Root:
        def __init__(self, resolver):
            self.resolver = resolver

        def foo(self, ctx, info, **args):
            return self.resolver(ctx, info, **args)

    assert graphql_blocking(
        schema,
        '{ foo (foo: "abcdef") }',
        root=Root(lambda *_, **args: args["foo"]),
    ).response() == {
        "errors": [{
            "locations": [{
                "column": 13,
                "line": 1
            }],
            "message": ("Expected type LimitedLenthString_0_4, found "
                        '"abcdef" (LimitedLenthString_0_4 length must be '
                        "between 0 and 4 but was 6)"),
        }]
    }

    assert graphql_blocking(
        schema,
        '{ foo (foo: "abcd") }',
        root=Root(lambda *_, **args: args["foo"]),
    ).response() == {
        "data": {
            "foo": "abcd"
        }
    }

    assert graphql_blocking(
        schema,
        '{ foo (bar: {baz: "abcd"}) }',
        root=Root(lambda *_, **args: args["bar"]["baz"]),
    ).response() == {
        "data": {
            "foo": "abcd"
        }
    }

    assert graphql_blocking(
        schema,
        '{ foo (bar: {baz: "a"}) }',
        root=Root(lambda *_, **args: args["bar"]["baz"]),
    ).response() == {
        "errors": [{
            "locations": [{
                "column": 19,
                "line": 1
            }],
            "message": ('Expected type LimitedLenthString_3_inf, found "a" '
                        "(LimitedLenthString_3_inf length must be between 3 "
                        "and inf but was 1)"),
        }]
    }
def test_custom_resolver_still_works(schema: Schema) -> None:
    schema.register_resolver("Query", "snake_case_field", lambda *_: 42)
    new_schema = transform_schema(schema, CamelCaseSchemaTransform())
    result = graphql_blocking(new_schema, "{ snakeCaseField }", root={})
    assert result and result.response()["data"] == {"snakeCaseField": 42}
Example #22
0
def test_object_modifier_and_field_modifier():
    class UppercaseDirective(SchemaDirective):
        definition = "upper"

        def on_field(self, field_definition):
            return wrap_resolver(field_definition, lambda x: x.upper())

    class UniqueIDDirective(SchemaDirective):
        definition = "uid"

        def __init__(self, args):
            self.name = args["name"]
            self.source = args["source"]
            assert len(self.source)

        def resolve(self, root, *_, **args):
            m = hashlib.sha256()
            for fieldname in self.source:
                m.update(str(root.get(fieldname, "")).encode("utf8"))
            return m.hexdigest()

        def on_object(self, object_definition):
            assert self.name not in object_definition.field_map
            assert all(s in object_definition.field_map for s in self.source)
            return ObjectType(
                name=object_definition.name,
                description=object_definition.description,
                fields=([Field(self.name, String, resolver=self.resolve)] +
                        object_definition.fields),
                interfaces=object_definition.interfaces,
                nodes=object_definition.nodes,
            )

    schema = build_schema(
        """
        directive @uid (name: String! = "uid", source: [String]!) on OBJECT
        directive @upper on FIELD_DEFINITION

        type Query {
            foo: Foo
        }

        type Foo @uid (source: ["id", "name"]) {
            id: Int
            name: String @upper
        }
        """,
        schema_directives=(UppercaseDirective, UniqueIDDirective),
    )

    assert schema.to_string() == dedent("""
        directive @uid(name: String! = "uid", source: [String]!) on OBJECT

        directive @upper on FIELD_DEFINITION

        type Foo {
            uid: String
            id: Int
            name: String
        }

        type Query {
            foo: Foo
        }
        """)

    assert graphql_blocking(
        schema,
        "{ foo { uid, name, id } }",
        root={
            "foo": {
                "name": "some lower case name",
                "id": 42
            }
        },
    ).response() == {
        "data": {
            "foo": {
                "uid": ("6dc146d52a9962cfb9b29c2414f68cc628e2a0dcce"
                        "7832760ddf39a441726173"),
                "name":
                "SOME LOWER CASE NAME",
                "id":
                42,
            }
        }
    }
Example #23
0
# -*- coding: utf-8 -*-
from py_gql import build_schema, graphql_blocking


schema = build_schema(
    """
    type Query {
        hello(value: String = "world"): String!
    }
    """
)


@schema.resolver("Query.hello")
def resolve_hello(*_, value):
    return "Hello {}!".format(value)


result = graphql_blocking(schema, '{ hello(value: "World") }')
assert result.response() == {"data": {"hello": "Hello World!"}}