Beispiel #1
0
def test_flattened_converted_error():
    with raises(TypeError):
        deserialize(Data3, {"attr": 0})
    with raises(TypeError):
        serialize(Data3, Data3(Field2(0)))
    with raises(TypeError):
        deserialization_schema(Data3)
    with raises(TypeError):
        serialization_schema(Data3)
    with raises(TypeError):
        graphql_schema(query=[get_data3])
Beispiel #2
0
def test_default_conversion_type_name():
    assert (
        print_schema(graphql_schema(query=[b]))
        == """\
type Query {
  b: B!
}

type B {
  a: Int!
}
"""
    )
    assert serialization_schema(B, all_refs=True) == {
        "$ref": "#/$defs/B",
        "$defs": {
            "B": {"$ref": "#/$defs/A"},
            "A": {
                "type": "object",
                "properties": {"a": {"type": "integer"}},
                "required": ["a"],
                "additionalProperties": False,
            },
        },
        "$schema": "http://json-schema.org/draft/2019-09/schema#",
    }
    assert serialization_schema(B) == {
        "type": "object",
        "properties": {"a": {"type": "integer"}},
        "required": ["a"],
        "additionalProperties": False,
        "$schema": "http://json-schema.org/draft/2019-09/schema#",
    }
Beispiel #3
0
async def test_subscription(alias, conversion, error_handler, resolver):
    if alias is not None:
        sub_name = alias
    elif resolver is not None:
        sub_name = resolver.__name__
    else:
        sub_name = events.__name__
    if (alias, conversion, error_handler, resolver) == (None, None, Undefined,
                                                        None):
        sub_op = events
    else:
        sub_op = Subscription(events,
                              alias,
                              conversion,
                              None,
                              error_handler,
                              resolver=resolver)
    schema = graphql_schema(query=[hello],
                            subscription=[sub_op],
                            types=[Event])
    sub_field = sub_name
    if resolver is not None:
        sub_field += "(dummy: Boolean)"
    sub_field += f": {'String' if conversion else 'Event'}"
    if error_handler is Undefined:
        sub_field += "!"
    schema_str = """\
type Event {
  name: String!
}

type Query {
  hello: String!
}

type Subscription {
  %s
}
"""
    assert print_schema(schema) == schema_str % sub_field
    sub_query = sub_name
    if conversion is None:
        sub_query += "{name}"
    subscription = await graphql.subscribe(
        schema, graphql.parse("subscription {%s}" % sub_query))
    result = EVENTS
    if resolver:
        result = [s.capitalize() for s in result]
    if not conversion:
        result = [{"name": s} for s in result]
    assert [ev.data async for ev in subscription] == [{
        sub_name: r
    } for r in result]
Beispiel #4
0
def test_annotated_schema():
    assert (deserialization_schema(A) == serialization_schema(A) == {
        "$schema": "http://json-schema.org/draft/2019-09/schema#",
        "type": "object",
        "properties": {
            "a": {
                "type": "integer",
                "maximum": 10,
                "minimum": 0,
                "description": "field description",
            }
        },
        "required": ["a"],
        "additionalProperties": False,
    })
    assert (deserialization_schema(A, all_refs=True) == serialization_schema(
        A, all_refs=True) == {
            "$schema": "http://json-schema.org/draft/2019-09/schema#",
            "$ref": "#/$defs/A",
            "$defs": {
                "A": {
                    "additionalProperties": False,
                    "properties": {
                        "a": {
                            "$ref": "#/$defs/someInt",
                            "description": "field description",
                            "minimum": 0,
                        }
                    },
                    "required": ["a"],
                    "type": "object",
                },
                "someInt": {
                    "description": "type description",
                    "maximum": 10,
                    "type": "integer",
                },
            },
        })
    assert (print_schema(graphql_schema(query=[a])) == '''\
type Query {
  a: A!
}

type A {
  """field description"""
  a: someInt!
}

"""type description"""
scalar someInt
''')
Beispiel #5
0
def test_flattened_converted():
    data2 = deserialize(Data2, {"attr": 0})
    assert isinstance(data2.data_field2,
                      Field2) and data2.data_field2.attr == 0
    assert serialize(Data2, data2) == {"attr": 0}
    assert (deserialization_schema(Data) == serialization_schema(Data) == {
        "$schema":
        "http://json-schema.org/draft/2019-09/schema#",
        "type":
        "object",
        "allOf": [
            {
                "type": "object",
                "additionalProperties": False
            },
            {
                "type": "object",
                "properties": {
                    "attr": {
                        "type": "integer"
                    }
                },
                "required": ["attr"],
                "additionalProperties": False,
            },
        ],
        "unevaluatedProperties":
        False,
    })
    schema = graphql_schema(query=[get_data2])
    assert graphql_sync(schema, "{getData2{attr}}").data == {
        "getData2": {
            "attr": 0
        }
    }
    assert (print_schema(schema) == """\
type Query {
  getData2: Data2!
}

type Data2 {
  attr: Int!
}
""")
Beispiel #6
0
def test_resolver_default_parameter_not_serializable(tp, default):
    def resolver(arg=default) -> bool:
        return arg is default

    resolver.__annotations__["arg"] = tp
    # wraps in order to trigger the bug of get_type_hints with None default value
    resolver2 = wraps(resolver)(lambda arg=default: resolver(arg))
    schema = graphql_schema(query=[resolver2])
    assert (
        print_schema(schema)
        == """\
type Query {
  resolver(arg: Int): Boolean!
}
"""
    )
    assert (
        graphql_sync(schema, "{resolver}").data
        == graphql_sync(schema, "{resolver(arg: null)}").data
        == {"resolver": True}
    )
