def test_nested_objects():

    Baz = Object("Baz")

    @Baz.field("val")
    def resolve_baz_val(root, info) -> str:
        return "BAZ-VALUE!"

    Bar = Object("Bar", {"baz": Baz})

    @Bar.field("baz")
    def resolve_bar_baz(root, info) -> Baz:
        return Baz()

    Foo = Object("Foo", {"bar": Bar})

    @Foo.field("bar")
    def resolve_foo_bar(root, info) -> Bar:
        return Bar()

    Query = Object("Query", {"foo": Foo})

    @Query.field("foo")
    def resolve_query_foo(root, info) -> Foo:
        return Foo()

    schema = Schema(query=Query)

    result = schema.execute("{foo {bar {baz {val}}}}")

    assert result.errors is None
    assert result.data == {"foo": {"bar": {"baz": {"val": "BAZ-VALUE!"}}}}
예제 #2
0
    def schema(self):
        schema = Schema()

        Success = Object(
            "Success",
            {
                "ok": bool,
                "result_id": int,
            },
        )

        Error = Object(
            "Error",
            {
                "ok": bool,
                "error_message": str,
            },
        )

        Result = pyql.Union("Result", [Success, Error])

        @schema.query.field("action")
        def resolve_action(root, info, id: int) -> Result:

            if id == 1:
                return Success(ok=True, result_id=123)

            if id == 2:
                return Error(ok=False, error_message="Action failed")

            return None

        return schema
예제 #3
0
def test_input_objects():

    Post = Object(
        "Post",
        fields={
            "id": ID,
            "title": str,
            "body": str,
        },
    )

    PostInput = InputObject(
        "PostInput",
        fields={
            "title": NonNull(str),
            "body": str,
        },
    )

    Query = Object("Query", fields={"dummy": str})
    Mutation = Object("Mutation")

    @Mutation.field("create_post")
    def resolve_create_post(root, info, post: PostInput) -> Post:
        return Post(id="1", title=post.title, body=post.body)

    schema = Schema(query=Query, mutation=Mutation)

    result = schema.execute(
        """
    mutation createPost($post: PostInput!) {
      createPost(post: $post) {
        id, title, body
      }
    }
    """,
        variable_values={"post": {
            "title": "Hello",
            "body": "Hello world"
        }},
    )

    assert result.errors is None
    assert result.data == {
        "createPost": {
            "id": "1",
            "title": "Hello",
            "body": "Hello world",
        }
    }
예제 #4
0
def test_objects_can_reference_each_other():

    Foo = Object("Foo", {"name": str})
    Bar = Object("Bar", {"name": str})

    @Foo.field("bar")
    def resolve_foo_bar(root, info) -> Bar:
        return Bar(name="{} bar".format(root.name))

    @Bar.field("foo")
    def resolve_bar_foo(root, info) -> Foo:
        return Foo(name="{} foo".format(root.name))

    schema = Schema()

    @schema.query.field("foo")
    def resolve_query_foo(root, info) -> Foo:
        return Foo(name="FOO")

    @schema.query.field("bar")
    def resolve_query_bar(root, info) -> Bar:
        return Bar(name="BAR")

    result = schema.execute("""
    query {
        foo {
            name
            bar {
                name
                foo {
                    name
                }
            }
        }
    }
    """)

    assert result.errors is None
    assert result.data == {
        "foo": {
            "name": "FOO",
            "bar": {
                "name": "FOO bar",
                "foo": {
                    "name": "FOO bar foo"
                }
            },
        }
    }
def test_base_scalars_output():

    Example = Object(
        "Example",
        fields={
            "my_str": str,
            "my_int": int,
            "my_float": float,
            "my_bool": bool,
            "my_id": ID,
        },
    )

    schema = Schema()

    @schema.query.field("example")
    def resolve_example(root, info) -> Example:
        return Example(
            my_str="Some string", my_int=42, my_float=3.14, my_bool=True, my_id="1234"
        )

    result = schema.execute("{ example { myStr, myInt, myFloat, myBool, myId } }")
    assert result.errors is None
    assert result.data == {
        "example": {
            "myStr": "Some string",
            "myInt": 42,
            "myFloat": 3.14,
            "myBool": True,
            "myId": "1234",
        },
    }
