mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-26 11:33:55 +03:00
Improved ObjectType implementation
This commit is contained in:
parent
d8201c44fa
commit
cf80f87dca
|
@ -2,7 +2,7 @@ import six
|
||||||
|
|
||||||
from graphql import GraphQLInputObjectType
|
from graphql import GraphQLInputObjectType
|
||||||
|
|
||||||
from .definitions import FieldsMeta, ClassTypeMeta, GrapheneGraphQLType
|
from .definitions import GrapheneGraphQLType
|
||||||
from .interface import attrs_without_fields
|
from .interface import attrs_without_fields
|
||||||
from .unmountedtype import UnmountedType
|
from .unmountedtype import UnmountedType
|
||||||
from .options import Options
|
from .options import Options
|
||||||
|
@ -48,7 +48,7 @@ class InputObjectTypeMeta(type):
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
assert not fields, "Can't mount InputFields in an InputObjectType with a defined graphql_type"
|
assert not fields, "Can't mount InputFields in an InputObjectType with a defined graphql_type"
|
||||||
fields = copy_fields(options.graphql_type.get_fields(), parent=cls)
|
fields = copy_fields(InputField, options.graphql_type.get_fields(), parent=cls)
|
||||||
|
|
||||||
for name, field in fields.items():
|
for name, field in fields.items():
|
||||||
setattr(cls, field.attname or name, field)
|
setattr(cls, field.attname or name, field)
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
from itertools import chain
|
|
||||||
import copy
|
import copy
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from graphql import GraphQLObjectType
|
from graphql import GraphQLObjectType
|
||||||
|
|
||||||
from .definitions import FieldsMeta, ClassTypeMeta, GrapheneGraphQLType
|
from .definitions import GrapheneGraphQLType
|
||||||
from .interface import GrapheneInterfaceType, InterfaceTypeMeta, Interface
|
from .interface import GrapheneInterfaceType, InterfaceTypeMeta, Interface, attrs_without_fields
|
||||||
|
from .options import Options
|
||||||
|
from ..utils.is_base_type import is_base_type
|
||||||
|
from ..utils.get_fields import get_fields
|
||||||
|
from ..utils.copy_fields import copy_fields
|
||||||
|
from .field import Field
|
||||||
|
|
||||||
|
|
||||||
class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType):
|
class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType):
|
||||||
|
@ -38,7 +42,7 @@ class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_interfaces(cls, interfaces):
|
def get_interfaces(interfaces):
|
||||||
from ..utils.get_graphql_type import get_graphql_type
|
from ..utils.get_graphql_type import get_graphql_type
|
||||||
|
|
||||||
for interface in interfaces:
|
for interface in interfaces:
|
||||||
|
@ -46,48 +50,58 @@ def get_interfaces(cls, interfaces):
|
||||||
yield graphql_type
|
yield graphql_type
|
||||||
|
|
||||||
|
|
||||||
class ObjectTypeMeta(FieldsMeta, ClassTypeMeta, InterfaceTypeMeta):
|
# 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):
|
||||||
|
|
||||||
def get_options(cls, meta):
|
def __new__(cls, name, bases, attrs):
|
||||||
return cls.options_class(
|
super_new = type.__new__
|
||||||
meta,
|
|
||||||
|
# Also ensure initialization is only performed for subclasses of Model
|
||||||
|
# (excluding Model class itself).
|
||||||
|
if not is_base_type(bases, ObjectTypeMeta):
|
||||||
|
return super_new(cls, name, bases, attrs)
|
||||||
|
|
||||||
|
options = Options(
|
||||||
|
attrs.pop('Meta', None),
|
||||||
name=None,
|
name=None,
|
||||||
description=None,
|
description=None,
|
||||||
graphql_type=None,
|
graphql_type=None,
|
||||||
interfaces=[],
|
interfaces=(),
|
||||||
abstract=False
|
abstract=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
interfaces = tuple(options.interfaces)
|
||||||
|
fields = get_fields(ObjectType, attrs, bases, interfaces)
|
||||||
|
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)
|
||||||
|
base_interfaces = tuple(b for b in bases if issubclass(b, Interface))
|
||||||
|
options.graphql_type = GrapheneObjectType(
|
||||||
|
graphene_type=cls,
|
||||||
|
name=options.name or cls.__name__,
|
||||||
|
description=options.description or cls.__doc__,
|
||||||
|
fields=fields,
|
||||||
|
interfaces=tuple(get_interfaces(interfaces + base_interfaces))
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
assert not fields, "Can't mount Fields in an ObjectType with a defined graphql_type"
|
||||||
|
fields = copy_fields(Field, options.graphql_type.get_fields(), parent=cls)
|
||||||
|
|
||||||
|
for name, field in fields.items():
|
||||||
|
setattr(cls, field.attname or name, field)
|
||||||
|
|
||||||
|
return cls
|
||||||
|
|
||||||
def get_interfaces(cls, bases):
|
def get_interfaces(cls, bases):
|
||||||
return (b for b in bases if issubclass(b, Interface))
|
return (b for b in bases if issubclass(b, Interface))
|
||||||
|
|
||||||
def is_object_type(cls):
|
def is_object_type(cls):
|
||||||
return issubclass(cls, ObjectType)
|
return issubclass(cls, ObjectType)
|
||||||
|
|
||||||
def construct(cls, bases, attrs):
|
|
||||||
if not cls._meta.abstract and cls.is_object_type():
|
|
||||||
cls.get_interfaces(bases)
|
|
||||||
interfaces = tuple(get_interfaces(cls, chain(
|
|
||||||
cls._meta.interfaces,
|
|
||||||
cls.get_interfaces(bases),
|
|
||||||
)))
|
|
||||||
|
|
||||||
local_fields = cls._extract_local_fields(attrs)
|
|
||||||
if not cls._meta.graphql_type:
|
|
||||||
cls = super(ObjectTypeMeta, cls).construct(bases, attrs)
|
|
||||||
cls._meta.graphql_type = GrapheneObjectType(
|
|
||||||
graphene_type=cls,
|
|
||||||
name=cls._meta.name or cls.__name__,
|
|
||||||
description=cls._meta.description or cls.__doc__,
|
|
||||||
fields=cls._fields(bases, attrs, local_fields, interfaces),
|
|
||||||
interfaces=interfaces,
|
|
||||||
)
|
|
||||||
return cls
|
|
||||||
else:
|
|
||||||
assert not local_fields, "Can't mount Fields in an ObjectType with a defined graphql_type"
|
|
||||||
|
|
||||||
return super(ObjectTypeMeta, cls).construct(bases, attrs)
|
|
||||||
|
|
||||||
|
|
||||||
def implements(*interfaces):
|
def implements(*interfaces):
|
||||||
# This function let us decorate a ObjectType
|
# This function let us decorate a ObjectType
|
||||||
|
@ -106,9 +120,6 @@ def implements(*interfaces):
|
||||||
|
|
||||||
|
|
||||||
class ObjectType(six.with_metaclass(ObjectTypeMeta)):
|
class ObjectType(six.with_metaclass(ObjectTypeMeta)):
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
# GraphQL ObjectType acting as container
|
# GraphQL ObjectType acting as container
|
||||||
args_len = len(args)
|
args_len = len(args)
|
||||||
|
|
|
@ -26,12 +26,12 @@ def get_fields_from_types(bases):
|
||||||
yield attname, field
|
yield attname, field
|
||||||
|
|
||||||
|
|
||||||
def get_fields(in_type, attrs, bases):
|
def get_fields(in_type, attrs, bases, graphql_types=()):
|
||||||
fields = []
|
fields = []
|
||||||
|
|
||||||
graphene_bases = tuple(
|
graphene_bases = tuple(
|
||||||
base._meta.graphql_type for base in bases if is_graphene_type(base) and not base._meta.abstract
|
base._meta.graphql_type for base in bases if is_graphene_type(base)
|
||||||
)
|
) + graphql_types
|
||||||
|
|
||||||
extended_fields = list(get_fields_from_types(graphene_bases))
|
extended_fields = list(get_fields_from_types(graphene_bases))
|
||||||
local_fields = list(get_fields_from_attrs(in_type, attrs))
|
local_fields = list(get_fields_from_attrs(in_type, attrs))
|
||||||
|
|
|
@ -8,7 +8,7 @@ def is_graphene_type(_type):
|
||||||
from ..types.scalars import Scalar
|
from ..types.scalars import Scalar
|
||||||
from ..types.enum import Enum
|
from ..types.enum import Enum
|
||||||
|
|
||||||
if _type in [Interface, InputObjectType]:
|
if _type in [Interface, InputObjectType, ObjectType]:
|
||||||
return False
|
return False
|
||||||
return inspect.isclass(_type) and issubclass(_type, (
|
return inspect.isclass(_type) and issubclass(_type, (
|
||||||
Interface,
|
Interface,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user