mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-02 12:44:15 +03:00
Improved tests and coverage
This commit is contained in:
parent
b474010060
commit
6f87720fc1
|
@ -14,7 +14,7 @@ Episode = graphene.Enum('Episode', dict(
|
||||||
class Character(graphene.Interface):
|
class Character(graphene.Interface):
|
||||||
id = graphene.IDField()
|
id = graphene.IDField()
|
||||||
name = graphene.StringField()
|
name = graphene.StringField()
|
||||||
friends = graphene.ListField('self')
|
friends = graphene.ListField('Character')
|
||||||
appears_in = graphene.ListField(Episode)
|
appears_in = graphene.ListField(Episode)
|
||||||
|
|
||||||
def resolve_friends(self, args, *_):
|
def resolve_friends(self, args, *_):
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
from graphql.core.type import (
|
from graphql.core.type import (
|
||||||
GraphQLEnumType as Enum,
|
GraphQLEnumType as Enum
|
||||||
GraphQLArgument as Argument,
|
|
||||||
GraphQLString as String,
|
|
||||||
GraphQLInt as Int,
|
|
||||||
GraphQLID as ID
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from graphene import signals
|
from graphene import signals
|
||||||
|
@ -16,6 +12,19 @@ from graphene.core.types import (
|
||||||
ObjectType,
|
ObjectType,
|
||||||
Interface,
|
Interface,
|
||||||
Mutation,
|
Mutation,
|
||||||
|
BaseType,
|
||||||
|
LazyType,
|
||||||
|
OrderedType,
|
||||||
|
Argument,
|
||||||
|
Field,
|
||||||
|
InputField,
|
||||||
|
String,
|
||||||
|
Int,
|
||||||
|
Boolean,
|
||||||
|
ID,
|
||||||
|
Float,
|
||||||
|
List,
|
||||||
|
NonNull
|
||||||
)
|
)
|
||||||
|
|
||||||
from graphene.core.fields import (
|
from graphene.core.fields import (
|
||||||
|
|
|
@ -1,14 +1,26 @@
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
from .types.base import FieldType
|
||||||
from .types.field import Field
|
from .types.field import Field
|
||||||
from .types.scalars import String, Int, Boolean, ID, Float
|
from .types.scalars import String, Int, Boolean, ID, Float
|
||||||
from .types.definitions import List, NonNull
|
from .types.definitions import List, NonNull
|
||||||
|
|
||||||
|
|
||||||
class DeprecatedField(object):
|
class DeprecatedField(FieldType):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
print("Using {} is not longer supported".format(self.__class__.__name__))
|
cls = self.__class__
|
||||||
|
warnings.warn("Using {} is not longer supported".format(cls.__name__)
|
||||||
|
, FutureWarning)
|
||||||
kwargs['resolver'] = kwargs.pop('resolve', None)
|
kwargs['resolver'] = kwargs.pop('resolve', None)
|
||||||
|
self.required = kwargs.pop('required', False)
|
||||||
return super(DeprecatedField, self).__init__(*args, **kwargs)
|
return super(DeprecatedField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def as_field(self):
|
||||||
|
t = self
|
||||||
|
if self.required:
|
||||||
|
t = NonNull(t)
|
||||||
|
return Field(t, _creation_counter=self.creation_counter, *self.args, **self.kwargs)
|
||||||
|
|
||||||
|
|
||||||
class StringField(DeprecatedField, String):
|
class StringField(DeprecatedField, String):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -44,6 +44,8 @@ class Schema(object):
|
||||||
if name:
|
if name:
|
||||||
self._types_names[name] = object_type
|
self._types_names[name] = object_type
|
||||||
return self._types[object_type]
|
return self._types[object_type]
|
||||||
|
else:
|
||||||
|
return object_type
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def query(self):
|
def query(self):
|
||||||
|
@ -83,7 +85,7 @@ class Schema(object):
|
||||||
return object_type
|
return object_type
|
||||||
|
|
||||||
def get_type(self, type_name):
|
def get_type(self, type_name):
|
||||||
self.schema._build_type_map()
|
# self.schema._build_type_map()
|
||||||
if type_name not in self._types_names:
|
if type_name not in self._types_names:
|
||||||
raise Exception('Type %s not found in %r' % (type_name, self))
|
raise Exception('Type %s not found in %r' % (type_name, self))
|
||||||
return self._types_names[type_name]
|
return self._types_names[type_name]
|
||||||
|
|
154
graphene/core/tests/test_fields.py
Normal file
154
graphene/core/tests/test_fields.py
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
|
||||||
|
from py.test import raises
|
||||||
|
from pytest import raises
|
||||||
|
|
||||||
|
from graphene.core.fields import Field, NonNullField, StringField
|
||||||
|
from graphene.core.options import Options
|
||||||
|
from graphene.core.schema import Schema
|
||||||
|
from graphene.core.types import ObjectType
|
||||||
|
from graphql.core.type import (GraphQLBoolean, GraphQLField, GraphQLID,
|
||||||
|
GraphQLInt, GraphQLNonNull, GraphQLString)
|
||||||
|
|
||||||
|
|
||||||
|
class ot(ObjectType):
|
||||||
|
def resolve_customdoc(self, *args, **kwargs):
|
||||||
|
'''Resolver documentation'''
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "ObjectType"
|
||||||
|
|
||||||
|
schema = Schema()
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_no_contributed_raises_error():
|
||||||
|
f = Field(GraphQLString)
|
||||||
|
with raises(Exception) as excinfo:
|
||||||
|
schema.T(f)
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_type():
|
||||||
|
f = Field(GraphQLString)
|
||||||
|
f.contribute_to_class(ot, 'field_name')
|
||||||
|
assert isinstance(schema.T(f), GraphQLField)
|
||||||
|
assert schema.T(f).type == GraphQLString
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_name_automatic_camelcase():
|
||||||
|
f = Field(GraphQLString)
|
||||||
|
f.contribute_to_class(ot, 'field_name')
|
||||||
|
assert f.name == 'fieldName'
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_name_use_name_if_exists():
|
||||||
|
f = Field(GraphQLString, name='my_custom_name')
|
||||||
|
f.contribute_to_class(ot, 'field_name')
|
||||||
|
assert f.name == 'my_custom_name'
|
||||||
|
|
||||||
|
|
||||||
|
def test_stringfield_type():
|
||||||
|
f = StringField()
|
||||||
|
f.contribute_to_class(ot, 'field_name')
|
||||||
|
assert schema.T(f) == GraphQLString
|
||||||
|
|
||||||
|
|
||||||
|
def test_nonnullfield_type():
|
||||||
|
f = NonNullField(StringField())
|
||||||
|
f.contribute_to_class(ot, 'field_name')
|
||||||
|
assert isinstance(schema.T(f), GraphQLNonNull)
|
||||||
|
|
||||||
|
|
||||||
|
def test_stringfield_type_required():
|
||||||
|
f = StringField(required=True).as_field()
|
||||||
|
f.contribute_to_class(ot, 'field_name')
|
||||||
|
assert isinstance(schema.T(f), GraphQLField)
|
||||||
|
assert isinstance(schema.T(f).type, GraphQLNonNull)
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_resolve():
|
||||||
|
f = StringField(required=True, resolve=lambda *args: 'RESOLVED').as_field()
|
||||||
|
f.contribute_to_class(ot, 'field_name')
|
||||||
|
field_type = schema.T(f)
|
||||||
|
assert 'RESOLVED' == field_type.resolver(ot, None, None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_resolve_type_custom():
|
||||||
|
class MyCustomType(ObjectType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
f = Field('MyCustomType')
|
||||||
|
|
||||||
|
class OtherType(ObjectType):
|
||||||
|
field_name = f
|
||||||
|
|
||||||
|
s = Schema()
|
||||||
|
s.query = OtherType
|
||||||
|
s.register(MyCustomType)
|
||||||
|
|
||||||
|
assert s.T(f).type == s.T(MyCustomType)
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_orders():
|
||||||
|
f1 = Field(None)
|
||||||
|
f2 = Field(None)
|
||||||
|
assert f1 < f2
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_orders_wrong_type():
|
||||||
|
field = Field(None)
|
||||||
|
try:
|
||||||
|
assert not field < 1
|
||||||
|
except TypeError:
|
||||||
|
# Fix exception raising in Python3+
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_eq():
|
||||||
|
f1 = Field(None)
|
||||||
|
f2 = Field(None)
|
||||||
|
assert f1 != f2
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_eq_wrong_type():
|
||||||
|
field = Field(None)
|
||||||
|
assert field != 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_hash():
|
||||||
|
f1 = Field(None)
|
||||||
|
f2 = Field(None)
|
||||||
|
assert hash(f1) != hash(f2)
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_none_type_raises_error():
|
||||||
|
s = Schema()
|
||||||
|
f = Field(None)
|
||||||
|
f.contribute_to_class(ot, 'field_name')
|
||||||
|
with raises(Exception) as excinfo:
|
||||||
|
s.T(f)
|
||||||
|
assert str(
|
||||||
|
excinfo.value) == "Internal type for field ot.field_name is None"
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_str():
|
||||||
|
f = StringField().as_field()
|
||||||
|
f.contribute_to_class(ot, 'field_name')
|
||||||
|
assert str(f) == "ot.field_name"
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_repr():
|
||||||
|
f = StringField().as_field()
|
||||||
|
assert repr(f) == "<graphene.core.types.field.Field>"
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_repr_contributed():
|
||||||
|
f = StringField().as_field()
|
||||||
|
f.contribute_to_class(ot, 'field_name')
|
||||||
|
assert repr(f) == "<graphene.core.types.field.Field: field_name>"
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_resolve_objecttype_cos():
|
||||||
|
f = StringField().as_field()
|
||||||
|
f.contribute_to_class(ot, 'customdoc')
|
||||||
|
field = schema.T(f)
|
||||||
|
assert field.description == 'Resolver documentation'
|
157
graphene/core/tests/test_schema.py
Normal file
157
graphene/core/tests/test_schema.py
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
|
||||||
|
from py.test import raises
|
||||||
|
from pytest import raises
|
||||||
|
|
||||||
|
from graphene import Interface, ObjectType, Schema
|
||||||
|
from graphene.core.fields import Field, ListField, StringField
|
||||||
|
from graphene.core.types.base import LazyType
|
||||||
|
from graphql.core import graphql
|
||||||
|
from graphql.core.type import (GraphQLInterfaceType, GraphQLObjectType,
|
||||||
|
GraphQLSchema)
|
||||||
|
from tests.utils import assert_equal_lists
|
||||||
|
|
||||||
|
schema = Schema(name='My own schema')
|
||||||
|
|
||||||
|
|
||||||
|
class Character(Interface):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
|
||||||
|
class Pet(ObjectType):
|
||||||
|
type = StringField(resolve=lambda *_: 'Dog')
|
||||||
|
|
||||||
|
|
||||||
|
class Human(Character):
|
||||||
|
friends = ListField(Character)
|
||||||
|
pet = Field(Pet)
|
||||||
|
|
||||||
|
def resolve_name(self, *args):
|
||||||
|
return 'Peter'
|
||||||
|
|
||||||
|
def resolve_friend(self, *args):
|
||||||
|
return Human(object())
|
||||||
|
|
||||||
|
def resolve_pet(self, *args):
|
||||||
|
return Pet(object())
|
||||||
|
|
||||||
|
schema.query = Human
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_registered_type():
|
||||||
|
assert schema.get_type('Character') == Character
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_unregistered_type():
|
||||||
|
with raises(Exception) as excinfo:
|
||||||
|
schema.get_type('NON_EXISTENT_MODEL')
|
||||||
|
assert 'not found' in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_schema_query():
|
||||||
|
assert schema.query == Human
|
||||||
|
|
||||||
|
|
||||||
|
def test_query_schema_graphql():
|
||||||
|
object()
|
||||||
|
query = '''
|
||||||
|
{
|
||||||
|
name
|
||||||
|
pet {
|
||||||
|
type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
expected = {
|
||||||
|
'name': 'Peter',
|
||||||
|
'pet': {
|
||||||
|
'type': 'Dog'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = graphql(schema.schema, query, root=Human(object()))
|
||||||
|
assert not result.errors
|
||||||
|
assert result.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_query_schema_execute():
|
||||||
|
object()
|
||||||
|
query = '''
|
||||||
|
{
|
||||||
|
name
|
||||||
|
pet {
|
||||||
|
type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
expected = {
|
||||||
|
'name': 'Peter',
|
||||||
|
'pet': {
|
||||||
|
'type': 'Dog'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = schema.execute(query, root=object())
|
||||||
|
assert not result.errors
|
||||||
|
assert result.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_schema_get_type_map():
|
||||||
|
assert_equal_lists(
|
||||||
|
schema.schema.get_type_map().keys(),
|
||||||
|
['__Field', 'String', 'Pet', 'Character', '__InputValue', '__Directive',
|
||||||
|
'__TypeKind', '__Schema', '__Type', 'Human', '__EnumValue', 'Boolean']
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_schema_no_query():
|
||||||
|
schema = Schema(name='My own schema')
|
||||||
|
with raises(Exception) as excinfo:
|
||||||
|
schema.schema
|
||||||
|
assert 'define a base query type' in str(excinfo)
|
||||||
|
|
||||||
|
|
||||||
|
def test_schema_register():
|
||||||
|
schema = Schema(name='My own schema')
|
||||||
|
|
||||||
|
@schema.register
|
||||||
|
class MyType(ObjectType):
|
||||||
|
type = StringField(resolve=lambda *_: 'Dog')
|
||||||
|
|
||||||
|
schema.query = MyType
|
||||||
|
|
||||||
|
assert schema.get_type('MyType') == MyType
|
||||||
|
|
||||||
|
|
||||||
|
def test_schema_register():
|
||||||
|
schema = Schema(name='My own schema')
|
||||||
|
|
||||||
|
@schema.register
|
||||||
|
class MyType(ObjectType):
|
||||||
|
type = StringField(resolve=lambda *_: 'Dog')
|
||||||
|
|
||||||
|
with raises(Exception) as excinfo:
|
||||||
|
schema.get_type('MyType')
|
||||||
|
assert 'base query type' in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_schema_introspect():
|
||||||
|
schema = Schema(name='My own schema')
|
||||||
|
|
||||||
|
class MyType(ObjectType):
|
||||||
|
type = StringField(resolve=lambda *_: 'Dog')
|
||||||
|
|
||||||
|
schema.query = MyType
|
||||||
|
|
||||||
|
introspection = schema.introspect()
|
||||||
|
assert '__schema' in introspection
|
||||||
|
|
||||||
|
|
||||||
|
def test_lazytype():
|
||||||
|
schema = Schema(name='My own schema')
|
||||||
|
|
||||||
|
t = LazyType('MyType')
|
||||||
|
|
||||||
|
class MyType(ObjectType):
|
||||||
|
type = StringField(resolve=lambda *_: 'Dog')
|
||||||
|
|
||||||
|
schema.query = MyType
|
||||||
|
|
||||||
|
assert schema.T(t) == schema.T(MyType)
|
|
@ -1 +1,6 @@
|
||||||
from .objecttype import ObjectTypeMeta, BaseObjectType, ObjectType, Interface, Mutation, InputObjectType
|
from .objecttype import ObjectTypeMeta, BaseObjectType, ObjectType, Interface, Mutation, InputObjectType
|
||||||
|
from .base import BaseType, LazyType, OrderedType
|
||||||
|
from .argument import Argument
|
||||||
|
from .field import Field, InputField
|
||||||
|
from .scalars import String, Int, Boolean, ID, Float
|
||||||
|
from .definitions import List, NonNull
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
import six
|
||||||
from graphql.core.type import (GraphQLList, GraphQLNonNull)
|
from graphql.core.type import (GraphQLList, GraphQLNonNull)
|
||||||
|
|
||||||
from .base import MountedType
|
from .base import MountedType, LazyType
|
||||||
|
|
||||||
|
|
||||||
class OfType(MountedType):
|
class OfType(MountedType):
|
||||||
def __init__(self, of_type, *args, **kwargs):
|
def __init__(self, of_type, *args, **kwargs):
|
||||||
|
if isinstance(of_type, six.string_types) and of_type != 'self':
|
||||||
|
of_type = LazyType(of_type)
|
||||||
self.of_type = of_type
|
self.of_type = of_type
|
||||||
super(OfType, self).__init__(*args, **kwargs)
|
super(OfType, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -55,14 +55,20 @@ class Field(OrderedType):
|
||||||
def custom_resolve_fn(instance, args, info):
|
def custom_resolve_fn(instance, args, info):
|
||||||
return resolve_fn(instance, args, info)
|
return resolve_fn(instance, args, info)
|
||||||
return custom_resolve_fn
|
return custom_resolve_fn
|
||||||
|
|
||||||
|
def default_getter(instance, args, info):
|
||||||
|
return getattr(instance, self.attname, None)
|
||||||
|
|
||||||
|
return default_getter
|
||||||
|
|
||||||
def internal_type(self, schema):
|
def internal_type(self, schema):
|
||||||
resolver = self.resolver
|
resolver = self.resolver
|
||||||
description = self.description
|
description = self.description
|
||||||
if not description and resolver:
|
if not description and resolver:
|
||||||
description = resolver.__doc__
|
description = resolver.__doc__
|
||||||
|
type = schema.T(self.type)
|
||||||
return GraphQLField(schema.T(self.type), args=self.get_arguments(schema), resolver=resolver,
|
assert type, 'Internal type for field %s is None' % str(self)
|
||||||
|
return GraphQLField(type, args=self.get_arguments(schema), resolver=resolver,
|
||||||
description=description,)
|
description=description,)
|
||||||
|
|
||||||
def get_arguments(self, schema):
|
def get_arguments(self, schema):
|
||||||
|
@ -88,6 +94,10 @@ class Field(OrderedType):
|
||||||
return '<%s: %s>' % (path, name)
|
return '<%s: %s>' % (path, name)
|
||||||
return '<%s>' % path
|
return '<%s>' % path
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" Return "object_type.field_name". """
|
||||||
|
return '%s.%s' % (self.object_type.__name__, self.attname)
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash((self.creation_counter, self.object_type))
|
return hash((self.creation_counter, self.object_type))
|
||||||
|
|
||||||
|
|
|
@ -49,20 +49,20 @@ def test_field_name_use_name_if_exists():
|
||||||
def test_stringfield_type():
|
def test_stringfield_type():
|
||||||
f = StringField()
|
f = StringField()
|
||||||
f.contribute_to_class(ot, 'field_name')
|
f.contribute_to_class(ot, 'field_name')
|
||||||
assert f.internal_type(schema) == GraphQLString
|
assert schema.T(f) == GraphQLString
|
||||||
|
|
||||||
|
|
||||||
def test_nonnullfield_type():
|
def test_nonnullfield_type():
|
||||||
f = NonNullField(StringField())
|
f = NonNullField(StringField())
|
||||||
f.contribute_to_class(ot, 'field_name')
|
f.contribute_to_class(ot, 'field_name')
|
||||||
assert isinstance(f.internal_type(schema), GraphQLNonNull)
|
assert isinstance(schema.T(f), GraphQLNonNull)
|
||||||
|
|
||||||
|
|
||||||
def test_stringfield_type_required():
|
def test_stringfield_type_required():
|
||||||
f = StringField(required=True)
|
f = Field(StringField(required=True))
|
||||||
f.contribute_to_class(ot, 'field_name')
|
f.contribute_to_class(ot, 'field_name')
|
||||||
assert isinstance(f.internal_field(schema), GraphQLField)
|
assert isinstance(schema.T(f), GraphQLField)
|
||||||
assert isinstance(f.internal_type(schema), GraphQLNonNull)
|
assert isinstance(schema.T(f).type, GraphQLNonNull)
|
||||||
|
|
||||||
|
|
||||||
def test_field_resolve():
|
def test_field_resolve():
|
||||||
|
|
Loading…
Reference in New Issue
Block a user