예제 #6
0
def test_input_objects_field_names_are_converted():

    # See issue #13: https://github.com/rshk/pyql/issues/13

    MyInput = InputObject(
        "MyInput",
        fields={
            "some_field_name": str,
        },
    )

    # Need at least one query, for some reason...
    schema = Schema(query=Object("Query", {"q": str}))

    @schema.mutation.field("do_something")
    def resolve_do_something(root, info, obj: MyInput) -> str:
        return obj.some_field_name

    result = schema.execute(
        """
    mutation doSomething($obj: MyInput!) {
        doSomething(obj: $obj)
    }
    """,
        variable_values={"obj": {
            "someFieldName": "HELLO"
        }},
    )

    assert result.errors is None
    assert result.data == {"doSomething": "HELLO"}
예제 #7
0
def test_field_names_can_be_camelcase_in_python():

    MyInput = InputObject(
        "MyInput",
        fields={
            "someFieldName": str,
        },
    )

    # Need at least one query, for some reason...
    schema = Schema(query=Object("Query", {"q": str}))

    @schema.mutation.field("do_something")
    def resolve_do_something(root, info, obj: MyInput) -> str:
        with pytest.raises(AttributeError):
            obj.some_field_name
        return obj.someFieldName

    result = schema.execute(
        """
    mutation doSomething($obj: MyInput!) {
        doSomething(obj: $obj)
    }
    """,
        variable_values={"obj": {
            "someFieldName": "HELLO"
        }},
    )

    assert result.errors is None
    assert result.data == {"doSomething": "HELLO"}
def test_mutation():

    # ...graphql-core forces us to have at least a query
    Query = Object("Query", fields={"foo": str})

    Mutation = Object("Mutation")

    @Mutation.field("example")
    def resolve_mutate_something(root, info, text: str) -> bool:
        return True

    schema = Schema(query=Query, mutation=Mutation)

    result = schema.execute(
        """
    mutation foo {
        example(text: "HEY")
    }
    """
    )

    assert result.errors is None
    assert result.data == {"example": True}
예제 #9
0
def test_resolver_cannot_return_different_container_instance():
    """
    An instance of a different "container" instance is considered a
    mistake, even if the two are compatible.
    """

    schema = Schema()

    Foo = Object("Foo", {"text": str})
    Bar = Object("Bar", {"text": str})

    @schema.query.field("foo")
    def resolve_foo(root, info) -> Foo:
        return Bar(text="a")

    result = schema.execute("""
    { foo { text } }
    """)

    assert result.data == {"foo": None}
    assert result.errors is not None
    assert len(result.errors) == 1
    assert (result.errors[0].message ==
            "Expected value of type 'Foo' but got: <Bar instance>.")
def test_mutation_with_variables():

    # ...graphql-core forces us to have at least a query
    Query = Object("Query", fields={"foo": str})

    Mutation = Object("Mutation")

    @Mutation.field("letter_count")
    def resolve_letter_count(root, info, text: str) -> int:
        return len(text)

    schema = Schema(query=Query, mutation=Mutation)

    result = schema.execute(
        """
    mutation letterCount($text: String!) {
        result: letterCount(text: $text)
    }
    """,
        variable_values={"text": "HELLO"},
    )

    assert result.errors is None
    assert result.data == {"result": 5}
예제 #11
0
def test_resolver_can_return_dict():

    schema = Schema()

    Foo = Object("Foo", {"text": str})

    @schema.query.field("foo")
    def resolve_foo(root, info) -> Foo:
        return {"text": "a"}

    result = schema.execute("""
    { foo { text } }
    """)

    assert result.errors is None
    assert result.data == {"foo": {"text": "a"}}
예제 #12
0
def test_returning_an_incompatible_object_fails():

    schema = Schema()

    Foo = Object("Foo", {"text": str})
    Spam = namedtuple("Spam", ("spam", ))

    @schema.query.field("foo")
    def resolve_foo(root, info) -> Foo:
        return Spam(spam="SPAM" * 10)

    result = schema.execute("""
    { foo { text } }
    """)

    assert result.data == {"foo": {"text": None}}
    assert result.errors is None
