Use latest graphql-core 3.1.0b1 instead of 3.0.3

Adapt Schema, because there is no type reducer in core 3.1 any more.
This commit is contained in:
Christoph Zwerschke 2020-03-04 12:23:40 +01:00
parent ffb7701466
commit 5e6f68957e
13 changed files with 293 additions and 328 deletions

View File

@ -1,2 +1,2 @@
[settings]
known_third_party = aniso8601,graphql,graphql_relay,promise,pytest,pytz,pyutils,setuptools,six,snapshottest,sphinx_graphene_theme
known_third_party = aniso8601,graphql,graphql_relay,promise,pytest,pytz,pyutils,setuptools,snapshottest,sphinx_graphene_theme

View File

@ -31,7 +31,16 @@ snapshots["test_correctly_refetches_xwing 1"] = {
snapshots[
"test_str_schema 1"
] = '''"""A faction in the Star Wars saga"""
] = '''type Query {
rebels: Faction
empire: Faction
node(
"""The ID of the object"""
id: ID!
): Node
}
"""A faction in the Star Wars saga"""
type Faction implements Node {
"""The ID of the object"""
id: ID!
@ -43,28 +52,20 @@ type Faction implements Node {
ships(before: String = null, after: String = null, first: Int = null, last: Int = null): ShipConnection
}
input IntroduceShipInput {
shipName: String!
factionId: String!
clientMutationId: String
}
type IntroduceShipPayload {
ship: Ship
faction: Faction
clientMutationId: String
}
type Mutation {
introduceShip(input: IntroduceShipInput!): IntroduceShipPayload
}
"""An object with an ID"""
interface Node {
"""The ID of the object"""
id: ID!
}
type ShipConnection {
"""Pagination data for this connection."""
pageInfo: PageInfo!
"""Contains the nodes in this connection."""
edges: [ShipEdge]!
}
"""
The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.
"""
@ -82,13 +83,13 @@ type PageInfo {
endCursor: String
}
type Query {
rebels: Faction
empire: Faction
node(
"""The ID of the object"""
id: ID!
): Node
"""A Relay edge containing a `Ship` and its cursor."""
type ShipEdge {
"""The item at the end of the edge"""
node: Ship
"""A cursor for use in pagination"""
cursor: String!
}
"""A ship in the Star Wars saga"""
@ -100,20 +101,19 @@ type Ship implements Node {
name: String
}
type ShipConnection {
"""Pagination data for this connection."""
pageInfo: PageInfo!
"""Contains the nodes in this connection."""
edges: [ShipEdge]!
type Mutation {
introduceShip(input: IntroduceShipInput!): IntroduceShipPayload
}
"""A Relay edge containing a `Ship` and its cursor."""
type ShipEdge {
"""The item at the end of the edge"""
node: Ship
type IntroduceShipPayload {
ship: Ship
faction: Faction
clientMutationId: String
}
"""A cursor for use in pagination"""
cursor: String!
input IntroduceShipInput {
shipName: String!
factionId: String!
clientMutationId: String
}
'''

View File

@ -42,7 +42,7 @@ from .utils.resolve_only_args import resolve_only_args
from .utils.module_loading import lazy_import
VERSION = (3, 0, 0, "alpha", 1)
VERSION = (3, 0, 0, "beta", 0)
__version__ = get_version(VERSION)

View File

@ -183,6 +183,12 @@ def test_str_schema():
name: String
}
"""An object with an ID"""
interface Node {
"""The ID of the object"""
id: ID!
}
type MyOtherNode implements Node {
"""The ID of the object"""
id: ID!
@ -191,12 +197,6 @@ def test_str_schema():
extraField: String
}
"""An object with an ID"""
interface Node {
"""The ID of the object"""
id: ID!
}
type RootQuery {
first: String
node(

View File

@ -59,9 +59,12 @@ def test_str_schema_correct():
query: RootQuery
}
interface BasePhoto {
"""The width of the photo in pixels"""
width: Int
type User implements Node {
"""The ID of the object"""
id: ID!
"""The full name of the user"""
name: String
}
interface Node {
@ -77,20 +80,17 @@ def test_str_schema_correct():
width: Int
}
interface BasePhoto {
"""The width of the photo in pixels"""
width: Int
}
type RootQuery {
node(
"""The ID of the object"""
id: ID!
): Node
}
type User implements Node {
"""The ID of the object"""
id: ID!
"""The full name of the user"""
name: String
}
'''
)

View File

@ -27,7 +27,7 @@ def test_issue():
graphene.Schema(query=Query)
assert str(exc_info.value) == (
"Query fields cannot be resolved:"
"Query fields cannot be resolved."
" IterableConnectionField type has to be a subclass of Connection."
' Received "MyUnion".'
)

View File

@ -3,8 +3,8 @@ from __future__ import absolute_import
import datetime
from aniso8601 import parse_date, parse_datetime, parse_time
from graphql import Undefined
from graphql.language import StringValueNode
from graphql.error import GraphQLError
from graphql.language import StringValueNode, print_ast
from .scalars import Scalar
@ -20,25 +20,30 @@ class Date(Scalar):
def serialize(date):
if isinstance(date, datetime.datetime):
date = date.date()
assert isinstance(
date, datetime.date
), 'Received not compatible date "{}"'.format(repr(date))
if not isinstance(date, datetime.date):
raise GraphQLError("Date cannot represent value: {}".format(repr(date)))
return date.isoformat()
@classmethod
def parse_literal(cls, node):
if isinstance(node, StringValueNode):
if not isinstance(node, StringValueNode):
raise GraphQLError(
"Date cannot represent non-string value: {}".format(print_ast(node))
)
return cls.parse_value(node.value)
@staticmethod
def parse_value(value):
try:
if isinstance(value, datetime.date):
return value
elif isinstance(value, str):
if not isinstance(value, str):
raise GraphQLError(
"Date cannot represent non-string value: {}".format(repr(value))
)
try:
return parse_date(value)
except ValueError:
return Undefined
raise GraphQLError("Date cannot represent value: {}".format(repr(value)))
class DateTime(Scalar):
@ -50,25 +55,32 @@ class DateTime(Scalar):
@staticmethod
def serialize(dt):
assert isinstance(
dt, (datetime.datetime, datetime.date)
), 'Received not compatible datetime "{}"'.format(repr(dt))
if not isinstance(dt, (datetime.datetime, datetime.date)):
raise GraphQLError("DateTime cannot represent value: {}".format(repr(dt)))
return dt.isoformat()
@classmethod
def parse_literal(cls, node):
if isinstance(node, StringValueNode):
if not isinstance(node, StringValueNode):
raise GraphQLError(
"DateTime cannot represent non-string value: {}".format(print_ast(node))
)
return cls.parse_value(node.value)
@staticmethod
def parse_value(value):
try:
if isinstance(value, datetime.datetime):
return value
elif isinstance(value, str):
if not isinstance(value, str):
raise GraphQLError(
"DateTime cannot represent non-string value: {}".format(repr(value))
)
try:
return parse_datetime(value)
except ValueError:
return Undefined
raise GraphQLError(
"DateTime cannot represent value: {}".format(repr(value))
)
class Time(Scalar):
@ -80,22 +92,27 @@ class Time(Scalar):
@staticmethod
def serialize(time):
assert isinstance(
time, datetime.time
), 'Received not compatible time "{}"'.format(repr(time))
if not isinstance(time, datetime.time):
raise GraphQLError("Time cannot represent value: {}".format(repr(time)))
return time.isoformat()
@classmethod
def parse_literal(cls, node):
if isinstance(node, StringValueNode):
if not isinstance(node, StringValueNode):
raise GraphQLError(
"Time cannot represent non-string value: {}".format(print_ast(node))
)
return cls.parse_value(node.value)
@classmethod
def parse_value(cls, value):
try:
if isinstance(value, datetime.time):
return value
elif isinstance(value, str):
if not isinstance(value, str):
raise GraphQLError(
"Time cannot represent non-string value: {}".format(repr(value))
)
try:
return parse_time(value)
except ValueError:
return Undefined
raise GraphQLError("Time cannot represent value: {}".format(repr(value)))

View File

@ -1,4 +1,5 @@
from graphql import Undefined
from .mountedtype import MountedType
from .structures import NonNull
from .utils import get_type

View File

@ -7,7 +7,6 @@ from graphql import (
graphql,
graphql_sync,
introspection_types,
is_type,
print_schema,
GraphQLArgument,
GraphQLBoolean,
@ -71,118 +70,74 @@ def is_graphene_type(type_):
return True
def resolve_type(resolve_type_func, map_, type_name, root, info, _type):
type_ = resolve_type_func(root, info)
if not type_:
return_type = map_[type_name]
return default_type_resolver(root, info, return_type)
if inspect.isclass(type_) and issubclass(type_, ObjectType):
graphql_type = map_.get(type_._meta.name)
assert graphql_type, "Can't find type {} in schema".format(type_._meta.name)
assert graphql_type.graphene_type == type_, (
"The type {} does not match with the associated graphene type {}."
).format(type_, graphql_type.graphene_type)
return graphql_type
return type_
def is_type_of_from_possible_types(possible_types, root, _info):
return isinstance(root, possible_types)
class GrapheneGraphQLSchema(GraphQLSchema):
"""A GraphQLSchema that can deal with Graphene types as well."""
class TypeMap(dict):
def __init__(
self,
query=None,
mutation=None,
subscription=None,
types=None,
directives=None,
auto_camelcase=True,
):
assert_valid_root_type(query)
assert_valid_root_type(mutation)
assert_valid_root_type(subscription)
if types is None:
types = []
for type_ in types:
assert is_graphene_type(type_)
self.auto_camelcase = auto_camelcase
super().__init__(query, mutation, subscription, types, directives)
if query:
self.query_type = self.get_type(
query.name if isinstance(query, GraphQLObjectType) else query._meta.name
)
if mutation:
self.mutation_type = self.get_type(
mutation.name
if isinstance(mutation, GraphQLObjectType)
else mutation._meta.name
)
if subscription:
self.subscription_type = self.get_type(
subscription.name
if isinstance(subscription, GraphQLObjectType)
else subscription._meta.name
)
create_graphql_type = self.add_type
def get_graphql_type(self, _type):
if not _type:
return _type
if is_type(_type):
return _type
if is_graphene_type(_type):
graphql_type = self.get_type(_type._meta.name)
assert graphql_type, "Type {} not found in this schema.".format(
_type._meta.name
self.query = create_graphql_type(query) if query else None
self.mutation = create_graphql_type(mutation) if mutation else None
self.subscription = create_graphql_type(subscription) if subscription else None
self.types = [create_graphql_type(graphene_type) for graphene_type in types]
def add_type(self, graphene_type):
if inspect.isfunction(graphene_type):
graphene_type = graphene_type()
if isinstance(graphene_type, List):
return GraphQLList(self.add_type(graphene_type.of_type))
if isinstance(graphene_type, NonNull):
return GraphQLNonNull(self.add_type(graphene_type.of_type))
try:
name = graphene_type._meta.name
except AttributeError:
raise TypeError(
"Expected Graphene type, but received: {}.".format(graphene_type)
)
assert graphql_type.graphene_type == _type
graphql_type = self.get(name)
if graphql_type:
return graphql_type
raise Exception("{} is not a valid GraphQL type.".format(_type))
# noinspection PyMethodOverriding
def type_map_reducer(self, map_, type_):
if not type_:
return map_
if inspect.isfunction(type_):
type_ = type_()
if is_graphene_type(type_):
return self.graphene_reducer(map_, type_)
return super().type_map_reducer(map_, type_)
def graphene_reducer(self, map_, type_):
if isinstance(type_, (List, NonNull)):
return self.type_map_reducer(map_, type_.of_type)
if type_._meta.name in map_:
_type = map_[type_._meta.name]
if isinstance(_type, GrapheneGraphQLType):
assert _type.graphene_type == type_, (
"Found different types with the same name in the schema: {}, {}."
).format(_type.graphene_type, type_)
return map_
if issubclass(type_, ObjectType):
internal_type = self.construct_objecttype(map_, type_)
elif issubclass(type_, InputObjectType):
internal_type = self.construct_inputobjecttype(map_, type_)
elif issubclass(type_, Interface):
internal_type = self.construct_interface(map_, type_)
elif issubclass(type_, Scalar):
internal_type = self.construct_scalar(type_)
elif issubclass(type_, Enum):
internal_type = self.construct_enum(type_)
elif issubclass(type_, Union):
internal_type = self.construct_union(map_, type_)
if issubclass(graphene_type, ObjectType):
graphql_type = self.create_objecttype(graphene_type)
elif issubclass(graphene_type, InputObjectType):
graphql_type = self.create_inputobjecttype(graphene_type)
elif issubclass(graphene_type, Interface):
graphql_type = self.create_interface(graphene_type)
elif issubclass(graphene_type, Scalar):
graphql_type = self.create_scalar(graphene_type)
elif issubclass(graphene_type, Enum):
graphql_type = self.create_enum(graphene_type)
elif issubclass(graphene_type, Union):
graphql_type = self.construct_union(graphene_type)
else:
raise Exception("Expected Graphene type, but received: {}.".format(type_))
return super().type_map_reducer(map_, internal_type)
raise TypeError(
"Expected Graphene type, but received: {}.".format(graphene_type)
)
self[name] = graphql_type
return graphql_type
@staticmethod
def construct_scalar(type_):
def create_scalar(graphene_type):
# We have a mapping to the original GraphQL types
# so there are no collisions.
_scalars = {
@ -192,29 +147,31 @@ class GrapheneGraphQLSchema(GraphQLSchema):
Boolean: GraphQLBoolean,
ID: GraphQLID,
}
if type_ in _scalars:
return _scalars[type_]
if graphene_type in _scalars:
return _scalars[graphene_type]
return GrapheneScalarType(
graphene_type=type_,
name=type_._meta.name,
description=type_._meta.description,
serialize=getattr(type_, "serialize", None),
parse_value=getattr(type_, "parse_value", None),
parse_literal=getattr(type_, "parse_literal", None),
graphene_type=graphene_type,
name=graphene_type._meta.name,
description=graphene_type._meta.description,
serialize=getattr(graphene_type, "serialize", None),
parse_value=getattr(graphene_type, "parse_value", None),
parse_literal=getattr(graphene_type, "parse_literal", None),
)
@staticmethod
def construct_enum(type_):
def create_enum(graphene_type):
values = {}
for name, value in type_._meta.enum.__members__.items():
for name, value in graphene_type._meta.enum.__members__.items():
description = getattr(value, "description", None)
deprecation_reason = getattr(value, "deprecation_reason", None)
if not description and callable(type_._meta.description):
description = type_._meta.description(value)
if not description and callable(graphene_type._meta.description):
description = graphene_type._meta.description(value)
if not deprecation_reason and callable(type_._meta.deprecation_reason):
deprecation_reason = type_._meta.deprecation_reason(value)
if not deprecation_reason and callable(
graphene_type._meta.deprecation_reason
):
deprecation_reason = graphene_type._meta.deprecation_reason(value)
values[name] = GraphQLEnumValue(
value=value.value,
@ -223,107 +180,98 @@ class GrapheneGraphQLSchema(GraphQLSchema):
)
type_description = (
type_._meta.description(None)
if callable(type_._meta.description)
else type_._meta.description
graphene_type._meta.description(None)
if callable(graphene_type._meta.description)
else graphene_type._meta.description
)
return GrapheneEnumType(
graphene_type=type_,
graphene_type=graphene_type,
values=values,
name=type_._meta.name,
name=graphene_type._meta.name,
description=type_description,
)
def construct_objecttype(self, map_, type_):
if type_._meta.name in map_:
_type = map_[type_._meta.name]
if isinstance(_type, GrapheneGraphQLType):
assert _type.graphene_type == type_, (
"Found different types with the same name in the schema: {}, {}."
).format(_type.graphene_type, type_)
return _type
def create_objecttype(self, graphene_type):
create_graphql_type = self.add_type
def interfaces():
interfaces = []
for interface in type_._meta.interfaces:
self.graphene_reducer(map_, interface)
internal_type = map_[interface._meta.name]
assert internal_type.graphene_type == interface
interfaces.append(internal_type)
for graphene_interface in graphene_type._meta.interfaces:
interface = create_graphql_type(graphene_interface)
assert interface.graphene_type == graphene_interface
interfaces.append(interface)
return interfaces
if type_._meta.possible_types:
if graphene_type._meta.possible_types:
is_type_of = partial(
is_type_of_from_possible_types, type_._meta.possible_types
is_type_of_from_possible_types, graphene_type._meta.possible_types
)
else:
is_type_of = type_.is_type_of
is_type_of = graphene_type.is_type_of
return GrapheneObjectType(
graphene_type=type_,
name=type_._meta.name,
description=type_._meta.description,
fields=partial(self.construct_fields_for_type, map_, type_),
graphene_type=graphene_type,
name=graphene_type._meta.name,
description=graphene_type._meta.description,
fields=partial(self.create_fields_for_type, graphene_type),
is_type_of=is_type_of,
interfaces=interfaces,
)
def construct_interface(self, map_, type_):
if type_._meta.name in map_:
_type = map_[type_._meta.name]
if isinstance(_type, GrapheneInterfaceType):
assert _type.graphene_type == type_, (
"Found different types with the same name in the schema: {}, {}."
).format(_type.graphene_type, type_)
return _type
_resolve_type = None
if type_.resolve_type:
_resolve_type = partial(
resolve_type, type_.resolve_type, map_, type_._meta.name
def create_interface(self, graphene_type):
resolve_type = (
partial(
self.resolve_type, graphene_type.resolve_type, graphene_type._meta.name
)
if graphene_type.resolve_type
else None
)
return GrapheneInterfaceType(
graphene_type=type_,
name=type_._meta.name,
description=type_._meta.description,
fields=partial(self.construct_fields_for_type, map_, type_),
resolve_type=_resolve_type,
graphene_type=graphene_type,
name=graphene_type._meta.name,
description=graphene_type._meta.description,
fields=partial(self.create_fields_for_type, graphene_type),
resolve_type=resolve_type,
)
def construct_inputobjecttype(self, map_, type_):
def create_inputobjecttype(self, graphene_type):
return GrapheneInputObjectType(
graphene_type=type_,
name=type_._meta.name,
description=type_._meta.description,
out_type=type_._meta.container,
graphene_type=graphene_type,
name=graphene_type._meta.name,
description=graphene_type._meta.description,
out_type=graphene_type._meta.container,
fields=partial(
self.construct_fields_for_type, map_, type_, is_input_type=True
self.create_fields_for_type, graphene_type, is_input_type=True
),
)
def construct_union(self, map_, type_):
_resolve_type = None
if type_.resolve_type:
_resolve_type = partial(
resolve_type, type_.resolve_type, map_, type_._meta.name
)
def construct_union(self, graphene_type):
create_graphql_type = self.add_type
def types():
union_types = []
for objecttype in type_._meta.types:
self.graphene_reducer(map_, objecttype)
internal_type = map_[objecttype._meta.name]
assert internal_type.graphene_type == objecttype
union_types.append(internal_type)
for graphene_objecttype in graphene_type._meta.types:
object_type = create_graphql_type(graphene_objecttype)
assert object_type.graphene_type == graphene_objecttype
union_types.append(object_type)
return union_types
resolve_type = (
partial(
self.resolve_type, graphene_type.resolve_type, graphene_type._meta.name
)
if graphene_type.resolve_type
else None
)
return GrapheneUnionType(
graphene_type=type_,
name=type_._meta.name,
description=type_._meta.description,
graphene_type=graphene_type,
name=graphene_type._meta.name,
description=graphene_type._meta.description,
types=types,
resolve_type=_resolve_type,
resolve_type=resolve_type,
)
def get_name(self, name):
@ -331,15 +279,16 @@ class GrapheneGraphQLSchema(GraphQLSchema):
return to_camel_case(name)
return name
def construct_fields_for_type(self, map_, type_, is_input_type=False):
def create_fields_for_type(self, graphene_type, is_input_type=False):
create_graphql_type = self.add_type
fields = {}
for name, field in type_._meta.fields.items():
for name, field in graphene_type._meta.fields.items():
if isinstance(field, Dynamic):
field = get_field_as(field.get_type(self), _as=Field)
if not field:
continue
map_ = self.type_map_reducer(map_, field.type)
field_type = self.get_field_type(map_, field.type)
field_type = create_graphql_type(field.type)
if is_input_type:
_field = GraphQLInputField(
field_type,
@ -350,8 +299,7 @@ class GrapheneGraphQLSchema(GraphQLSchema):
else:
args = {}
for arg_name, arg in field.args.items():
map_ = self.type_map_reducer(map_, arg.type)
arg_type = self.get_field_type(map_, arg.type)
arg_type = create_graphql_type(arg.type)
processed_arg_name = arg.name or self.get_name(arg_name)
args[processed_arg_name] = GraphQLArgument(
arg_type,
@ -361,12 +309,13 @@ class GrapheneGraphQLSchema(GraphQLSchema):
if isinstance(arg.type, NonNull)
else arg.default_value,
)
resolve = field.get_resolver(
self.get_resolver(graphene_type, name, field.default_value)
)
_field = GraphQLField(
field_type,
args=args,
resolve=field.get_resolver(
self.get_resolver_for_type(type_, name, field.default_value)
),
resolve=resolve,
deprecation_reason=field.deprecation_reason,
description=field.description,
)
@ -374,15 +323,32 @@ class GrapheneGraphQLSchema(GraphQLSchema):
fields[field_name] = _field
return fields
def get_resolver_for_type(self, type_, name, default_value):
if not issubclass(type_, ObjectType):
def resolve_type(self, resolve_type_func, type_name, root, info, _type):
type_ = resolve_type_func(root, info)
if not type_:
return_type = self[type_name]
return default_type_resolver(root, info, return_type)
if inspect.isclass(type_) and issubclass(type_, ObjectType):
graphql_type = self.get(type_._meta.name)
assert graphql_type, "Can't find type {} in schema".format(type_._meta.name)
assert graphql_type.graphene_type == type_, (
"The type {} does not match with the associated graphene type {}."
).format(type_, graphql_type.graphene_type)
return graphql_type
return type_
def get_resolver(self, graphene_type, name, default_value):
if not issubclass(graphene_type, ObjectType):
return
resolver = getattr(type_, "resolve_{}".format(name), None)
resolver = getattr(graphene_type, "resolve_{}".format(name), None)
if not resolver:
# If we don't find the resolver in the ObjectType class, then try to
# find it in each of the interfaces
interface_resolver = None
for interface in type_._meta.interfaces:
for interface in graphene_type._meta.interfaces:
if name not in interface._meta.fields:
continue
interface_resolver = getattr(interface, "resolve_{}".format(name), None)
@ -394,16 +360,11 @@ class GrapheneGraphQLSchema(GraphQLSchema):
if resolver:
return get_unbound_function(resolver)
default_resolver = type_._meta.default_resolver or get_default_resolver()
default_resolver = (
graphene_type._meta.default_resolver or get_default_resolver()
)
return partial(default_resolver, name, default_value)
def get_field_type(self, map_, type_):
if isinstance(type_, List):
return GraphQLList(self.get_field_type(map_, type_.of_type))
if isinstance(type_, NonNull):
return GraphQLNonNull(self.get_field_type(map_, type_.of_type))
return map_.get(type_._meta.name)
class Schema:
"""Schema Definition.
@ -419,11 +380,11 @@ class Schema:
fields to *create, update or delete* data in your API.
subscription (ObjectType, optional): Root subscription *ObjectType*. Describes entry point
for fields to receive continuous updates.
types (List[ObjectType], optional): List of any types to include in schema that
may not be introspected through root types.
directives (List[GraphQLDirective], optional): List of custom directives to include in the
GraphQL schema. Defaults to only include directives defined by GraphQL spec (@include
and @skip) [GraphQLIncludeDirective, GraphQLSkipDirective].
types (List[GraphQLType], optional): List of any types to include in schema that
may not be introspected through root types.
auto_camelcase (bool): Fieldnames will be transformed in Schema's TypeMap from snake_case
to camelCase (preferred by GraphQL standard). Default True.
"""
@ -440,13 +401,15 @@ class Schema:
self.query = query
self.mutation = mutation
self.subscription = subscription
self.graphql_schema = GrapheneGraphQLSchema(
query,
mutation,
subscription,
types,
type_map = TypeMap(
query, mutation, subscription, types, auto_camelcase=auto_camelcase
)
self.graphql_schema = GraphQLSchema(
type_map.query,
type_map.mutation,
type_map.subscription,
type_map.types,
directives,
auto_camelcase=auto_camelcase,
)
def __str__(self):

View File

@ -3,7 +3,7 @@ import datetime
import pytz
from graphql import GraphQLError
from pytest import fixture, mark
from pytest import fixture
from ..datetime import Date, DateTime, Time
from ..objecttype import ObjectType
@ -84,8 +84,9 @@ def test_bad_datetime_query():
assert result.errors and len(result.errors) == 1
error = result.errors[0]
assert isinstance(error, GraphQLError)
assert error.message == (
'Expected type DateTime, found "Some string that\'s not a datetime".'
assert (
error.message == "DateTime cannot represent value:"
' "Some string that\'s not a datetime"'
)
assert result.data is None
@ -97,8 +98,9 @@ def test_bad_date_query():
error = result.errors[0]
assert isinstance(error, GraphQLError)
assert error.message == (
'Expected type Date, found "Some string that\'s not a date".'
assert (
error.message == "Date cannot represent value:"
' "Some string that\'s not a date"'
)
assert result.data is None
@ -110,8 +112,9 @@ def test_bad_time_query():
error = result.errors[0]
assert isinstance(error, GraphQLError)
assert error.message == (
'Expected type Time, found "Some string that\'s not a time".'
assert (
error.message == "Time cannot represent value:"
' "Some string that\'s not a time"'
)
assert result.data is None
@ -174,9 +177,6 @@ def test_time_query_variable(sample_time):
assert result.data == {"time": isoformat}
@mark.xfail(
reason="creating the error message fails when un-parsable object is not JSON serializable."
)
def test_bad_variables(sample_date, sample_datetime, sample_time):
def _test_bad_variables(type_, input_):
result = schema.execute(
@ -185,8 +185,6 @@ def test_bad_variables(sample_date, sample_datetime, sample_time):
),
variables={"input": input_},
)
# when `input` is not JSON serializable formatting the error message in
# `graphql.utils.is_valid_value` line 79 fails with a TypeError
assert isinstance(result.errors, list)
assert len(result.errors) == 1
assert isinstance(result.errors[0], GraphQLError)
@ -205,7 +203,6 @@ def test_bad_variables(sample_date, sample_datetime, sample_time):
("DateTime", time),
("Date", not_a_date),
("Date", not_a_date_str),
("Date", now),
("Date", time),
("Time", not_a_date),
("Time", not_a_date_str),

View File

@ -1,5 +1,6 @@
from pytest import raises
from graphql.type import GraphQLObjectType, GraphQLSchema
from graphql.pyutils import dedent
from ..field import Field
@ -17,8 +18,13 @@ class Query(ObjectType):
def test_schema():
schema = Schema(Query).graphql_schema
assert schema.query_type == schema.get_graphql_type(Query)
schema = Schema(Query)
graphql_schema = schema.graphql_schema
assert isinstance(graphql_schema, GraphQLSchema)
query_type = graphql_schema.query_type
assert isinstance(query_type, GraphQLObjectType)
assert query_type.name == "Query"
assert query_type.graphene_type is Query
def test_schema_get_type():
@ -39,13 +45,13 @@ def test_schema_str():
schema = Schema(Query)
assert str(schema) == dedent(
"""
type MyOtherType {
field: String
}
type Query {
inner: MyOtherType
}
type MyOtherType {
field: String
}
"""
)

View File

@ -1,5 +1,3 @@
from pytest import raises
from graphql.type import (
GraphQLArgument,
GraphQLEnumType,
@ -21,13 +19,13 @@ from ..interface import Interface
from ..objecttype import ObjectType
from ..scalars import Int, String
from ..structures import List, NonNull
from ..schema import GrapheneGraphQLSchema, resolve_type
from ..schema import Schema
def create_type_map(types, auto_camelcase=True):
query = GraphQLObjectType("Query", {})
schema = GrapheneGraphQLSchema(query, types=types, auto_camelcase=auto_camelcase)
return schema.type_map
query = type("Query", (ObjectType,), {})
schema = Schema(query, types=types, auto_camelcase=auto_camelcase)
return schema.graphql_schema.type_map
def test_enum():
@ -272,20 +270,3 @@ def test_objecttype_with_possible_types():
assert graphql_type.is_type_of
assert graphql_type.is_type_of({}, None) is True
assert graphql_type.is_type_of(MyObjectType(), None) is False
def test_resolve_type_with_missing_type():
class MyObjectType(ObjectType):
foo_bar = String()
class MyOtherObjectType(ObjectType):
fizz_buzz = String()
def resolve_type_func(root, info):
return MyOtherObjectType
type_map = create_type_map([MyObjectType])
with raises(AssertionError) as excinfo:
resolve_type(resolve_type_func, type_map, "MyOtherObjectType", {}, {}, None)
assert "MyOtherObjectTyp" in str(excinfo.value)

View File

@ -82,7 +82,7 @@ setup(
keywords="api graphql protocol rest relay graphene",
packages=find_packages(exclude=["tests", "tests.*", "examples"]),
install_requires=[
"graphql-core>=3.0.3,<3.1",
"graphql-core>=3.1.0b1,<4",
"graphql-relay>=3.0,<4",
"aniso8601>=8,<9",
"unidecode>=1.1.1,<2",