Beispiel #7
0
def test_resolver_position():
    assert serialization_schema(B) == {
        "type": "object",
        "properties": {
            "a": {
                "type": "integer"
            },
            "b": {
                "type": "integer"
            },
            "c": {
                "type": "integer"
            },
            "d": {
                "type": "integer"
            },
            "e": {
                "type": "integer"
            },
        },
        "required": ["a", "b", "c", "d", "e"],
        "additionalProperties": False,
        "$schema": "http://json-schema.org/draft/2019-09/schema#",
    }
    assert (print_schema(graphql_schema(query=[query])) == """\
type Query {
  query: B!
}

type B {
  a: Int!
  b: Int!
  c: Int!
  d: Int!
  e: Int!
}
""")
Beispiel #8
0
@dataclass
class Foo:
    foo: int


@dataclass
class Bar:
    bar: int


def foo_or_bar() -> Union[Foo, Bar]:
    ...


# union_ref default value is made explicit here
schema = graphql_schema(query=[foo_or_bar], union_name="Or".join)
schema_str = """\
type Query {
  fooOrBar: FooOrBar!
}

union FooOrBar = Foo | Bar

type Foo {
  foo: Int!
}

type Bar {
  bar: Int!
}
"""
Beispiel #9
0
from graphql.utilities import print_schema

from apischema import schema
from apischema.graphql import graphql_schema


class MyEnum(Enum):
    FOO = "FOO"
    BAR = "BAR"


def echo(enum: MyEnum) -> MyEnum:
    return enum


schema_ = graphql_schema(query=[echo],
                         enum_schemas={MyEnum.FOO: schema(description="foo")})
schema_str = '''\
type Query {
  echo(enum: MyEnum!): MyEnum!
}

enum MyEnum {
  """foo"""
  FOO
  BAR
}
'''
assert print_schema(schema_) == schema_str
assert graphql_sync(schema_, "{echo(enum: FOO)}").data == {"echo": "FOO"}
Beispiel #10
0
from dataclasses import dataclass

from graphql import print_schema

from apischema.graphql import Query, graphql_schema, resolver


@dataclass
class Foo:
    @resolver
    async def bar(self, arg: int = 0) -> str:
        ...


async def get_foo() -> Foo:
    ...


schema = graphql_schema(query=[Query(get_foo, alias="foo", error_handler=None)])
schema_str = """\
type Query {
  foo: Foo
}

type Foo {
  bar(arg: Int! = 0): String!
}
"""
assert print_schema(schema) == schema_str
Beispiel #11
0
    return USERS


def posts() -> Collection[Post]:
    return POSTS


def user(username: str) -> Optional[User]:
    for user in users():
        if user.username == username:
            return user
    else:
        return None