def test_enum_output():
    """Return value from an Enum"""

    Card = Object(
        "Card",
        fields={
            "name": str,
            "color": Color,
        },
    )

    schema = Schema()

    @schema.query.field("random_card")
    def resolve_random_card(root, info) -> Card:
        return Card(name="Hello", color=Color.RED)

    result = schema.execute("{ randomCard { name, color } }")
    assert result.errors is None
    assert result.data == {"randomCard": {"name": "Hello", "color": "RED"}}
예제 #14
0
def test_resolver_can_return_compatible_object():
    """
    Still a duck.
    """

    schema = Schema()

    Foo = Object("Foo", {"text": str})
    AnotherFoo = namedtuple("AnotherFoo", ("text", ))

    @schema.query.field("foo")
    def resolve_foo(root, info) -> Foo:
        return AnotherFoo(text="a")

    result = schema.execute("""
    { foo { text } }
    """)

    assert result.errors is None
    assert result.data == {"foo": {"text": "a"}}
예제 #15
0
def test_schema_with_nested_objects():

    schema = Schema()

    Post = Object(
        "Post",
        fields={
            "title": str,
            "body": str,
        },
    )

    @schema.query.field("post")
    def resolve_posts(root, info) -> Post:
        return Post(title="One", body="First post")

    # ----------------------------------------------------------------

    result = schema.execute("{post {title, body}}")

    assert result.data == {"post": {"title": "One", "body": "First post"}}
    assert result.errors is None
예제 #16
0
def test_omitted_fields_are_filled_with_none():

    schema = Schema()

    MyObj = Object(
        "MyObj",
        fields={
            "foo": str,
            "bar": str,
        },
    )

    @schema.query.field("my_obj")
    def resolve_my_obj(root, info) -> MyObj:
        return MyObj(foo="FOO")

    # ----------------------------------------------------------------

    result = schema.execute("{ myObj { foo, bar } }")

    assert result.errors is None
    assert result.data == {"myObj": {"foo": "FOO", "bar": None}}
예제 #17
0
def test_fields_are_converted_to_camel_case():

    schema = Schema()

    MyObject = Object("MyObject", fields={"some_field_name": str})

    @schema.query.field("hello")
    def resolve_hello(root, info) -> MyObject:
        return MyObject(some_field_name="A VALUE")

    # ----------------------------------------------------------------

    result = schema.execute(
        """
        query  {
            hello {
                someFieldName
            }
        }
        """
    )

    assert result.errors is None
    assert result.data == {"hello": {"someFieldName": "A VALUE"}}
예제 #18
0
def test_schema_with_nested_objects_list():

    schema = Schema()

    Post = Object(
        "Post",
        fields={
            "title": str,
            "body": str,
        },
    )

    @schema.query.field("posts")
    def resolve_posts(root, info) -> List[Post]:
        return [
            Post(title="One", body="First post"),
            Post(title="Two", body="Second post"),
        ]

    # ----------------------------------------------------------------

    result = schema.execute("{posts {title, body}}")

    assert result.data == {
        "posts": [
            {
                "title": "One",
                "body": "First post"
            },
            {
                "title": "Two",
                "body": "Second post"
            },
        ]
    }
    assert result.errors is None
예제 #19
0
from pyql import Object

from app.lib.auth import get_token_for_credentials

from .base import schema


AuthResult = Object('AuthResult', {
    'ok': bool,
    'token': str,
})


@schema.mutation.field('authenticate')
def resolve_auth(root, info, username: str, password: str) -> AuthResult:

    token = get_token_for_credentials(username, password)

    if not token:
        return AuthResult(ok=False, token=None)

    return AuthResult(ok=True, token=token)
예제 #20
0
import logging
from datetime import datetime
from typing import List

from pyql import InputObject, Object

from app.core.exceptions import UserError
from app.core.library import LibraryCore

