Moved Interface to ObjectType

This commit is contained in:
Syrus Akbary 2016-06-20 17:47:26 -07:00
parent 7a29502790
commit 6611c861d8
3 changed files with 66 additions and 87 deletions

View File

@ -7,7 +7,7 @@ from ..utils.get_fields import get_fields
from ..utils.is_base_type import is_base_type from ..utils.is_base_type import is_base_type
from .definitions import GrapheneGraphQLType from .definitions import GrapheneGraphQLType
from .field import InputField from .field import InputField
from .interface import attrs_without_fields from .objecttype import attrs_without_fields
from .options import Options from .options import Options
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType

View File

@ -1,81 +1 @@
import six from .objecttype import Interface, GrapheneInterfaceType
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
'''

View File

@ -1,18 +1,20 @@
import six import six
from graphql import GraphQLObjectType from graphql import GraphQLObjectType, GraphQLInterfaceType
from ..utils.copy_fields import copy_fields from ..utils.copy_fields import copy_fields
from ..utils.get_fields import get_fields from ..utils.get_fields import get_fields
from ..utils.is_base_type import is_base_type from ..utils.is_base_type import is_base_type
from .definitions import GrapheneGraphQLType from .definitions import GrapheneGraphQLType
from .field import Field from .field import Field
from .interface import (GrapheneInterfaceType, Interface, InterfaceTypeMeta,
attrs_without_fields)
from .options import Options from .options import Options
class GrapheneInterfaceType(GrapheneGraphQLType, GraphQLInterfaceType):
pass
class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType): class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -42,10 +44,13 @@ def is_objecttype(bases):
return False 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 # We inherit from InterfaceTypeMeta instead of type for being able
# to have ObjectTypes extending Interfaces using Python syntax, like: # to have ObjectTypes extending Interfaces using Python syntax, like:
# class MyObjectType(ObjectType, MyInterface) # class MyObjectType(ObjectType, MyInterface)
class ObjectTypeMeta(InterfaceTypeMeta): class ObjectTypeMeta(type):
def __new__(cls, name, bases, attrs): def __new__(cls, name, bases, attrs):
super_new = type.__new__ super_new = type.__new__
@ -57,7 +62,7 @@ class ObjectTypeMeta(InterfaceTypeMeta):
return super_new(cls, name, bases, attrs) return super_new(cls, name, bases, attrs)
if not is_objecttype(bases): if not is_objecttype(bases):
return super(ObjectTypeMeta, cls).__new__(cls, name, bases, attrs) return cls._create_interface(cls, name, bases, attrs)
options = Options( options = Options(
attrs.pop('Meta', None), attrs.pop('Meta', None),
@ -99,6 +104,42 @@ class ObjectTypeMeta(InterfaceTypeMeta):
def is_object_type(cls): def is_object_type(cls):
return issubclass(cls, ObjectType) 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)): 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 return graphql_type.name == cls._meta.graphql_type.name
except: except:
return False 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
'''