schema = graphql_schema(query=[users, user, posts], id_types={UUID})
schema_str = """\
type Query {
  users: [User!]!
  user(username: String!): User
  posts: [Post!]!
}

type User {
  id: ID!
  username: String!
  birthday: Date
  posts: [Post!]!
}

scalar Date
Beispiel #12
0
from typing import Optional, Union

from graphql import graphql_sync

from apischema import Undefined, UndefinedType
from apischema.graphql import graphql_schema


def arg_is_absent(
        arg: Optional[Union[int, UndefinedType]] = Undefined) -> bool:
    return arg is Undefined


schema = graphql_schema(query=[arg_is_absent])
assert graphql_sync(schema, "{argIsAbsent(arg: null)}").data == {
    "argIsAbsent": False
}
assert graphql_sync(schema, "{argIsAbsent}").data == {"argIsAbsent": True}
Beispiel #13
0
    # TOTAL FRAMES
    total_frames = len(path)  # Capture the total length of the path

    # MAX FRAMES
    # Limit the consumed data by the max_frames argument
    if max_frames and (max_frames < len(path)):
        # Cap the frames by the max limit
        path = reduce_frames(dims, max_frames)
    # WARNING: path object is consumed after this statement
    chunk = path.consume(max_frames)

    return PointsResponse(chunk, total_frames)


# Define the schema
schema = graphql_schema(query=[validate_spec, get_points])


def reduce_frames(dims: List[Dimension], max_frames: int) -> Path:
    """Removes frames from a spec such that it produces a number that is
    closest to the max points value

    Args:
        dims (List[Dimension]): A dimension object created by a spec
        max_frames (int): The maximum number of frames the user wishes to be returned

    Returns:
        Path: A consumable object containing the expanded dimension with reduced frames
    """
    # Calculate the total number of frames
    num_frames = 1
Beispiel #14
0
from apischema import serialize
from apischema.graphql import graphql_schema, relay


@dataclass
class Faction(relay.Node[int]):
    name: str

    @classmethod
    def get_by_id(cls,
                  id: int,
                  info: graphql.GraphQLResolveInfo = None) -> "Faction":
        return [Faction(0, "Empire"), Faction(1, "Rebels")][id]


schema = graphql_schema(query=[relay.node], types=relay.nodes())
some_global_id = Faction.get_by_id(0).global_id  # Let's pick a global id ...
assert some_global_id == relay.GlobalId("0", Faction)
query = """
query factionName($id: ID!) {
    node(id: $id) {
        ... on Faction {
            name
        }
    }
}
"""
assert graphql.graphql_sync(  # ... and use it in a query
    schema,
    query,
    variable_values={
Beispiel #15
0
from dataclasses import dataclass
from typing import Optional
from uuid import UUID

from graphql import print_schema

from apischema.graphql import graphql_schema


@dataclass
class Foo:
    bar: UUID


def foo() -> Optional[Foo]:
    ...


# id_types={UUID} is equivalent to id_types=lambda t: t in {UUID}
schema = graphql_schema(query=[foo], id_types={UUID})
schema_str = """\
type Query {
  foo: Foo
}

type Foo {
  bar: ID!
}
"""
assert print_schema(schema) == schema_str
Beispiel #16
0
            "items": {
                "type": "string"
            },
            "uniqueItems": True
        },
    },
    "required": ["id", "name"],
    "additionalProperties": False,
}


# Define GraphQL operations
def resources(tags: Collection[str] = None) -> Collection[Resource]:
    ...


# Generate GraphQL schema
schema = graphql_schema(query=[resources], id_types={UUID})
schema_str = """\
type Query {
  resources(tags: [String!]): [Resource!]
}

type Resource {
  id: ID!
  name: String!
  tags: [String!]!
}
"""
assert print_schema(schema) == schema_str
Beispiel #17
0
@interface
@dataclass
class Bar:
    bar: int


@dataclass
class Foo(Bar):
    baz: str


def bar() -> Bar:
    ...


schema = graphql_schema(query=[bar], types=[Foo])
# type Foo would have not been present if Foo was not put in types
schema_str = """\
type Foo implements Bar {
  bar: Int!
  baz: String!
}

interface Bar {
  bar: Int!
}

type Query {
  bar: Bar!
}
"""
Beispiel #18
0

async def events() -> AsyncIterable[str]:
    yield "bonjour"
    yield "au revoir"


@dataclass
class Message:
    body: str


# Message can also be used directly as a function
schema = graphql_schema(
    query=[hello],
    subscription=[
        Subscription(events, alias="messageReceived", resolver=Message)
    ],
)
schema_str = """\
type Query {
  hello: String!
}

type Subscription {
  messageReceived: Message!
}

type Message {
  body: String!
}
"""
Beispiel #19
0
    @staticmethod
    def mutate(
        # mut_id is required because no default value
        faction_id: str,
        ship_name: str,
        mut_id: relay.ClientMutationId,
    ) -> "IntroduceShip":
        ...


def hello() -> str:
    return "world"


schema = graphql_schema(query=[hello], mutation=relay.mutations())
# clientMutationId field becomes non nullable in introduceShip types
schema_str = """\
type Query {
  hello: String!
}

