mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-22 09:36:44 +03:00
Improved relay compatibility
This commit is contained in:
parent
b24e9a1051
commit
d67b7bc6a1
|
@ -1,33 +1,37 @@
|
|||
import graphene
|
||||
from graphene import relay, resolve_only_args
|
||||
from graphene import implements, relay, resolve_only_args
|
||||
|
||||
from .data import create_ship, get_empire, get_faction, get_rebels, get_ship
|
||||
|
||||
schema = graphene.Schema(name='Starwars Relay Schema')
|
||||
|
||||
|
||||
class Ship(relay.Node):
|
||||
# @implements(relay.Node)
|
||||
class Ship(graphene.ObjectType):
|
||||
class Meta:
|
||||
interfaces = [relay.Node]
|
||||
'''A ship in the Star Wars saga'''
|
||||
name = graphene.String(description='The name of the ship.')
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, id, info):
|
||||
def get_node(cls, id, context, info):
|
||||
return get_ship(id)
|
||||
|
||||
|
||||
class Faction(relay.Node):
|
||||
# @implements(relay.Node)
|
||||
class Faction(graphene.ObjectType):
|
||||
class Meta:
|
||||
interfaces = [relay.Node]
|
||||
'''A faction in the Star Wars saga'''
|
||||
name = graphene.String(description='The name of the faction.')
|
||||
ships = relay.ConnectionField(
|
||||
Ship, description='The ships used by the faction.')
|
||||
|
||||
@resolve_only_args
|
||||
def resolve_ships(self, **args):
|
||||
# Transform the instance ship_ids into real instances
|
||||
return [get_ship(ship_id) for ship_id in self.ships]
|
||||
# ships = relay.ConnectionField(
|
||||
# Ship, description='The ships used by the faction.')
|
||||
ships = graphene.List(graphene.String)
|
||||
# @resolve_only_args
|
||||
# def resolve_ships(self, **args):
|
||||
# # Transform the instance ship_ids into real instances
|
||||
# return [get_ship(ship_id) for ship_id in self.ships]
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, id, info):
|
||||
def get_node(cls, id, context, info):
|
||||
return get_faction(id)
|
||||
|
||||
|
||||
|
@ -41,9 +45,9 @@ class IntroduceShip(relay.ClientIDMutation):
|
|||
faction = graphene.Field(Faction)
|
||||
|
||||
@classmethod
|
||||
def mutate_and_get_payload(cls, input, info):
|
||||
ship_name = input.get('ship_name')
|
||||
faction_id = input.get('faction_id')
|
||||
def mutate_and_get_payload(cls, input, context, info):
|
||||
ship_name = input.get('shipName')
|
||||
faction_id = input.get('factionId')
|
||||
ship = create_ship(ship_name, faction_id)
|
||||
faction = get_faction(faction_id)
|
||||
return IntroduceShip(ship=ship, faction=faction)
|
||||
|
@ -52,7 +56,7 @@ class IntroduceShip(relay.ClientIDMutation):
|
|||
class Query(graphene.ObjectType):
|
||||
rebels = graphene.Field(Faction)
|
||||
empire = graphene.Field(Faction)
|
||||
node = relay.NodeField()
|
||||
node = relay.Node.Field
|
||||
|
||||
@resolve_only_args
|
||||
def resolve_rebels(self):
|
||||
|
@ -64,8 +68,8 @@ class Query(graphene.ObjectType):
|
|||
|
||||
|
||||
class Mutation(graphene.ObjectType):
|
||||
introduce_ship = graphene.Field(IntroduceShip)
|
||||
introduce_ship = IntroduceShip.Field
|
||||
|
||||
|
||||
schema.query = Query
|
||||
schema.mutation = Mutation
|
||||
|
||||
schema = graphene.Schema(query=Query, mutation=Mutation)
|
||||
|
|
|
@ -14,14 +14,14 @@ def test_mutations():
|
|||
}
|
||||
faction {
|
||||
name
|
||||
ships {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
# ships {
|
||||
# edges {
|
||||
# node {
|
||||
# id
|
||||
# name
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,42 +34,43 @@ def test_mutations():
|
|||
},
|
||||
'faction': {
|
||||
'name': 'Alliance to Restore the Republic',
|
||||
'ships': {
|
||||
'edges': [{
|
||||
'node': {
|
||||
'id': 'U2hpcDox',
|
||||
'name': 'X-Wing'
|
||||
}
|
||||
}, {
|
||||
'node': {
|
||||
'id': 'U2hpcDoy',
|
||||
'name': 'Y-Wing'
|
||||
}
|
||||
}, {
|
||||
'node': {
|
||||
'id': 'U2hpcDoz',
|
||||
'name': 'A-Wing'
|
||||
}
|
||||
}, {
|
||||
'node': {
|
||||
'id': 'U2hpcDo0',
|
||||
'name': 'Millenium Falcon'
|
||||
}
|
||||
}, {
|
||||
'node': {
|
||||
'id': 'U2hpcDo1',
|
||||
'name': 'Home One'
|
||||
}
|
||||
}, {
|
||||
'node': {
|
||||
'id': 'U2hpcDo5',
|
||||
'name': 'Peter'
|
||||
}
|
||||
}]
|
||||
},
|
||||
# 'ships': {
|
||||
# 'edges': [{
|
||||
# 'node': {
|
||||
# 'id': 'U2hpcDox',
|
||||
# 'name': 'X-Wing'
|
||||
# }
|
||||
# }, {
|
||||
# 'node': {
|
||||
# 'id': 'U2hpcDoy',
|
||||
# 'name': 'Y-Wing'
|
||||
# }
|
||||
# }, {
|
||||
# 'node': {
|
||||
# 'id': 'U2hpcDoz',
|
||||
# 'name': 'A-Wing'
|
||||
# }
|
||||
# }, {
|
||||
# 'node': {
|
||||
# 'id': 'U2hpcDo0',
|
||||
# 'name': 'Millenium Falcon'
|
||||
# }
|
||||
# }, {
|
||||
# 'node': {
|
||||
# 'id': 'U2hpcDo1',
|
||||
# 'name': 'Home One'
|
||||
# }
|
||||
# }, {
|
||||
# 'node': {
|
||||
# 'id': 'U2hpcDo5',
|
||||
# 'name': 'Peter'
|
||||
# }
|
||||
# }]
|
||||
# },
|
||||
}
|
||||
}
|
||||
}
|
||||
result = schema.execute(query)
|
||||
# raise result.errors[0].original_error, None, result.errors[0].stack
|
||||
assert not result.errors
|
||||
assert result.data == expected
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
from .node import Node
|
||||
# from .mutation import ClientIDMutation
|
||||
from .mutation import ClientIDMutation
|
||||
|
|
62
graphene/relay/mutation.py
Normal file
62
graphene/relay/mutation.py
Normal file
|
@ -0,0 +1,62 @@
|
|||
from functools import partial
|
||||
import copy
|
||||
import six
|
||||
from graphql_relay import mutation_with_client_mutation_id
|
||||
|
||||
from ..types.mutation import Mutation, MutationMeta
|
||||
from ..types.inputobjecttype import GrapheneInputObjectType, InputObjectType
|
||||
from ..types.objecttype import GrapheneObjectType
|
||||
from ..types.field import Field, InputField
|
||||
|
||||
from ..utils.props import props
|
||||
|
||||
|
||||
class ClientIDMutationMeta(MutationMeta):
|
||||
_construct_field = False
|
||||
|
||||
def get_options(cls, meta):
|
||||
options = cls.options_class(
|
||||
meta,
|
||||
name=None,
|
||||
abstract=False
|
||||
)
|
||||
options.graphql_type = None
|
||||
options.interfaces = []
|
||||
return options
|
||||
|
||||
def construct(cls, bases, attrs):
|
||||
if not cls._meta.abstract:
|
||||
Input = attrs.pop('Input', None)
|
||||
field_attrs = props(Input) if Input else {}
|
||||
|
||||
cls.mutate_and_get_payload = attrs.pop('mutate_and_get_payload', None)
|
||||
|
||||
input_local_fields = {f.name: f for f in InputObjectType._extract_local_fields(field_attrs)}
|
||||
local_fields = cls._extract_local_fields(attrs)
|
||||
assert cls.mutate_and_get_payload, "{}.mutate_and_get_payload method is required in a ClientIDMutation ObjectType.".format(cls.__name__)
|
||||
field = mutation_with_client_mutation_id(
|
||||
name=cls._meta.name or cls.__name__,
|
||||
input_fields=input_local_fields,
|
||||
output_fields=cls._fields(bases, attrs, local_fields),
|
||||
mutate_and_get_payload=cls.mutate_and_get_payload,
|
||||
|
||||
input_type_class=partial(GrapheneInputObjectType, graphene_type=cls),
|
||||
input_field_class=InputField,
|
||||
output_type_class=partial(GrapheneObjectType, graphene_type=cls),
|
||||
field_class=Field,
|
||||
)
|
||||
cls._meta.graphql_type = field.type
|
||||
cls._Field = field
|
||||
constructed = super(ClientIDMutationMeta, cls).construct(bases, attrs)
|
||||
return constructed
|
||||
|
||||
@property
|
||||
def Field(cls):
|
||||
field = copy.copy(cls._Field)
|
||||
field.reset_counter()
|
||||
return field
|
||||
|
||||
|
||||
class ClientIDMutation(six.with_metaclass(ClientIDMutationMeta, Mutation)):
|
||||
class Meta:
|
||||
abstract = True
|
|
@ -1,7 +1,7 @@
|
|||
import copy
|
||||
from functools import partial
|
||||
import six
|
||||
from graphql_relay import node_definitions, from_global_id
|
||||
from graphql_relay import node_definitions, from_global_id, to_global_id
|
||||
|
||||
from ..types.field import Field
|
||||
from ..types.interface import GrapheneInterfaceType, Interface, InterfaceTypeMeta
|
||||
|
@ -14,10 +14,12 @@ class NodeMeta(InterfaceTypeMeta):
|
|||
|
||||
def construct(cls, bases, attrs):
|
||||
cls.get_node = attrs.pop('get_node')
|
||||
cls.id_resolver = attrs.pop('id_resolver', None)
|
||||
node_interface, node_field = node_definitions(
|
||||
cls.get_node,
|
||||
id_resolver=cls.id_resolver,
|
||||
interface_class=partial(GrapheneInterfaceType, graphene_type=cls),
|
||||
field_class=Field
|
||||
field_class=Field,
|
||||
)
|
||||
cls._meta.graphql_type = node_interface
|
||||
cls._Field = node_field
|
||||
|
@ -42,6 +44,14 @@ class Node(six.with_metaclass(NodeMeta, Interface)):
|
|||
def from_global_id(cls, global_id):
|
||||
return from_global_id(global_id)
|
||||
|
||||
@classmethod
|
||||
def to_global_id(cls, type, id):
|
||||
return to_global_id(type, id)
|
||||
|
||||
@classmethod
|
||||
def id_resolver(cls, root, args, context, info):
|
||||
return cls.to_global_id(info.parent_type.name, getattr(root, 'id', None))
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, global_id, context, info):
|
||||
try:
|
||||
|
@ -61,4 +71,5 @@ class Node(six.with_metaclass(NodeMeta, Interface)):
|
|||
'''
|
||||
if cls.require_get_node():
|
||||
assert hasattr(object_type, 'get_node'), '{}.get_node method is required by the Node interface.'.format(object_type.__name__)
|
||||
|
||||
return super(Node, cls).implements(object_type)
|
||||
|
|
84
graphene/relay/tests/test_mutation.py
Normal file
84
graphene/relay/tests/test_mutation.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
import pytest
|
||||
|
||||
from graphql_relay import to_global_id
|
||||
|
||||
from ..mutation import ClientIDMutation
|
||||
from ...types import ObjectType, Schema, implements
|
||||
from ...types.scalars import String
|
||||
|
||||
|
||||
class SaySomething(ClientIDMutation):
|
||||
class Input:
|
||||
what = String()
|
||||
phrase = String()
|
||||
|
||||
@staticmethod
|
||||
def mutate_and_get_payload(args, context, info):
|
||||
what = args.get('what')
|
||||
return SaySomething(phrase=str(what))
|
||||
|
||||
|
||||
class RootQuery(ObjectType):
|
||||
something = String()
|
||||
|
||||
|
||||
class Mutation(ObjectType):
|
||||
say = SaySomething.Field
|
||||
|
||||
schema = Schema(query=RootQuery, mutation=Mutation)
|
||||
|
||||
|
||||
def test_no_mutate_and_get_payload():
|
||||
with pytest.raises(AssertionError) as excinfo:
|
||||
class MyMutation(ClientIDMutation):
|
||||
pass
|
||||
|
||||
assert "MyMutation.mutate_and_get_payload method is required in a ClientIDMutation ObjectType." == str(excinfo.value)
|
||||
|
||||
|
||||
def test_node_good():
|
||||
graphql_type = SaySomething._meta.graphql_type
|
||||
fields = graphql_type.get_fields()
|
||||
assert 'phrase' in fields
|
||||
assert SaySomething.Field.type == SaySomething._meta.graphql_type
|
||||
graphql_field = SaySomething.Field
|
||||
assert 'input' in graphql_field.args
|
||||
input = graphql_field.args['input']
|
||||
assert 'clientMutationId' in input.type.of_type.get_fields()
|
||||
|
||||
|
||||
def test_node_query():
|
||||
executed = schema.execute(
|
||||
'mutation a { say(input: {what:"hello", clientMutationId:"1"}) { phrase } }'
|
||||
)
|
||||
assert not executed.errors
|
||||
assert executed.data == {'say': {'phrase': 'hello'}}
|
||||
|
||||
|
||||
# def test_node_query_incorrect_id():
|
||||
# executed = schema.execute(
|
||||
# '{ node(id:"%s") { ... on MyNode { name } } }' % "something:2"
|
||||
# )
|
||||
# assert not executed.errors
|
||||
# assert executed.data == {'node': None}
|
||||
|
||||
# def test_str_schema():
|
||||
# assert str(schema) == """
|
||||
# schema {
|
||||
# query: RootQuery
|
||||
# }
|
||||
|
||||
# type MyNode implements Node {
|
||||
# id: ID!
|
||||
# name: String
|
||||
# }
|
||||
|
||||
# interface Node {
|
||||
# id: ID!
|
||||
# }
|
||||
|
||||
# type RootQuery {
|
||||
# first: String
|
||||
# node(id: ID!): Node
|
||||
# }
|
||||
# """.lstrip()
|
|
@ -11,7 +11,7 @@ from .argument import to_arguments
|
|||
class AbstractField(object):
|
||||
@property
|
||||
def name(self):
|
||||
return self._name or to_camel_case(self.attname)
|
||||
return self._name or self.attname and to_camel_case(self.attname)
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
|
@ -81,7 +81,8 @@ class Field(AbstractField, GraphQLField, OrderedType):
|
|||
# We try to get the resolver from the interfaces
|
||||
if not resolver and issubclass(self.parent, ObjectType):
|
||||
graphql_type = self.parent._meta.graphql_type
|
||||
for interface in graphql_type._provided_interfaces:
|
||||
interfaces = graphql_type._provided_interfaces or []
|
||||
for interface in interfaces:
|
||||
if not isinstance(interface, GrapheneInterfaceType):
|
||||
continue
|
||||
fields = interface.get_fields()
|
||||
|
|
|
@ -9,17 +9,19 @@ from ..utils.props import props
|
|||
|
||||
class MutationMeta(ObjectTypeMeta):
|
||||
|
||||
def construct_field(cls, field_attrs):
|
||||
_construct_field = True
|
||||
|
||||
def construct_field(cls, field_args):
|
||||
resolver = getattr(cls, 'mutate', None)
|
||||
assert resolver, 'All mutations must define a mutate method in it'
|
||||
return partial(Field, cls, args=field_attrs, resolver=resolver)
|
||||
return partial(Field, cls, args=field_args, resolver=resolver)
|
||||
|
||||
def construct(cls, bases, attrs):
|
||||
super(MutationMeta, cls).construct(bases, attrs)
|
||||
if not cls._meta.abstract:
|
||||
if not cls._meta.abstract and cls._construct_field:
|
||||
Input = attrs.pop('Input', None)
|
||||
field_attrs = props(Input) if Input else {}
|
||||
cls.Field = cls.construct_field(field_attrs)
|
||||
field_args = props(Input) if Input else {}
|
||||
cls.Field = cls.construct_field(field_args)
|
||||
return cls
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType):
|
|||
self.check_interfaces()
|
||||
|
||||
def check_interfaces(self):
|
||||
if not self._provided_interfaces:
|
||||
return
|
||||
for interface in self._provided_interfaces:
|
||||
if isinstance(interface, GrapheneInterfaceType):
|
||||
interface.graphene_type.implements(self.graphene_type)
|
||||
|
|
|
@ -97,108 +97,108 @@ def test_parent_container_get_fields():
|
|||
assert fields.keys() == ['field1', 'field2']
|
||||
|
||||
|
||||
# def test_objecttype_as_container_only_args():
|
||||
# container = Container("1", "2")
|
||||
# assert container.field1 == "1"
|
||||
# assert container.field2 == "2"
|
||||
def test_objecttype_as_container_only_args():
|
||||
container = Container("1", "2")
|
||||
assert container.field1 == "1"
|
||||
assert container.field2 == "2"
|
||||
|
||||
|
||||
# def test_objecttype_as_container_args_kwargs():
|
||||
# container = Container("1", field2="2")
|
||||
# assert container.field1 == "1"
|
||||
# assert container.field2 == "2"
|
||||
def test_objecttype_as_container_args_kwargs():
|
||||
container = Container("1", field2="2")
|
||||
assert container.field1 == "1"
|
||||
assert container.field2 == "2"
|
||||
|
||||
|
||||
# def test_objecttype_as_container_few_kwargs():
|
||||
# container = Container(field2="2")
|
||||
# assert container.field2 == "2"
|
||||
def test_objecttype_as_container_few_kwargs():
|
||||
container = Container(field2="2")
|
||||
assert container.field2 == "2"
|
||||
|
||||
|
||||
# def test_objecttype_as_container_all_kwargs():
|
||||
# container = Container(field1="1", field2="2")
|
||||
# assert container.field1 == "1"
|
||||
# assert container.field2 == "2"
|
||||
def test_objecttype_as_container_all_kwargs():
|
||||
container = Container(field1="1", field2="2")
|
||||
assert container.field1 == "1"
|
||||
assert container.field2 == "2"
|
||||
|
||||
|
||||
# def test_objecttype_as_container_extra_args():
|
||||
# with pytest.raises(IndexError) as excinfo:
|
||||
# Container("1", "2", "3")
|
||||
def test_objecttype_as_container_extra_args():
|
||||
with pytest.raises(IndexError) as excinfo:
|
||||
Container("1", "2", "3")
|
||||
|
||||
# assert "Number of args exceeds number of fields" == str(excinfo.value)
|
||||
assert "Number of args exceeds number of fields" == str(excinfo.value)
|
||||
|
||||
|
||||
# def test_objecttype_as_container_invalid_kwargs():
|
||||
# with pytest.raises(TypeError) as excinfo:
|
||||
# Container(unexisting_field="3")
|
||||
def test_objecttype_as_container_invalid_kwargs():
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
Container(unexisting_field="3")
|
||||
|
||||
# assert "'unexisting_field' is an invalid keyword argument for this function" == str(excinfo.value)
|
||||
assert "'unexisting_field' is an invalid keyword argument for this function" == str(excinfo.value)
|
||||
|
||||
|
||||
# def test_objecttype_reuse_graphql_type():
|
||||
# MyGraphQLType = GraphQLObjectType('MyGraphQLType', fields={
|
||||
# 'field': GraphQLField(GraphQLString)
|
||||
# })
|
||||
def test_objecttype_reuse_graphql_type():
|
||||
MyGraphQLType = GraphQLObjectType('MyGraphQLType', fields={
|
||||
'field': GraphQLField(GraphQLString)
|
||||
})
|
||||
|
||||
# class GrapheneObjectType(ObjectType):
|
||||
# class Meta:
|
||||
# graphql_type = MyGraphQLType
|
||||
class GrapheneObjectType(ObjectType):
|
||||
class Meta:
|
||||
graphql_type = MyGraphQLType
|
||||
|
||||
# graphql_type = GrapheneObjectType._meta.graphql_type
|
||||
# assert graphql_type == MyGraphQLType
|
||||
# instance = GrapheneObjectType(field="A")
|
||||
# assert instance.field == "A"
|
||||
graphql_type = GrapheneObjectType._meta.graphql_type
|
||||
assert graphql_type == MyGraphQLType
|
||||
instance = GrapheneObjectType(field="A")
|
||||
assert instance.field == "A"
|
||||
|
||||
|
||||
# def test_objecttype_add_fields_in_reused_graphql_type():
|
||||
# MyGraphQLType = GraphQLObjectType('MyGraphQLType', fields={
|
||||
# 'field': GraphQLField(GraphQLString)
|
||||
# })
|
||||
def test_objecttype_add_fields_in_reused_graphql_type():
|
||||
MyGraphQLType = GraphQLObjectType('MyGraphQLType', fields={
|
||||
'field': GraphQLField(GraphQLString)
|
||||
})
|
||||
|
||||
# with pytest.raises(AssertionError) as excinfo:
|
||||
# class GrapheneObjectType(ObjectType):
|
||||
# field = Field(GraphQLString)
|
||||
with pytest.raises(AssertionError) as excinfo:
|
||||
class GrapheneObjectType(ObjectType):
|
||||
field = Field(GraphQLString)
|
||||
|
||||
# class Meta:
|
||||
# graphql_type = MyGraphQLType
|
||||
class Meta:
|
||||
graphql_type = MyGraphQLType
|
||||
|
||||
# assert """Field "MyGraphQLType.field" can only be mounted in ObjectType or Interface, received GrapheneObjectType.""" == str(excinfo.value)
|
||||
assert """Can't mount Fields in an ObjectType with a defined graphql_type""" == str(excinfo.value)
|
||||
|
||||
|
||||
# def test_objecttype_graphql_interface():
|
||||
# MyInterface = GraphQLInterfaceType('MyInterface', fields={
|
||||
# 'field': GraphQLField(GraphQLString)
|
||||
# })
|
||||
def test_objecttype_graphql_interface():
|
||||
MyInterface = GraphQLInterfaceType('MyInterface', fields={
|
||||
'field': GraphQLField(GraphQLString)
|
||||
})
|
||||
|
||||
# class GrapheneObjectType(ObjectType):
|
||||
# class Meta:
|
||||
# interfaces = [MyInterface]
|
||||
class GrapheneObjectType(ObjectType):
|
||||
class Meta:
|
||||
interfaces = [MyInterface]
|
||||
|
||||
# graphql_type = GrapheneObjectType._meta.graphql_type
|
||||
# assert graphql_type.get_interfaces() == (MyInterface, )
|
||||
# # assert graphql_type.is_type_of(MyInterface, None, None)
|
||||
# fields = graphql_type.get_fields()
|
||||
# assert 'field' in fields
|
||||
graphql_type = GrapheneObjectType._meta.graphql_type
|
||||
assert graphql_type.get_interfaces() == (MyInterface, )
|
||||
# assert graphql_type.is_type_of(MyInterface, None, None)
|
||||
fields = graphql_type.get_fields()
|
||||
assert 'field' in fields
|
||||
|
||||
|
||||
# def test_objecttype_graphene_interface():
|
||||
# class GrapheneInterface(Interface):
|
||||
# name = Field(GraphQLString)
|
||||
# extended = Field(GraphQLString)
|
||||
def test_objecttype_graphene_interface():
|
||||
class GrapheneInterface(Interface):
|
||||
name = Field(GraphQLString)
|
||||
extended = Field(GraphQLString)
|
||||
|
||||
# class GrapheneObjectType(ObjectType):
|
||||
# class Meta:
|
||||
# interfaces = [GrapheneInterface]
|
||||
class GrapheneObjectType(ObjectType):
|
||||
class Meta:
|
||||
interfaces = [GrapheneInterface]
|
||||
|
||||
# field = Field(GraphQLString)
|
||||
field = Field(GraphQLString)
|
||||
|
||||
# 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']
|
||||
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']
|
||||
|
||||
|
||||
# def test_objecttype_graphene_interface_extended():
|
||||
|
|
|
@ -31,7 +31,7 @@ def get_base_fields(cls, bases):
|
|||
if attname in fields:
|
||||
continue
|
||||
field = copy.copy(field)
|
||||
if isinstance(field, Field):
|
||||
if isinstance(field, (Field, InputField)):
|
||||
field.parent = cls
|
||||
fields.add(attname)
|
||||
_fields.append(field)
|
||||
|
|
Loading…
Reference in New Issue
Block a user