mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-26 11:33:55 +03:00
Merge branch 'master' of github.com:graphql-python/graphene
This commit is contained in:
commit
1795ed516c
|
@ -17,7 +17,7 @@ class Ship(DjangoNode):
|
||||||
model = ShipModel
|
model = ShipModel
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_node(cls, id):
|
def get_node(cls, id, info):
|
||||||
return Ship(get_ship(id))
|
return Ship(get_ship(id))
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class Faction(DjangoNode):
|
||||||
model = FactionModel
|
model = FactionModel
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_node(cls, id):
|
def get_node(cls, id, info):
|
||||||
return Faction(get_faction(id))
|
return Faction(get_faction(id))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ class Ship(relay.Node):
|
||||||
name = graphene.String(description='The name of the ship.')
|
name = graphene.String(description='The name of the ship.')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_node(cls, id):
|
def get_node(cls, id, info):
|
||||||
return get_ship(id)
|
return get_ship(id)
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class Faction(relay.Node):
|
||||||
return [get_ship(ship_id) for ship_id in self.ships]
|
return [get_ship(ship_id) for ship_id in self.ships]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_node(cls, id):
|
def get_node(cls, id, info):
|
||||||
return get_faction(id)
|
return get_faction(id)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,7 @@ from .utils import get_type_for_model, lazy_map
|
||||||
class DjangoConnectionField(ConnectionField):
|
class DjangoConnectionField(ConnectionField):
|
||||||
|
|
||||||
def wrap_resolved(self, value, instance, args, info):
|
def wrap_resolved(self, value, instance, args, info):
|
||||||
schema = info.schema.graphene_schema
|
return lazy_map(value, self.type)
|
||||||
return lazy_map(value, self.type.get_object_type(schema))
|
|
||||||
|
|
||||||
|
|
||||||
class LazyListField(Field):
|
class LazyListField(Field):
|
||||||
|
@ -20,9 +19,8 @@ class LazyListField(Field):
|
||||||
return List(self.type)
|
return List(self.type)
|
||||||
|
|
||||||
def resolver(self, instance, args, info):
|
def resolver(self, instance, args, info):
|
||||||
schema = info.schema.graphene_schema
|
|
||||||
resolved = super(LazyListField, self).resolver(instance, args, info)
|
resolved = super(LazyListField, self).resolver(instance, args, info)
|
||||||
return lazy_map(resolved, self.get_object_type(schema))
|
return lazy_map(resolved, self.type)
|
||||||
|
|
||||||
|
|
||||||
class ConnectionOrListField(Field):
|
class ConnectionOrListField(Field):
|
||||||
|
@ -30,12 +28,14 @@ class ConnectionOrListField(Field):
|
||||||
def internal_type(self, schema):
|
def internal_type(self, schema):
|
||||||
model_field = self.type
|
model_field = self.type
|
||||||
field_object_type = model_field.get_object_type(schema)
|
field_object_type = model_field.get_object_type(schema)
|
||||||
|
if not field_object_type:
|
||||||
|
raise SkipField()
|
||||||
if is_node(field_object_type):
|
if is_node(field_object_type):
|
||||||
field = DjangoConnectionField(model_field)
|
field = DjangoConnectionField(field_object_type)
|
||||||
else:
|
else:
|
||||||
field = LazyListField(model_field)
|
field = LazyListField(field_object_type)
|
||||||
field.contribute_to_class(self.object_type, self.name)
|
field.contribute_to_class(self.object_type, self.name)
|
||||||
return field.internal_type(schema)
|
return schema.T(field)
|
||||||
|
|
||||||
|
|
||||||
class DjangoModelField(FieldType):
|
class DjangoModelField(FieldType):
|
||||||
|
|
|
@ -66,7 +66,7 @@ def test_should_node():
|
||||||
model = Reporter
|
model = Reporter
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_node(cls, id):
|
def get_node(cls, id, info):
|
||||||
return ReporterNode(Reporter(id=2, first_name='Cookie Monster'))
|
return ReporterNode(Reporter(id=2, first_name='Cookie Monster'))
|
||||||
|
|
||||||
def resolve_articles(self, *args, **kwargs):
|
def resolve_articles(self, *args, **kwargs):
|
||||||
|
@ -78,7 +78,7 @@ def test_should_node():
|
||||||
model = Article
|
model = Article
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_node(cls, id):
|
def get_node(cls, id, info):
|
||||||
return ArticleNode(Article(id=1, headline='Article node'))
|
return ArticleNode(Article(id=1, headline='Article node'))
|
||||||
|
|
||||||
class Query(graphene.ObjectType):
|
class Query(graphene.ObjectType):
|
||||||
|
|
|
@ -10,12 +10,12 @@ from ..core.types.scalars import ID, Int, String
|
||||||
|
|
||||||
class ConnectionField(Field):
|
class ConnectionField(Field):
|
||||||
|
|
||||||
def __init__(self, field_type, resolver=None, description='',
|
def __init__(self, type, resolver=None, description='',
|
||||||
connection_type=None, edge_type=None, **kwargs):
|
connection_type=None, edge_type=None, **kwargs):
|
||||||
super(
|
super(
|
||||||
ConnectionField,
|
ConnectionField,
|
||||||
self).__init__(
|
self).__init__(
|
||||||
field_type,
|
type,
|
||||||
resolver=resolver,
|
resolver=resolver,
|
||||||
before=String(),
|
before=String(),
|
||||||
after=String(),
|
after=String(),
|
||||||
|
@ -38,7 +38,6 @@ class ConnectionField(Field):
|
||||||
resolved = self.wrap_resolved(resolved, instance, args, info)
|
resolved = self.wrap_resolved(resolved, instance, args, info)
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
resolved, Iterable), 'Resolved value from the connection field have to be iterable'
|
resolved, Iterable), 'Resolved value from the connection field have to be iterable'
|
||||||
|
|
||||||
type = schema.T(self.type)
|
type = schema.T(self.type)
|
||||||
node = schema.objecttype(type)
|
node = schema.objecttype(type)
|
||||||
connection_type = self.get_connection_type(node)
|
connection_type = self.get_connection_type(node)
|
||||||
|
@ -56,7 +55,8 @@ class ConnectionField(Field):
|
||||||
return connection_type.for_node(node, edge_type=edge_type)
|
return connection_type.for_node(node, edge_type=edge_type)
|
||||||
|
|
||||||
def get_edge_type(self, node):
|
def get_edge_type(self, node):
|
||||||
return self.edge_type or node.get_edge_type()
|
edge_type = self.edge_type or node.get_edge_type()
|
||||||
|
return edge_type.for_node(node)
|
||||||
|
|
||||||
def get_type(self, schema):
|
def get_type(self, schema):
|
||||||
from graphene.relay.utils import is_node
|
from graphene.relay.utils import is_node
|
||||||
|
@ -65,6 +65,7 @@ class ConnectionField(Field):
|
||||||
assert is_node(node), 'Only nodes have connections.'
|
assert is_node(node), 'Only nodes have connections.'
|
||||||
schema.register(node)
|
schema.register(node)
|
||||||
connection_type = self.get_connection_type(node)
|
connection_type = self.get_connection_type(node)
|
||||||
|
|
||||||
return connection_type
|
return connection_type
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,7 +92,7 @@ class NodeField(Field):
|
||||||
object_type != self.field_object_type):
|
object_type != self.field_object_type):
|
||||||
return
|
return
|
||||||
|
|
||||||
return object_type.get_node(_id)
|
return object_type.get_node(_id, info)
|
||||||
|
|
||||||
def resolver(self, instance, args, info):
|
def resolver(self, instance, args, info):
|
||||||
global_id = args.get('id')
|
global_id = args.get('id')
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import pytest
|
||||||
from graphql.core.type import GraphQLID, GraphQLNonNull
|
from graphql.core.type import GraphQLID, GraphQLNonNull
|
||||||
|
|
||||||
import graphene
|
import graphene
|
||||||
|
@ -15,12 +16,22 @@ class MyNode(relay.Node):
|
||||||
name = graphene.String()
|
name = graphene.String()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_node(cls, id):
|
def get_node(cls, id, info):
|
||||||
return MyNode(id=id, name='mo')
|
return MyNode(id=id, name='mo')
|
||||||
|
|
||||||
|
|
||||||
|
class SpecialNode(relay.Node):
|
||||||
|
value = graphene.String()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_node(cls, id, info):
|
||||||
|
value = "!!!" if info.request_context.get('is_special') else "???"
|
||||||
|
return SpecialNode(id=id, value=value)
|
||||||
|
|
||||||
|
|
||||||
class Query(graphene.ObjectType):
|
class Query(graphene.ObjectType):
|
||||||
my_node = relay.NodeField(MyNode)
|
my_node = relay.NodeField(MyNode)
|
||||||
|
special_node = relay.NodeField(SpecialNode)
|
||||||
all_my_nodes = relay.ConnectionField(
|
all_my_nodes = relay.ConnectionField(
|
||||||
MyNode, connection_type=MyConnection, customArg=graphene.String())
|
MyNode, connection_type=MyConnection, customArg=graphene.String())
|
||||||
|
|
||||||
|
@ -79,6 +90,28 @@ def test_nodefield_query():
|
||||||
assert result.data == expected
|
assert result.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('specialness,value', [(True, '!!!'), (False, '???')])
|
||||||
|
def test_get_node_info(specialness, value):
|
||||||
|
query = '''
|
||||||
|
query ValueQuery {
|
||||||
|
specialNode(id:"U3BlY2lhbE5vZGU6Mg==") {
|
||||||
|
id
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
'specialNode': {
|
||||||
|
'id': 'U3BlY2lhbE5vZGU6Mg==',
|
||||||
|
'value': value,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
result = schema.execute(query, request_context={'is_special': specialness})
|
||||||
|
assert not result.errors
|
||||||
|
assert result.data == expected
|
||||||
|
|
||||||
|
|
||||||
def test_nodeidfield():
|
def test_nodeidfield():
|
||||||
id_field = MyNode._meta.fields_map['id']
|
id_field = MyNode._meta.fields_map['id']
|
||||||
id_field_type = schema.T(id_field)
|
id_field_type = schema.T(id_field)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from pytest import raises
|
from pytest import raises
|
||||||
|
from graphql.core.type import GraphQLList
|
||||||
|
|
||||||
import graphene
|
import graphene
|
||||||
from graphene import relay
|
from graphene import relay
|
||||||
|
@ -31,3 +32,15 @@ def test_node_should_have_same_connection_always():
|
||||||
|
|
||||||
def test_node_should_have_id_field():
|
def test_node_should_have_id_field():
|
||||||
assert 'id' in OtherNode._meta.fields_map
|
assert 'id' in OtherNode._meta.fields_map
|
||||||
|
|
||||||
|
|
||||||
|
def test_node_connection_should_have_edge():
|
||||||
|
connection = relay.Connection.for_node(OtherNode)
|
||||||
|
edge = relay.Edge.for_node(OtherNode)
|
||||||
|
connection_type = schema.T(connection)
|
||||||
|
connection_fields = connection_type.get_fields()
|
||||||
|
assert 'edges' in connection_fields
|
||||||
|
assert 'pageInfo' in connection_fields
|
||||||
|
edges_type = connection_fields['edges'].type
|
||||||
|
assert isinstance(edges_type, GraphQLList)
|
||||||
|
assert edges_type.of_type == schema.T(edge)
|
||||||
|
|
|
@ -3,7 +3,6 @@ from graphql_relay.node.node import to_global_id
|
||||||
from ..core.types import (Boolean, Field, InputObjectType, Interface, List,
|
from ..core.types import (Boolean, Field, InputObjectType, Interface, List,
|
||||||
Mutation, ObjectType, String)
|
Mutation, ObjectType, String)
|
||||||
from ..core.types.argument import ArgumentsGroup
|
from ..core.types.argument import ArgumentsGroup
|
||||||
from ..core.types.base import LazyType
|
|
||||||
from ..core.types.definitions import NonNull
|
from ..core.types.definitions import NonNull
|
||||||
from ..utils import memoize
|
from ..utils import memoize
|
||||||
from .fields import GlobalIDField
|
from .fields import GlobalIDField
|
||||||
|
@ -24,11 +23,6 @@ class PageInfo(ObjectType):
|
||||||
|
|
||||||
class Edge(ObjectType):
|
class Edge(ObjectType):
|
||||||
'''An edge in a connection.'''
|
'''An edge in a connection.'''
|
||||||
class Meta:
|
|
||||||
type_name = 'DefaultEdge'
|
|
||||||
|
|
||||||
node = Field(LazyType(lambda object_type: object_type.node_type),
|
|
||||||
description='The item at the end of the edge')
|
|
||||||
cursor = String(
|
cursor = String(
|
||||||
required=True, description='A cursor for use in pagination')
|
required=True, description='A cursor for use in pagination')
|
||||||
|
|
||||||
|
@ -37,10 +31,11 @@ class Edge(ObjectType):
|
||||||
def for_node(cls, node):
|
def for_node(cls, node):
|
||||||
from graphene.relay.utils import is_node
|
from graphene.relay.utils import is_node
|
||||||
assert is_node(node), 'ObjectTypes in a edge have to be Nodes'
|
assert is_node(node), 'ObjectTypes in a edge have to be Nodes'
|
||||||
|
node_field = Field(node, description='The item at the end of the edge')
|
||||||
return type(
|
return type(
|
||||||
'%s%s' % (node._meta.type_name, cls._meta.type_name),
|
'%s%s' % (node._meta.type_name, cls._meta.type_name),
|
||||||
(cls,),
|
(cls,),
|
||||||
{'node_type': node})
|
{'node_type': node, 'node': node_field})
|
||||||
|
|
||||||
|
|
||||||
class Connection(ObjectType):
|
class Connection(ObjectType):
|
||||||
|
@ -50,8 +45,6 @@ class Connection(ObjectType):
|
||||||
|
|
||||||
page_info = Field(PageInfo, required=True,
|
page_info = Field(PageInfo, required=True,
|
||||||
description='The Information to aid in pagination')
|
description='The Information to aid in pagination')
|
||||||
edges = List(LazyType(lambda object_type: object_type.edge_type),
|
|
||||||
description='Information to aid in pagination.')
|
|
||||||
|
|
||||||
_connection_data = None
|
_connection_data = None
|
||||||
|
|
||||||
|
@ -59,12 +52,13 @@ class Connection(ObjectType):
|
||||||
@memoize
|
@memoize
|
||||||
def for_node(cls, node, edge_type=None):
|
def for_node(cls, node, edge_type=None):
|
||||||
from graphene.relay.utils import is_node
|
from graphene.relay.utils import is_node
|
||||||
edge_type = edge_type or Edge
|
edge_type = edge_type or Edge.for_node(node)
|
||||||
assert is_node(node), 'ObjectTypes in a connection have to be Nodes'
|
assert is_node(node), 'ObjectTypes in a connection have to be Nodes'
|
||||||
|
edges = List(edge_type, description='Information to aid in pagination.')
|
||||||
return type(
|
return type(
|
||||||
'%s%s' % (node._meta.type_name, cls._meta.type_name),
|
'%s%s' % (node._meta.type_name, cls._meta.type_name),
|
||||||
(cls,),
|
(cls,),
|
||||||
{'edge_type': edge_type.for_node(node)})
|
{'edge_type': edge_type, 'edges': edges})
|
||||||
|
|
||||||
def set_connection_data(self, data):
|
def set_connection_data(self, data):
|
||||||
self._connection_data = data
|
self._connection_data = data
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -24,7 +24,7 @@ class PyTest(TestCommand):
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='graphene',
|
name='graphene',
|
||||||
version='0.4.0',
|
version='0.4.0.1',
|
||||||
|
|
||||||
description='Graphene: Python DSL for GraphQL',
|
description='Graphene: Python DSL for GraphQL',
|
||||||
long_description=open('README.rst').read(),
|
long_description=open('README.rst').read(),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user