from .base import schema

logger = logging.getLogger(__name__)

Book = Object('Book', {
    'id': int,
    'title': str,
    'author': str,
    'cover_url': str,
})

BookRequest = Object('BookRequest', {
    'id': int,
    'email': str,
    'title': str,
    'timestamp': datetime,
})


@BookRequest.field('timestamp')
def resolve_book_request_timestamp(root, info) -> datetime:
    return root.date_created
예제 #21
0
from pyql import Object

from .base import schema
from .user import User

Info = Object('Info', {
    'version': str,
})


@Info.field('user')
def resolve_info_user(root, info) -> User:
    user = info.context.auth_info.user
    if not user:
        return None
    return user


@schema.query.field('info')
def resolve_info(root, info) -> Info:
    return Info(version='1.0')
예제 #22
0
from pyql import InputObject, Object
from rx import Observable

from app.core.example import NotesCore
from app.core.exceptions import UserError
from app.lib.graphql import GraphQLFileUpload

from .base import schema

logger = logging.getLogger(__name__)


Note = Object('Note', {
    'id': int,
    'title': str,
    'text': str,
})


@Note.field('summary')
def resolve_note_summary(note, info, length: int = 100) -> str:

    if length < 0:
        raise ValueError('Invalid length: {}'.format(length))

    return (note.text or '')[:length]


# Note: list ---------------------------------------------------------
예제 #23
0
def test_container_object_is_instance_of_object():
    MyObject = Object("MyObject", fields={"foo": str})

    obj = MyObject(foo="A")

    assert isinstance(obj, MyObject)
예제 #24
0
from pyql import InputObject, Object

from app.core.exceptions import AuthorizationError
from app.core.user import UsersCore

from .base import schema
from .user import User

CreateUserInput = InputObject('CreateUserInput', {
    'email': str,
    'password': str,
    'display_name': str,
})

CreateUserOutput = Object('CreateUserOutput', {
    'ok': bool,
    'user': User,
})


@schema.mutation.field('create_user')
def mut_create_user(root, info, data: CreateUserInput) -> CreateUserOutput:
    core = UsersCore.from_request()

    try:
        uid = core.create(email=data.email,
                          password=data.password,
                          display_name=data.display_name)

    except AuthorizationError:
        return CreateUserOutput(ok=False)
예제 #25
0
from typing import List

from pyql import Object
from pyql.utils.str_converters import to_camel_case

from .fields import AnyValue

FormFieldConfig = Object('FormFieldConfig', {
    'id': str,
    'value': AnyValue,
    'readable': bool,
    'editable': bool,
    'required': bool,
})


@FormFieldConfig.field('id')
def resolve_formfieldconfig_id(cfg, info) -> str:
    # This needs to match the field name in javascript
    return to_camel_case(cfg.id)


FormConfig = Object('FormConfig', {
    'editable': bool,
    'fields': List[FormFieldConfig],
})
def test_nested_objects_namespace():

    Baz = Object("Baz")

    @Baz.field("val")
    def resolve_baz_val(root, info) -> str:
        return "BAZ-VALUE!"

    Bar = Object("Bar")
    Bar.namespace_field("baz", Baz)

    Foo = Object("Foo")
    Foo.namespace_field("bar", Bar)

    Query = Object("Query")
    Query.namespace_field("foo", Foo)

    schema = Schema(query=Query)

    result = schema.execute("{foo {bar {baz {val}}}}")

    assert result.errors is None
    assert result.data == {"foo": {"bar": {"baz": {"val": "BAZ-VALUE!"}}}}
예제 #27
0
from pyql import Object
import hashlib

from app.utils.normalize import normalize_email_address


User = Object('User', {
    'id': int,
    'email': str,
    'display_name': str,
    'image_url': str,
})


@User.field('display_name')
def resolve_display_name(user, info) -> str:
    if user.display_name:
        return user.display_name

    return get_name_from_email(user.email)


@User.field('image_url')
def resolve_image_url(user, info) -> str:
    return get_gravatar_url(user.email)


def get_name_from_email(email):
    return email.split('@')[0]