type Mutation {
  introduceShip(input: IntroduceShipInput!): IntroduceShipPayload!
}

type IntroduceShipPayload {
  ship: Ship!
  faction: Faction!
  clientMutationId: String!
}
Beispiel #20
0
from dataclasses import dataclass
from typing import Optional
from uuid import UUID

from graphql import graphql_sync

from apischema.graphql import graphql_schema


@dataclass
class Foo:
    id: UUID


def foo() -> Optional[Foo]:
    return Foo(UUID("58c88e87-5769-4723-8974-f9ec5007a38b"))


schema = graphql_schema(
    query=[foo],
    id_types={UUID},
    id_encoding=(
        lambda s: b64decode(s).decode(),
        lambda s: b64encode(s.encode()).decode(),
    ),
)

assert graphql_sync(schema, "{foo{id}}").data == {
    "foo": {"id": "NThjODhlODctNTc2OS00NzIzLTg5NzQtZjllYzUwMDdhMzhi"}
}
Beispiel #21
0
class Bar:
    baz: int


@dataclass
class Foo:
    @resolver
    async def bar(self, arg: int = 0) -> Bar:
        ...


async def foo() -> Foo:
    ...


schema = graphql_schema(query=[foo])
schema_str = """\
type Query {
  foo: Foo
}

type Foo {
  bar(arg: Int! = 0): Bar
}

type Bar {
  baz: Int!
}
"""
assert print_schema(schema) == schema_str
Beispiel #22
0
import graphql
from graphql import print_schema

from apischema.graphql import graphql_schema


def hello() -> str:
    return "world"


async def events() -> AsyncIterable[str]:
    yield "bonjour"
    yield "au revoir"


schema = graphql_schema(query=[hello], subscription=[events])
schema_str = """\
type Query {
  hello: String!
}

type Subscription {
  events: String!
}
"""
assert print_schema(schema) == schema_str


async def test():
    subscription = await graphql.subscribe(
        schema, graphql.parse("subscription {events}"))
Beispiel #23
0
@dataclass
class Faction:
    @resolver
    def ships(
        self, first: Optional[int], after: Optional[Cursor]
    ) -> Optional[Connection[Optional[Ship]]]:
        edges = [relay.Edge(Ship("X-Wing"), 0), relay.Edge(Ship("B-Wing"), 1)]
        return Connection(edges, relay.PageInfo.from_edges(edges))


def faction() -> Optional[Faction]:
    return Faction()


schema = graphql_schema(query=[faction])
schema_str = """\
type Query {
  faction: Faction
}

type Faction {
  ships(first: Int, after: Int): ShipConnection
}

type ShipConnection {
  edges: [ShipEdge]
  pageInfo: PageInfo!
}

type ShipEdge {
Beispiel #24
0
from apischema.graphql import graphql_schema


def foo(test: int) -> int:
    return test


def bar(my_test: int) -> int:
    return my_test


def baz(my_test: Optional[int]) -> int:
    return my_test or 1


schema = graphql_schema(query=[foo, bar, baz])


def test_no_alias_needed():
    query = """
    {
        foo(test: 4)
    }
    """

    assert graphql_sync(schema, query).data == {"foo": 4}


def test_aliased_parameter():
    query = """
    {
Beispiel #25
0
@dataclass
class Bar:
    field: str


class Foo(TaggedUnion):
    bar: Tagged[Bar]
    baz: Tagged[int]


def query(foo: Foo) -> Foo:
    return foo


schema = graphql_schema(query=[query])
schema_str = """\
type Query {
  query(foo: FooInput!): Foo!
}

type Foo {
  bar: Bar
  baz: Int
}

type Bar {
  field: String!
}

input FooInput {
Beispiel #26
0
class Concat(Drawing):
    left: Drawing
    right: Drawing

    async def points(self) -> AsyncIterable[float]:
        async for point in self.left.points():
            yield point
        async for point in self.right.points():
            yield point


def echo(drawing: Drawing = None) -> Optional[Drawing]:
    return drawing


drawing_schema = graphql_schema(query=[echo])
assert (graphql.utilities.print_schema(drawing_schema) == """\
type Query {
  echo(drawing: DrawingInput): Drawing
}

type Drawing {
  Line: Line
  Concat: Concat
}

type Line {
  start: Float!
  stop: Float!
  step: Float!
}