mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-02 12:44:15 +03:00
Improved classtypes core support
This commit is contained in:
parent
398f7da24c
commit
8abcaff02b
|
@ -8,11 +8,15 @@ from graphene.core.schema import (
|
|||
Schema
|
||||
)
|
||||
|
||||
from graphene.core.types import (
|
||||
from graphene.core.classtypes import (
|
||||
ObjectType,
|
||||
InputObjectType,
|
||||
Interface,
|
||||
Mutation,
|
||||
Scalar
|
||||
)
|
||||
|
||||
from graphene.core.types import (
|
||||
BaseType,
|
||||
LazyType,
|
||||
Argument,
|
||||
|
@ -59,6 +63,7 @@ __all__ = [
|
|||
'InputObjectType',
|
||||
'Interface',
|
||||
'Mutation',
|
||||
'Scalar',
|
||||
'Field',
|
||||
'InputField',
|
||||
'StringField',
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
from .inputobjecttype import InputObjectType
|
||||
from .interface import Interface
|
||||
from .mutation import Mutation
|
||||
from .objecttype import ObjectType
|
||||
from .options import Options
|
||||
from .scalar import Scalar
|
||||
from .uniontype import UnionType
|
||||
|
||||
__all__ = [
|
||||
'InputObjectType',
|
||||
'Interface',
|
||||
'Mutation',
|
||||
'ObjectType',
|
||||
'Options',
|
||||
'Scalar',
|
||||
'UnionType']
|
|
@ -1,72 +0,0 @@
|
|||
from collections import OrderedDict
|
||||
|
||||
from ..utils import cached_property
|
||||
|
||||
DEFAULT_NAMES = ('description', 'name', 'is_interface', 'is_mutation',
|
||||
'type_name', 'interfaces', 'abstract')
|
||||
|
||||
|
||||
class Options(object):
|
||||
|
||||
def __init__(self, meta=None):
|
||||
self.meta = meta
|
||||
self.local_fields = []
|
||||
self.is_interface = False
|
||||
self.is_mutation = False
|
||||
self.is_union = False
|
||||
self.abstract = False
|
||||
self.interfaces = []
|
||||
self.parents = []
|
||||
self.types = []
|
||||
self.valid_attrs = DEFAULT_NAMES
|
||||
|
||||
def contribute_to_class(self, cls, name):
|
||||
cls._meta = self
|
||||
self.parent = cls
|
||||
# First, construct the default values for these options.
|
||||
self.object_name = cls.__name__
|
||||
self.type_name = self.object_name
|
||||
|
||||
self.description = cls.__doc__
|
||||
# Store the original user-defined values for each option,
|
||||
# for use when serializing the model definition
|
||||
self.original_attrs = {}
|
||||
|
||||
# Next, apply any overridden values from 'class Meta'.
|
||||
if self.meta:
|
||||
meta_attrs = self.meta.__dict__.copy()
|
||||
for name in self.meta.__dict__:
|
||||
# Ignore any private attributes that Django doesn't care about.
|
||||
# NOTE: We can't modify a dictionary's contents while looping
|
||||
# over it, so we loop over the *original* dictionary instead.
|
||||
if name.startswith('_'):
|
||||
del meta_attrs[name]
|
||||
for attr_name in self.valid_attrs:
|
||||
if attr_name in meta_attrs:
|
||||
setattr(self, attr_name, meta_attrs.pop(attr_name))
|
||||
self.original_attrs[attr_name] = getattr(self, attr_name)
|
||||
elif hasattr(self.meta, attr_name):
|
||||
setattr(self, attr_name, getattr(self.meta, attr_name))
|
||||
self.original_attrs[attr_name] = getattr(self, attr_name)
|
||||
|
||||
del self.valid_attrs
|
||||
|
||||
# Any leftover attributes must be invalid.
|
||||
if meta_attrs != {}:
|
||||
raise TypeError(
|
||||
"'class Meta' got invalid attribute(s): %s" %
|
||||
','.join(
|
||||
meta_attrs.keys()))
|
||||
|
||||
del self.meta
|
||||
|
||||
def add_field(self, field):
|
||||
self.local_fields.append(field)
|
||||
|
||||
@cached_property
|
||||
def fields(self):
|
||||
return sorted(self.local_fields)
|
||||
|
||||
@cached_property
|
||||
def fields_map(self):
|
||||
return OrderedDict([(f.attname, f) for f in self.fields])
|
|
@ -11,7 +11,6 @@ from graphql.core.utils.schema_printer import print_schema
|
|||
from graphene import signals
|
||||
|
||||
from .types.base import BaseType
|
||||
from .types.objecttype import BaseObjectType
|
||||
from .classtypes.base import ClassType
|
||||
|
||||
|
||||
|
@ -49,7 +48,7 @@ class Schema(object):
|
|||
internal_type = object_type.internal_type(self)
|
||||
self._types[object_type] = internal_type
|
||||
is_objecttype = inspect.isclass(
|
||||
object_type) and issubclass(object_type, BaseObjectType)
|
||||
object_type) and issubclass(object_type, ClassType)
|
||||
if is_objecttype:
|
||||
self.register(object_type)
|
||||
return self._types[object_type]
|
||||
|
@ -91,7 +90,7 @@ class Schema(object):
|
|||
if name:
|
||||
objecttype = self._types_names.get(name, None)
|
||||
if objecttype and inspect.isclass(
|
||||
objecttype) and issubclass(objecttype, BaseObjectType):
|
||||
objecttype) and issubclass(objecttype, ClassType):
|
||||
return objecttype
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
from .base import BaseType, LazyType, OrderedType
|
||||
from .argument import Argument, ArgumentsGroup, to_arguments
|
||||
from .definitions import List, NonNull
|
||||
from .objecttype import ObjectTypeMeta, BaseObjectType, Interface, ObjectType, Mutation, InputObjectType
|
||||
# Compatibility import
|
||||
from .objecttype import Interface, ObjectType, Mutation, InputObjectType
|
||||
|
||||
from .scalars import String, ID, Boolean, Int, Float, Scalar
|
||||
from .field import Field, InputField
|
||||
|
||||
|
@ -17,8 +19,6 @@ __all__ = [
|
|||
'Field',
|
||||
'InputField',
|
||||
'Interface',
|
||||
'BaseObjectType',
|
||||
'ObjectTypeMeta',
|
||||
'ObjectType',
|
||||
'Mutation',
|
||||
'InputObjectType',
|
||||
|
|
|
@ -2,9 +2,6 @@ from functools import total_ordering
|
|||
|
||||
import six
|
||||
|
||||
from ..classtypes.base import FieldsClassType
|
||||
from ..classtypes.inputobjecttype import InputObjectType as NewInputObjectType
|
||||
|
||||
|
||||
class BaseType(object):
|
||||
|
||||
|
@ -107,11 +104,12 @@ class ArgumentType(MirroredType):
|
|||
class FieldType(MirroredType):
|
||||
|
||||
def contribute_to_class(self, cls, name):
|
||||
from ..types import BaseObjectType, InputObjectType
|
||||
if issubclass(cls, (InputObjectType, NewInputObjectType)):
|
||||
from ..classtypes.base import FieldsClassType
|
||||
from ..classtypes.inputobjecttype import InputObjectType
|
||||
if issubclass(cls, (InputObjectType)):
|
||||
inputfield = self.as_inputfield()
|
||||
return inputfield.contribute_to_class(cls, name)
|
||||
elif issubclass(cls, (BaseObjectType, FieldsClassType)):
|
||||
elif issubclass(cls, (FieldsClassType)):
|
||||
field = self.as_field()
|
||||
return field.contribute_to_class(cls, name)
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ from graphql.core.type import GraphQLField, GraphQLInputObjectField
|
|||
|
||||
from ...utils import to_camel_case
|
||||
from ..classtypes.base import FieldsClassType
|
||||
from ..classtypes.inputobjecttype import InputObjectType as NewInputObjectType
|
||||
from ..types import BaseObjectType, InputObjectType
|
||||
from ..classtypes.mutation import Mutation
|
||||
from ..classtypes.inputobjecttype import InputObjectType
|
||||
from .argument import ArgumentsGroup, snake_case_args
|
||||
from .base import LazyType, MountType, OrderedType
|
||||
from .definitions import NonNull
|
||||
|
@ -34,7 +34,7 @@ class Field(OrderedType):
|
|||
|
||||
def contribute_to_class(self, cls, attname):
|
||||
assert issubclass(
|
||||
cls, (BaseObjectType, FieldsClassType)), 'Field {} cannot be mounted in {}'.format(
|
||||
cls, (FieldsClassType)), 'Field {} cannot be mounted in {}'.format(
|
||||
self, cls)
|
||||
if not self.name:
|
||||
self.name = to_camel_case(attname)
|
||||
|
@ -71,7 +71,7 @@ class Field(OrderedType):
|
|||
description = resolver.__doc__
|
||||
type = schema.T(self.get_type(schema))
|
||||
type_objecttype = schema.objecttype(type)
|
||||
if type_objecttype and type_objecttype._meta.is_mutation:
|
||||
if type_objecttype and issubclass(type_objecttype, Mutation):
|
||||
assert len(arguments) == 0
|
||||
arguments = type_objecttype.get_arguments()
|
||||
resolver = getattr(type_objecttype, 'mutate')
|
||||
|
@ -128,7 +128,7 @@ class InputField(OrderedType):
|
|||
|
||||
def contribute_to_class(self, cls, attname):
|
||||
assert issubclass(
|
||||
cls, (InputObjectType, NewInputObjectType)), 'InputField {} cannot be mounted in {}'.format(
|
||||
cls, (InputObjectType)), 'InputField {} cannot be mounted in {}'.format(
|
||||
self, cls)
|
||||
if not self.name:
|
||||
self.name = to_camel_case(attname)
|
||||
|
|
|
@ -1,282 +1,3 @@
|
|||
import copy
|
||||
import inspect
|
||||
from collections import OrderedDict
|
||||
from functools import partial
|
||||
from ..classtypes import ObjectType, Interface, Mutation, InputObjectType
|
||||
|
||||
import six
|
||||
from graphql.core.type import (GraphQLInputObjectType, GraphQLInterfaceType,
|
||||
GraphQLObjectType, GraphQLUnionType)
|
||||
|
||||
from graphene import signals
|
||||
|
||||
from ..exceptions import SkipField
|
||||
from ..options import Options
|
||||
from .argument import ArgumentsGroup
|
||||
from .base import BaseType
|
||||
from .definitions import List, NonNull
|
||||
|
||||
|
||||
def is_objecttype(cls):
|
||||
if not issubclass(cls, BaseObjectType):
|
||||
return False
|
||||
_meta = getattr(cls, '_meta', None)
|
||||
return not(_meta and (_meta.abstract or _meta.is_interface))
|
||||
|
||||
|
||||
class ObjectTypeMeta(type):
|
||||
options_cls = Options
|
||||
|
||||
def is_interface(cls, parents):
|
||||
return Interface in parents
|
||||
|
||||
def is_mutation(cls, parents):
|
||||
return issubclass(cls, Mutation)
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
super_new = super(ObjectTypeMeta, cls).__new__
|
||||
parents = [b for b in bases if isinstance(b, cls)]
|
||||
if not parents:
|
||||
# If this isn't a subclass of Model, don't do anything special.
|
||||
return super_new(cls, name, bases, attrs)
|
||||
|
||||
module = attrs.pop('__module__', None)
|
||||
doc = attrs.pop('__doc__', None)
|
||||
new_class = super_new(cls, name, bases, {
|
||||
'__module__': module,
|
||||
'__doc__': doc
|
||||
})
|
||||
attr_meta = attrs.pop('Meta', None)
|
||||
abstract = getattr(attr_meta, 'abstract', False)
|
||||
if not attr_meta:
|
||||
meta = getattr(new_class, 'Meta', None)
|
||||
else:
|
||||
meta = attr_meta
|
||||
|
||||
base_meta = getattr(new_class, '_meta', None)
|
||||
|
||||
new_class.add_to_class('_meta', new_class.options_cls(meta))
|
||||
|
||||
new_class._meta.is_interface = new_class.is_interface(parents)
|
||||
new_class._meta.is_mutation = new_class.is_mutation(parents) or (base_meta and base_meta.is_mutation)
|
||||
union_types = list(filter(is_objecttype, parents))
|
||||
|
||||
new_class._meta.is_union = len(union_types) > 1
|
||||
new_class._meta.types = union_types
|
||||
|
||||
assert not (
|
||||
new_class._meta.is_interface and new_class._meta.is_mutation)
|
||||
|
||||
assert not (
|
||||
new_class._meta.is_interface and new_class._meta.is_union)
|
||||
|
||||
# Add all attributes to the class.
|
||||
for obj_name, obj in attrs.items():
|
||||
new_class.add_to_class(obj_name, obj)
|
||||
|
||||
if abstract:
|
||||
new_class._prepare()
|
||||
return new_class
|
||||
|
||||
if new_class._meta.is_mutation:
|
||||
assert hasattr(
|
||||
new_class, 'mutate'), "All mutations must implement mutate method"
|
||||
|
||||
new_class.add_extra_fields()
|
||||
|
||||
new_fields = new_class._meta.local_fields
|
||||
assert not(new_class._meta.is_union and new_fields), 'An union cannot have extra fields'
|
||||
|
||||
field_names = {f.name: f for f in new_fields}
|
||||
|
||||
for base in parents:
|
||||
if not hasattr(base, '_meta'):
|
||||
# Things without _meta aren't functional models, so they're
|
||||
# uninteresting parents.
|
||||
continue
|
||||
# if base._meta.schema != new_class._meta.schema:
|
||||
# raise Exception('The parent schema is not the same')
|
||||
|
||||
parent_fields = base._meta.local_fields
|
||||
# Check for clashes between locally declared fields and those
|
||||
# on the base classes (we cannot handle shadowed fields at the
|
||||
# moment).
|
||||
for field in parent_fields:
|
||||
if field.name in field_names and field.type.__class__ != field_names[
|
||||
field.name].type.__class__:
|
||||
raise Exception(
|
||||
'Local field %r in class %r (%r) clashes '
|
||||
'with field with similar name from '
|
||||
'Interface %s (%r)' % (
|
||||
field.name,
|
||||
new_class.__name__,
|
||||
field.__class__,
|
||||
base.__name__,
|
||||
field_names[field.name].__class__)
|
||||
)
|
||||
new_field = copy.copy(field)
|
||||
new_class.add_to_class(field.attname, new_field)
|
||||
|
||||
new_class._meta.parents.append(base)
|
||||
if base._meta.is_interface:
|
||||
new_class._meta.interfaces.append(base)
|
||||
# new_class._meta.parents.extend(base._meta.parents)
|
||||
|
||||
setattr(new_class, 'NonNull', NonNull(new_class))
|
||||
setattr(new_class, 'List', List(new_class))
|
||||
|
||||
new_class._prepare()
|
||||
return new_class
|
||||
|
||||
def add_extra_fields(cls):
|
||||
pass
|
||||
|
||||
def _prepare(cls):
|
||||
if hasattr(cls, '_prepare_class'):
|
||||
cls._prepare_class()
|
||||
signals.class_prepared.send(cls)
|
||||
|
||||
def add_to_class(cls, name, value):
|
||||
# We should call the contribute_to_class method only if it's bound
|
||||
if not inspect.isclass(value) and hasattr(
|
||||
value, 'contribute_to_class'):
|
||||
value.contribute_to_class(cls, name)
|
||||
else:
|
||||
setattr(cls, name, value)
|
||||
|
||||
|
||||
class BaseObjectType(BaseType):
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls._meta.is_interface:
|
||||
raise Exception("An interface cannot be initialized")
|
||||
elif cls._meta.is_union:
|
||||
raise Exception("An union cannot be initialized")
|
||||
elif cls._meta.abstract:
|
||||
raise Exception("An abstract ObjectType cannot be initialized")
|
||||
return super(BaseObjectType, cls).__new__(cls)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
signals.pre_init.send(self.__class__, args=args, kwargs=kwargs)
|
||||
self._root = kwargs.pop('_root', None)
|
||||
args_len = len(args)
|
||||
fields = self._meta.fields
|
||||
if args_len > len(fields):
|
||||
# Daft, but matches old exception sans the err msg.
|
||||
raise IndexError("Number of args exceeds number of fields")
|
||||
fields_iter = iter(fields)
|
||||
|
||||
if not kwargs:
|
||||
for val, field in zip(args, fields_iter):
|
||||
setattr(self, field.attname, val)
|
||||
else:
|
||||
for val, field in zip(args, fields_iter):
|
||||
setattr(self, field.attname, val)
|
||||
kwargs.pop(field.attname, None)
|
||||
|
||||
for field in fields_iter:
|
||||
try:
|
||||
val = kwargs.pop(field.attname)
|
||||
setattr(self, field.attname, val)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if kwargs:
|
||||
for prop in list(kwargs):
|
||||
try:
|
||||
if isinstance(getattr(self.__class__, prop), property):
|
||||
setattr(self, prop, kwargs.pop(prop))
|
||||
except AttributeError:
|
||||
pass
|
||||
if kwargs:
|
||||
raise TypeError(
|
||||
"'%s' is an invalid keyword argument for this function" %
|
||||
list(kwargs)[0])
|
||||
|
||||
signals.post_init.send(self.__class__, instance=self)
|
||||
|
||||
@classmethod
|
||||
def _resolve_type(cls, schema, instance, *args):
|
||||
return schema.T(instance.__class__)
|
||||
|
||||
@classmethod
|
||||
def internal_type(cls, schema):
|
||||
if cls._meta.abstract:
|
||||
raise Exception("Abstract ObjectTypes don't have a specific type.")
|
||||
|
||||
if cls._meta.is_interface:
|
||||
return GraphQLInterfaceType(
|
||||
cls._meta.type_name,
|
||||
description=cls._meta.description,
|
||||
resolve_type=partial(cls._resolve_type, schema),
|
||||
fields=partial(cls.get_fields, schema)
|
||||
)
|
||||
elif cls._meta.is_union:
|
||||
return GraphQLUnionType(
|
||||
cls._meta.type_name,
|
||||
types=cls._meta.types,
|
||||
description=cls._meta.description,
|
||||
)
|
||||
return GraphQLObjectType(
|
||||
cls._meta.type_name,
|
||||
description=cls._meta.description,
|
||||
interfaces=[schema.T(i) for i in cls._meta.interfaces],
|
||||
fields=partial(cls.get_fields, schema),
|
||||
is_type_of=getattr(cls, 'is_type_of', None)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls, schema):
|
||||
fields = []
|
||||
for field in cls._meta.fields:
|
||||
try:
|
||||
fields.append((field.name, schema.T(field)))
|
||||
except SkipField:
|
||||
continue
|
||||
|
||||
return OrderedDict(fields)
|
||||
|
||||
@classmethod
|
||||
def wrap(cls, instance, args, info):
|
||||
return cls(_root=instance)
|
||||
|
||||
|
||||
class Interface(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
|
||||
pass
|
||||
|
||||
|
||||
class ObjectType(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
|
||||
pass
|
||||
|
||||
|
||||
class Mutation(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
|
||||
|
||||
@classmethod
|
||||
def _construct_arguments(cls, items):
|
||||
return ArgumentsGroup(**items)
|
||||
|
||||
@classmethod
|
||||
def _prepare_class(cls):
|
||||
input_class = getattr(cls, 'Input', None)
|
||||
if input_class:
|
||||
items = dict(vars(input_class))
|
||||
items.pop('__dict__', None)
|
||||
items.pop('__doc__', None)
|
||||
items.pop('__module__', None)
|
||||
items.pop('__weakref__', None)
|
||||
cls.add_to_class('arguments', cls._construct_arguments(items))
|
||||
delattr(cls, 'Input')
|
||||
|
||||
@classmethod
|
||||
def get_arguments(cls):
|
||||
return cls.arguments
|
||||
|
||||
|
||||
class InputObjectType(ObjectType):
|
||||
|
||||
@classmethod
|
||||
def internal_type(cls, schema):
|
||||
return GraphQLInputObjectType(
|
||||
cls._meta.type_name,
|
||||
description=cls._meta.description,
|
||||
fields=partial(cls.get_fields, schema),
|
||||
)
|
||||
__all__ = ['ObjectType', 'Interface', 'Mutation', 'InputObjectType']
|
||||
|
|
|
@ -1,194 +0,0 @@
|
|||
from graphql.core.execution.middlewares.utils import (resolver_has_tag,
|
||||
tag_resolver)
|
||||
from graphql.core.type import (GraphQLInterfaceType, GraphQLObjectType,
|
||||
GraphQLUnionType)
|
||||
from py.test import raises
|
||||
|
||||
from graphene.core.schema import Schema
|
||||
from graphene.core.types import Int, Interface, ObjectType, String
|
||||
|
||||
|
||||
class Character(Interface):
|
||||
'''Character description'''
|
||||
name = String()
|
||||
|
||||
class Meta:
|
||||
type_name = 'core_Character'
|
||||
|
||||
|
||||
class Human(Character):
|
||||
'''Human description'''
|
||||
friends = String()
|
||||
|
||||
class Meta:
|
||||
type_name = 'core_Human'
|
||||
|
||||
@property
|
||||
def readonly_prop(self):
|
||||
return 'readonly'
|
||||
|
||||
@property
|
||||
def write_prop(self):
|
||||
return self._write_prop
|
||||
|
||||
@write_prop.setter
|
||||
def write_prop(self, value):
|
||||
self._write_prop = value
|
||||
|
||||
|
||||
class Droid(Character):
|
||||
'''Droid description'''
|
||||
|
||||
|
||||
class CharacterType(Droid, Human):
|
||||
'''Union Type'''
|
||||
|
||||
schema = Schema()
|
||||
|
||||
|
||||
def test_interface():
|
||||
object_type = schema.T(Character)
|
||||
assert Character._meta.is_interface is True
|
||||
assert isinstance(object_type, GraphQLInterfaceType)
|
||||
assert Character._meta.type_name == 'core_Character'
|
||||
assert object_type.description == 'Character description'
|
||||
assert list(object_type.get_fields().keys()) == ['name']
|
||||
|
||||
|
||||
def test_interface_cannot_initialize():
|
||||
with raises(Exception) as excinfo:
|
||||
Character()
|
||||
assert 'An interface cannot be initialized' == str(excinfo.value)
|
||||
|
||||
|
||||
def test_union():
|
||||
object_type = schema.T(CharacterType)
|
||||
assert CharacterType._meta.is_union is True
|
||||
assert isinstance(object_type, GraphQLUnionType)
|
||||
assert object_type.description == 'Union Type'
|
||||
|
||||
|
||||
def test_union_cannot_initialize():
|
||||
with raises(Exception) as excinfo:
|
||||
CharacterType()
|
||||
assert 'An union cannot be initialized' == str(excinfo.value)
|
||||
|
||||
|
||||
def test_interface_resolve_type():
|
||||
resolve_type = Character._resolve_type(schema, Human(object()))
|
||||
assert isinstance(resolve_type, GraphQLObjectType)
|
||||
|
||||
|
||||
def test_object_type():
|
||||
object_type = schema.T(Human)
|
||||
assert Human._meta.is_interface is False
|
||||
assert Human._meta.type_name == 'core_Human'
|
||||
assert isinstance(object_type, GraphQLObjectType)
|
||||
assert object_type.description == 'Human description'
|
||||
assert list(object_type.get_fields().keys()) == ['name', 'friends']
|
||||
assert object_type.get_interfaces() == [schema.T(Character)]
|
||||
assert Human._meta.fields_map['name'].object_type == Human
|
||||
|
||||
|
||||
def test_object_type_container():
|
||||
h = Human(name='My name')
|
||||
assert h.name == 'My name'
|
||||
|
||||
|
||||
def test_object_type_set_properties():
|
||||
h = Human(readonly_prop='custom', write_prop='custom')
|
||||
assert h.readonly_prop == 'readonly'
|
||||
assert h.write_prop == 'custom'
|
||||
|
||||
|
||||
def test_object_type_container_invalid_kwarg():
|
||||
with raises(TypeError):
|
||||
Human(invalid='My name')
|
||||
|
||||
|
||||
def test_object_type_container_too_many_args():
|
||||
with raises(IndexError):
|
||||
Human('Peter', 'No friends :(', None)
|
||||
|
||||
|
||||
def test_field_clashes():
|
||||
with raises(Exception) as excinfo:
|
||||
class Droid(Character):
|
||||
name = Int()
|
||||
|
||||
assert 'clashes' in str(excinfo.value)
|
||||
|
||||
|
||||
def test_fields_inherited_should_be_different():
|
||||
assert Character._meta.fields_map['name'] != Human._meta.fields_map['name']
|
||||
|
||||
|
||||
def test_field_mantain_resolver_tags():
|
||||
class Droid(Character):
|
||||
name = String()
|
||||
|
||||
def resolve_name(self, *args):
|
||||
return 'My Droid'
|
||||
|
||||
tag_resolver(resolve_name, 'test')
|
||||
|
||||
field = schema.T(Droid._meta.fields_map['name'])
|
||||
assert resolver_has_tag(field.resolver, 'test')
|
||||
|
||||
|
||||
def test_type_has_nonnull():
|
||||
class Droid(Character):
|
||||
name = String()
|
||||
|
||||
assert Droid.NonNull.of_type == Droid
|
||||
|
||||
|
||||
def test_type_has_list():
|
||||
class Droid(Character):
|
||||
name = String()
|
||||
|
||||
assert Droid.List.of_type == Droid
|
||||
|
||||
|
||||
def test_abstracttype():
|
||||
class MyObject1(ObjectType):
|
||||
class Meta:
|
||||
abstract = True
|
||||
name1 = String()
|
||||
|
||||
class MyObject2(ObjectType):
|
||||
class Meta:
|
||||
abstract = True
|
||||
name2 = String()
|
||||
|
||||
class MyObject(MyObject1, MyObject2):
|
||||
pass
|
||||
|
||||
object_type = schema.T(MyObject)
|
||||
|
||||
assert list(MyObject._meta.fields_map.keys()) == ['name1', 'name2']
|
||||
assert MyObject._meta.fields_map['name1'].object_type == MyObject
|
||||
assert MyObject._meta.fields_map['name2'].object_type == MyObject
|
||||
assert isinstance(object_type, GraphQLObjectType)
|
||||
|
||||
|
||||
def test_abstracttype_initialize():
|
||||
class MyAbstractObjectType(ObjectType):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
with raises(Exception) as excinfo:
|
||||
MyAbstractObjectType()
|
||||
|
||||
assert 'An abstract ObjectType cannot be initialized' == str(excinfo.value)
|
||||
|
||||
|
||||
def test_abstracttype_type():
|
||||
class MyAbstractObjectType(ObjectType):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
with raises(Exception) as excinfo:
|
||||
schema.T(MyAbstractObjectType)
|
||||
|
||||
assert 'Abstract ObjectTypes don\'t have a specific type.' == str(excinfo.value)
|
Loading…
Reference in New Issue
Block a user