mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-08 23:50:38 +03:00
Moved Interface to ObjectType. Improved integration with latest GraphQL-core
This commit is contained in:
parent
7a29502790
commit
9a9d7f8873
|
@ -2,7 +2,7 @@ import inspect
|
|||
from collections import OrderedDict
|
||||
from itertools import chain
|
||||
|
||||
from graphql import GraphQLArgument
|
||||
from graphql.type.definition import GraphQLArgument, GraphQLArgumentDefinition
|
||||
from graphql.utils.assert_valid_name import assert_valid_name
|
||||
|
||||
from ..utils.orderedtype import OrderedType
|
||||
|
@ -40,11 +40,15 @@ class Argument(GraphQLArgument, OrderedType):
|
|||
|
||||
@classmethod
|
||||
def copy_from(cls, argument):
|
||||
if isinstance (argument, (GraphQLArgumentDefinition, Argument)):
|
||||
name = argument.name
|
||||
else:
|
||||
name = None
|
||||
return cls(
|
||||
type=argument.type,
|
||||
default_value=argument.default_value,
|
||||
description=argument.description,
|
||||
name=argument.name,
|
||||
name=name,
|
||||
_creation_counter=argument.creation_counter if isinstance(argument, Argument) else None,
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from collections import OrderedDict
|
||||
import inspect
|
||||
|
||||
from graphql.type import GraphQLField, GraphQLInputObjectField
|
||||
from graphql.type import GraphQLField, GraphQLInputObjectField, GraphQLFieldDefinition
|
||||
from graphql.utils.assert_valid_name import assert_valid_name
|
||||
|
||||
from ..utils.orderedtype import OrderedType
|
||||
|
@ -126,18 +127,23 @@ class Field(AbstractField, GraphQLField, OrderedType):
|
|||
_creation_counter = field.creation_counter if _creation_counter is False else None
|
||||
attname = attname or field.attname
|
||||
parent = parent or field.parent
|
||||
args = to_arguments(args, field.args)
|
||||
else:
|
||||
# If is a GraphQLField
|
||||
type = type or field.type
|
||||
resolver = resolver or field.resolver
|
||||
name = field.name
|
||||
field_args = field.args
|
||||
if isinstance(field, GraphQLFieldDefinition):
|
||||
name = name or field.name
|
||||
field_args = OrderedDict((a.name, a) for a in field_args)
|
||||
args = to_arguments(args, field_args)
|
||||
_creation_counter = None
|
||||
attname = attname or name
|
||||
parent = parent
|
||||
|
||||
new_field = cls(
|
||||
type=type,
|
||||
args=to_arguments(args, field.args),
|
||||
args=args,
|
||||
resolver=resolver,
|
||||
source=source,
|
||||
deprecation_reason=field.deprecation_reason,
|
||||
|
|
|
@ -7,7 +7,7 @@ from ..utils.get_fields import get_fields
|
|||
from ..utils.is_base_type import is_base_type
|
||||
from .definitions import GrapheneGraphQLType
|
||||
from .field import InputField
|
||||
from .interface import attrs_without_fields
|
||||
from .objecttype import attrs_without_fields
|
||||
from .options import Options
|
||||
from .unmountedtype import UnmountedType
|
||||
|
||||
|
|
|
@ -1,81 +1 @@
|
|||
import six
|
||||
|
||||
from graphql import GraphQLInterfaceType
|
||||
|
||||
from ..utils.copy_fields import copy_fields
|
||||
from ..utils.get_fields import get_fields
|
||||
from ..utils.is_base_type import is_base_type
|
||||
from .definitions import GrapheneGraphQLType
|
||||
from .field import Field
|
||||
from .options import Options
|
||||
|
||||
|
||||
class GrapheneInterfaceType(GrapheneGraphQLType, GraphQLInterfaceType):
|
||||
pass
|
||||
|
||||
|
||||
class InterfaceTypeMeta(type):
|
||||
|
||||
@staticmethod
|
||||
def _get_interface_options(meta):
|
||||
return Options(
|
||||
meta,
|
||||
name=None,
|
||||
description=None,
|
||||
graphql_type=None,
|
||||
abstract=False
|
||||
)
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
super_new = super(InterfaceTypeMeta, cls).__new__
|
||||
|
||||
# Also ensure initialization is only performed for subclasses of Model
|
||||
# (excluding Model class itself).
|
||||
if not is_base_type(bases, InterfaceTypeMeta):
|
||||
return super_new(cls, name, bases, attrs)
|
||||
|
||||
options = cls._get_interface_options(attrs.pop('Meta', None))
|
||||
|
||||
fields = get_fields(Interface, attrs, bases)
|
||||
attrs = attrs_without_fields(attrs, fields)
|
||||
cls = super_new(cls, name, bases, dict(attrs, _meta=options))
|
||||
|
||||
if not options.graphql_type:
|
||||
fields = copy_fields(Field, fields, parent=cls)
|
||||
options.graphql_type = GrapheneInterfaceType(
|
||||
graphene_type=cls,
|
||||
name=options.name or cls.__name__,
|
||||
resolve_type=cls.resolve_type,
|
||||
description=options.description or cls.__doc__,
|
||||
fields=fields,
|
||||
)
|
||||
else:
|
||||
assert not fields, "Can't mount Fields in an Interface with a defined graphql_type"
|
||||
fields = copy_fields(options.graphql_type.get_fields(), parent=cls)
|
||||
|
||||
for name, field in fields.items():
|
||||
setattr(cls, field.attname or name, field)
|
||||
|
||||
return cls
|
||||
|
||||
|
||||
def attrs_without_fields(attrs, fields):
|
||||
return {k: v for k, v in attrs.items() if k not in fields}
|
||||
|
||||
|
||||
class Interface(six.with_metaclass(InterfaceTypeMeta)):
|
||||
resolve_type = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
from .objecttype import ObjectType
|
||||
if not isinstance(self, ObjectType):
|
||||
raise Exception("An interface cannot be intitialized")
|
||||
super(Interface, self).__init__(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def implements(cls, object_type):
|
||||
'''
|
||||
We use this function for customizing when a ObjectType have this class as Interface
|
||||
For example, if we want to check that the ObjectType have some required things
|
||||
in it like Node.get_node
|
||||
'''
|
||||
from .objecttype import Interface, GrapheneInterfaceType
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
|
||||
import six
|
||||
|
||||
from graphql import GraphQLObjectType
|
||||
from graphql import GraphQLObjectType, GraphQLInterfaceType
|
||||
|
||||
from ..utils.copy_fields import copy_fields
|
||||
from ..utils.get_fields import get_fields
|
||||
from ..utils.is_base_type import is_base_type
|
||||
from .definitions import GrapheneGraphQLType
|
||||
from .field import Field
|
||||
from .interface import (GrapheneInterfaceType, Interface, InterfaceTypeMeta,
|
||||
attrs_without_fields)
|
||||
from .options import Options
|
||||
|
||||
|
||||
class GrapheneInterfaceType(GrapheneGraphQLType, GraphQLInterfaceType):
|
||||
pass
|
||||
|
||||
|
||||
class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -42,10 +44,13 @@ def is_objecttype(bases):
|
|||
return False
|
||||
|
||||
|
||||
def attrs_without_fields(attrs, fields):
|
||||
return {k: v for k, v in attrs.items() if k not in fields}
|
||||
|
||||
# We inherit from InterfaceTypeMeta instead of type for being able
|
||||
# to have ObjectTypes extending Interfaces using Python syntax, like:
|
||||
# class MyObjectType(ObjectType, MyInterface)
|
||||
class ObjectTypeMeta(InterfaceTypeMeta):
|
||||
class ObjectTypeMeta(type):
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
super_new = type.__new__
|
||||
|
@ -57,7 +62,7 @@ class ObjectTypeMeta(InterfaceTypeMeta):
|
|||
return super_new(cls, name, bases, attrs)
|
||||
|
||||
if not is_objecttype(bases):
|
||||
return super(ObjectTypeMeta, cls).__new__(cls, name, bases, attrs)
|
||||
return cls._create_interface(cls, name, bases, attrs)
|
||||
|
||||
options = Options(
|
||||
attrs.pop('Meta', None),
|
||||
|
@ -99,6 +104,42 @@ class ObjectTypeMeta(InterfaceTypeMeta):
|
|||
def is_object_type(cls):
|
||||
return issubclass(cls, ObjectType)
|
||||
|
||||
@staticmethod
|
||||
def _get_interface_options(meta):
|
||||
return Options(
|
||||
meta,
|
||||
name=None,
|
||||
description=None,
|
||||
graphql_type=None,
|
||||
abstract=False
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _create_interface(cls, name, bases, attrs):
|
||||
options = cls._get_interface_options(attrs.pop('Meta', None))
|
||||
|
||||
fields = get_fields(Interface, attrs, bases)
|
||||
attrs = attrs_without_fields(attrs, fields)
|
||||
cls = type.__new__(cls, name, bases, dict(attrs, _meta=options))
|
||||
|
||||
if not options.graphql_type:
|
||||
fields = copy_fields(Field, fields, parent=cls)
|
||||
options.graphql_type = GrapheneInterfaceType(
|
||||
graphene_type=cls,
|
||||
name=options.name or cls.__name__,
|
||||
resolve_type=cls.resolve_type,
|
||||
description=options.description or cls.__doc__,
|
||||
fields=fields,
|
||||
)
|
||||
else:
|
||||
assert not fields, "Can't mount Fields in an Interface with a defined graphql_type"
|
||||
fields = copy_fields(options.graphql_type.get_fields(), parent=cls)
|
||||
|
||||
for name, field in fields.items():
|
||||
setattr(cls, field.attname or name, field)
|
||||
|
||||
return cls
|
||||
|
||||
|
||||
class ObjectType(six.with_metaclass(ObjectTypeMeta)):
|
||||
|
||||
|
@ -152,3 +193,21 @@ class ObjectType(six.with_metaclass(ObjectTypeMeta)):
|
|||
return graphql_type.name == cls._meta.graphql_type.name
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
class Interface(six.with_metaclass(ObjectTypeMeta)):
|
||||
resolve_type = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
from .objecttype import ObjectType
|
||||
if not isinstance(self, ObjectType):
|
||||
raise Exception("An interface cannot be intitialized")
|
||||
super(Interface, self).__init__(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def implements(cls, object_type):
|
||||
'''
|
||||
We use this function for customizing when a ObjectType have this class as Interface
|
||||
For example, if we want to check that the ObjectType have some required things
|
||||
in it like Node.get_node
|
||||
'''
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
from graphql import GraphQLInputObjectType, GraphQLString
|
||||
from graphql.type.definition import GraphQLInputFieldDefinition
|
||||
|
||||
from ..field import InputField
|
||||
from ..inputobjecttype import InputObjectType
|
||||
|
@ -43,7 +44,7 @@ def test_generate_objecttype_with_fields():
|
|||
graphql_type = MyObjectType._meta.graphql_type
|
||||
fields = graphql_type.get_fields()
|
||||
assert 'field' in fields
|
||||
assert isinstance(fields['field'], InputField)
|
||||
assert isinstance(fields['field'], GraphQLInputFieldDefinition)
|
||||
|
||||
|
||||
def test_generate_objecttype_with_graphene_fields():
|
||||
|
@ -53,4 +54,4 @@ def test_generate_objecttype_with_graphene_fields():
|
|||
graphql_type = MyObjectType._meta.graphql_type
|
||||
fields = graphql_type.get_fields()
|
||||
assert 'field' in fields
|
||||
assert isinstance(fields['field'], InputField)
|
||||
assert isinstance(fields['field'], GraphQLInputFieldDefinition)
|
||||
|
|
|
@ -56,7 +56,7 @@ def test_interface_inheritance():
|
|||
fields = graphql_type.get_fields()
|
||||
assert 'field' in fields
|
||||
assert 'inherited' in fields
|
||||
assert fields['field'] > fields['inherited']
|
||||
assert MyInterface.field > MyInheritedInterface.inherited
|
||||
|
||||
|
||||
def test_interface_instance():
|
||||
|
|
|
@ -74,11 +74,7 @@ def test_objecttype_inheritance():
|
|||
|
||||
graphql_type = MyObjectType._meta.graphql_type
|
||||
fields = graphql_type.get_fields()
|
||||
assert 'field1' in fields
|
||||
assert 'field2' in fields
|
||||
assert 'inherited' in fields
|
||||
assert fields['field1'] > fields['inherited']
|
||||
assert fields['field2'] > fields['field1']
|
||||
assert fields.keys() == ['inherited', 'field1', 'field2']
|
||||
|
||||
|
||||
def test_objecttype_as_container_get_fields():
|
||||
|
@ -195,11 +191,7 @@ def test_objecttype_graphene_interface():
|
|||
graphql_type = GrapheneObjectType._meta.graphql_type
|
||||
assert graphql_type.get_interfaces() == (GrapheneInterface._meta.graphql_type, )
|
||||
assert graphql_type.is_type_of(GrapheneObjectType(), None, None)
|
||||
fields = graphql_type.get_fields()
|
||||
assert 'field' in fields
|
||||
assert 'extended' in fields
|
||||
assert 'name' in fields
|
||||
assert fields['field'] > fields['extended'] > fields['name']
|
||||
fields = graphql_type.get_fields().keys() == ['name', 'extended', 'field']
|
||||
|
||||
|
||||
def test_objecttype_graphene_inherit_interface():
|
||||
|
|
|
@ -3,8 +3,9 @@ import datetime
|
|||
import pytest
|
||||
|
||||
from graphene.utils.get_graphql_type import get_graphql_type
|
||||
from graphql import (GraphQLBoolean, GraphQLFloat, GraphQLInt,
|
||||
GraphQLScalarType, GraphQLString, graphql)
|
||||
from graphql import graphql
|
||||
from graphql.type import (GraphQLBoolean, GraphQLFloat, GraphQLInt,
|
||||
GraphQLScalarType, GraphQLString, GraphQLFieldDefinition)
|
||||
from graphql.language import ast
|
||||
|
||||
from ..field import Field
|
||||
|
@ -94,7 +95,7 @@ def test_scalar_in_objecttype(scalar_class, graphql_type):
|
|||
graphql_type = get_graphql_type(MyObjectType)
|
||||
fields = graphql_type.get_fields()
|
||||
assert list(fields.keys()) == ['before', 'field', 'after']
|
||||
assert isinstance(fields['field'], Field)
|
||||
assert isinstance(fields['field'], GraphQLFieldDefinition)
|
||||
|
||||
|
||||
def test_custom_scalar_empty():
|
||||
|
|
|
@ -11,6 +11,12 @@ class Character(Interface):
|
|||
friends = List(lambda: Character)
|
||||
best_friend = Field(lambda: Character)
|
||||
|
||||
def resolve_friends(self, *args):
|
||||
return [Human(name='Peter')]
|
||||
|
||||
def resolve_best_friend(self, *args):
|
||||
return Human(name='Best')
|
||||
|
||||
|
||||
class Pet(ObjectType):
|
||||
type = String()
|
||||
|
@ -26,12 +32,6 @@ class Human(ObjectType):
|
|||
def resolve_pet(self, *args):
|
||||
return Pet(type='Dog')
|
||||
|
||||
def resolve_friends(self, *args):
|
||||
return [Human(name='Peter')]
|
||||
|
||||
def resolve_best_friend(self, *args):
|
||||
return Human(name='Best')
|
||||
|
||||
|
||||
class RootQuery(ObjectType):
|
||||
character = Field(Character)
|
||||
|
|
Loading…
Reference in New Issue
Block a user