Merge branch '0.4.0-cov' of github.com:graphql-python/graphene into 0.4.0-cov

This commit is contained in:
Syrus Akbary 2015-11-11 18:06:39 -08:00
commit a55222e107
10 changed files with 78 additions and 75 deletions

View File

@ -5,6 +5,7 @@ from graphene.contrib.django.fields import (ConnectionOrListField,
DjangoModelField) DjangoModelField)
from graphene.core.fields import (BooleanField, FloatField, IDField, IntField, from graphene.core.fields import (BooleanField, FloatField, IDField, IntField,
StringField) StringField)
from graphene.core.types.scalars import Boolean, Float, ID, Int, String
try: try:
UUIDField = models.UUIDField UUIDField = models.UUIDField
@ -28,12 +29,12 @@ def convert_django_field(field):
@convert_django_field.register(models.URLField) @convert_django_field.register(models.URLField)
@convert_django_field.register(UUIDField) @convert_django_field.register(UUIDField)
def convert_field_to_string(field): def convert_field_to_string(field):
return StringField(description=field.help_text) return String(description=field.help_text)
@convert_django_field.register(models.AutoField) @convert_django_field.register(models.AutoField)
def convert_field_to_id(field): def convert_field_to_id(field):
return IDField(description=field.help_text) return ID(description=field.help_text)
@convert_django_field.register(models.PositiveIntegerField) @convert_django_field.register(models.PositiveIntegerField)
@ -42,23 +43,23 @@ def convert_field_to_id(field):
@convert_django_field.register(models.BigIntegerField) @convert_django_field.register(models.BigIntegerField)
@convert_django_field.register(models.IntegerField) @convert_django_field.register(models.IntegerField)
def convert_field_to_int(field): def convert_field_to_int(field):
return IntField(description=field.help_text) return Int(description=field.help_text)
@convert_django_field.register(models.BooleanField) @convert_django_field.register(models.BooleanField)
def convert_field_to_boolean(field): def convert_field_to_boolean(field):
return BooleanField(description=field.help_text, required=True) return Boolean(description=field.help_text, required=True)
@convert_django_field.register(models.NullBooleanField) @convert_django_field.register(models.NullBooleanField)
def convert_field_to_nullboolean(field): def convert_field_to_nullboolean(field):
return BooleanField(description=field.help_text) return Boolean(description=field.help_text)
@convert_django_field.register(models.DecimalField) @convert_django_field.register(models.DecimalField)
@convert_django_field.register(models.FloatField) @convert_django_field.register(models.FloatField)
def convert_field_to_float(field): def convert_field_to_float(field):
return FloatField(description=field.help_text) return Float(description=field.help_text)
@convert_django_field.register(models.ManyToManyField) @convert_django_field.register(models.ManyToManyField)

View File

@ -1,6 +1,7 @@
from graphene import relay from graphene import relay
from graphene.contrib.django.utils import get_type_for_model, lazy_map from graphene.contrib.django.utils import get_type_for_model, lazy_map
from graphene.core.fields import Field, LazyField, ListField from graphene.core.fields import Field, ListField
from graphene.core.types.base import FieldType
from graphene.relay.utils import is_node from graphene.relay.utils import is_node
@ -8,60 +9,49 @@ class DjangoConnectionField(relay.ConnectionField):
def wrap_resolved(self, value, instance, args, info): def wrap_resolved(self, value, instance, args, info):
schema = info.schema.graphene_schema schema = info.schema.graphene_schema
return lazy_map(value, self.get_object_type(schema)) return lazy_map(value, self.type.get_object_type(schema))
class LazyListField(ListField): class LazyListField(ListField):
def resolve(self, instance, args, info): def resolver(self, instance, args, info):
schema = info.schema.graphene_schema schema = info.schema.graphene_schema
resolved = super(LazyListField, self).resolve(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.get_object_type(schema))
class ConnectionOrListField(LazyField): class ConnectionOrListField(Field):
def get_field(self, schema): def internal_type(self, schema):
model_field = self.field_type model_field = self.type
field_object_type = model_field.get_object_type(schema) field_object_type = model_field.get_object_type(schema)
if is_node(field_object_type): if is_node(field_object_type):
field = DjangoConnectionField(model_field) field = DjangoConnectionField(model_field)
else: else:
field = LazyListField(model_field) field = LazyListField(model_field)
field.contribute_to_class(self.object_type, self.name) field.contribute_to_class(self.object_type, self.name)
return field return field.internal_type(schema)
class DjangoModelField(Field): class DjangoModelField(FieldType):
def __init__(self, model, *args, **kwargs): def __init__(self, model, *args, **kwargs):
super(DjangoModelField, self).__init__(None, *args, **kwargs)
self.model = model self.model = model
super(DjangoModelField, self).__init__(*args, **kwargs)
def resolve(self, instance, args, info):
resolved = super(DjangoModelField, self).resolve(instance, args, info)
schema = info.schema.graphene_schema
_type = self.get_object_type(schema)
assert _type, ("Field %s cannot be retrieved as the "
"ObjectType is not registered by the schema" % (
self.attname
))
return _type(resolved)
def internal_type(self, schema): def internal_type(self, schema):
_type = self.get_object_type(schema) _type = self.get_object_type(schema)
if not _type and self.object_type._meta.only_fields: if not _type and self.parent._meta.only_fields:
raise Exception( raise Exception(
"Model %r is not accessible by the schema. " "Model %r is not accessible by the schema. "
"You can either register the type manually " "You can either register the type manually "
"using @schema.register. " "using @schema.register. "
"Or disable the field %s in %s" % ( "Or disable the field in %s" % (
self.model, self.model,
self.attname, self.parent,
self.object_type
) )
) )
return schema.T(_type) or Field.SKIP return schema.T(_type)
def get_object_type(self, schema): def get_object_type(self, schema):
return get_type_for_model(schema, self.model) return get_type_for_model(schema, self.model)

View File

@ -40,9 +40,9 @@ class Schema(object):
if object_type not in self._types: if object_type not in self._types:
internal_type = object_type.internal_type(self) internal_type = object_type.internal_type(self)
self._types[object_type] = internal_type self._types[object_type] = internal_type
name = getattr(internal_type, 'name', None) is_objecttype = inspect.isclass(object_type) and issubclass(object_type, BaseObjectType)
if name: if is_objecttype:
self._types_names[name] = object_type self.register(object_type)
return self._types[object_type] return self._types[object_type]
else: else:
return object_type return object_type
@ -65,6 +65,10 @@ class Schema(object):
return GraphQLSchema(self, query=self.T(self.query), mutation=self.T(self.mutation)) return GraphQLSchema(self, query=self.T(self.query), mutation=self.T(self.mutation))
def register(self, object_type): def register(self, object_type):
type_name = object_type._meta.type_name
registered_object_type = self._types_names.get(type_name, None)
if registered_object_type:
assert registered_object_type == object_type, 'Type {} already registered with other object type'.format(type_name)
self._types_names[object_type._meta.type_name] = object_type self._types_names[object_type._meta.type_name] = object_type
return object_type return object_type

View File

@ -31,14 +31,12 @@ class Field(OrderedType):
if isinstance(type, six.string_types): if isinstance(type, six.string_types):
type = LazyType(type) type = LazyType(type)
self.required = required self.required = required
if self.required:
type = NonNull(type)
self.type = type self.type = type
self.description = description self.description = description
args = OrderedDict(args or {}, **kwargs) args = OrderedDict(args or {}, **kwargs)
self.arguments = ArgumentsGroup(*args_list, **args) self.arguments = ArgumentsGroup(*args_list, **args)
self.object_type = None self.object_type = None
self.resolver = resolver self.resolver_fn = resolver
self.default = default self.default = default
def contribute_to_class(self, cls, attname): def contribute_to_class(self, cls, attname):
@ -54,11 +52,11 @@ class Field(OrderedType):
@property @property
def resolver(self): def resolver(self):
return self._resolver or self.get_resolver_fn() return self.resolver_fn or self.get_resolver_fn()
@resolver.setter @resolver.setter
def resolver(self, value): def resolver(self, value):
self._resolver = value self.resolver_fn = value
def get_resolver_fn(self): def get_resolver_fn(self):
resolve_fn_name = 'resolve_%s' % self.attname resolve_fn_name = 'resolve_%s' % self.attname
@ -70,6 +68,8 @@ class Field(OrderedType):
return default_getter return default_getter
def get_type(self, schema): def get_type(self, schema):
if self.required:
return NonNull(self.type)
return self.type return self.type
def internal_type(self, schema): def internal_type(self, schema):

View File

@ -1,7 +1,7 @@
from collections import Iterable from collections import Iterable
from graphene.core.fields import Field, IDField from graphene.core.fields import Field, IDField
from graphene.core.types.scalars import String, ID from graphene.core.types.scalars import String, ID, Int
from graphql.core.type import GraphQLArgument, GraphQLID, GraphQLNonNull from graphql.core.type import GraphQLArgument, GraphQLID, GraphQLNonNull
from graphql_relay.connection.arrayconnection import connection_from_list from graphql_relay.connection.arrayconnection import connection_from_list
from graphql_relay.node.node import from_global_id from graphql_relay.node.node import from_global_id
@ -14,8 +14,8 @@ class ConnectionField(Field):
super(ConnectionField, self).__init__(field_type, resolver=resolver, super(ConnectionField, self).__init__(field_type, resolver=resolver,
before=String(), before=String(),
after=String(), after=String(),
first=String(), first=Int(),
last=String(), last=Int(),
description=description, **kwargs) description=description, **kwargs)
self.connection_type = connection_type self.connection_type = connection_type
self.edge_type = edge_type self.edge_type = edge_type
@ -24,17 +24,18 @@ class ConnectionField(Field):
return value return value
def resolve(self, instance, args, info): def resolver(self, instance, args, info):
from graphene.relay.types import PageInfo from graphene.relay.types import PageInfo
schema = info.schema.graphene_schema schema = info.schema.graphene_schema
resolved = super(ConnectionField, self).resolve(instance, args, info) resolved = super(ConnectionField, self).resolver(instance, args, info)
if resolved: if resolved:
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'
node = self.get_object_type(schema) type = schema.T(self.type)
node = schema.objecttype(type)
connection_type = self.get_connection_type(node) connection_type = self.get_connection_type(node)
edge_type = self.get_edge_type(node) edge_type = self.get_edge_type(node)
@ -81,14 +82,16 @@ class NodeField(Field):
return object_type.get_node(_id) return object_type.get_node(_id)
def resolve(self, instance, args, info): def resolver(self, instance, args, info):
global_id = args.get('id') global_id = args.get('id')
return self.id_fetcher(global_id, info) return self.id_fetcher(global_id, info)
class GlobalIDField(IDField): class GlobalIDField(Field):
'''The ID of an object''' '''The ID of an object'''
required = True def __init__(self, *args, **kwargs):
super(GlobalIDField, self).__init__(ID(), *args, **kwargs)
self.required = True
def contribute_to_class(self, cls, name): def contribute_to_class(self, cls, name):
from graphene.relay.utils import is_node, is_node_type from graphene.relay.utils import is_node, is_node_type
@ -96,5 +99,5 @@ class GlobalIDField(IDField):
assert in_node, 'GlobalIDField could only be inside a Node, but got %r' % cls assert in_node, 'GlobalIDField could only be inside a Node, but got %r' % cls
super(GlobalIDField, self).contribute_to_class(cls, name) super(GlobalIDField, self).contribute_to_class(cls, name)
def resolve(self, instance, args, info): def resolver(self, instance, args, info):
return self.object_type.to_global_id(instance, args, info) return self.object_type.to_global_id(instance, args, info)

View File

@ -15,7 +15,7 @@ class MyNode(relay.Node):
@classmethod @classmethod
def get_node(cls, id): def get_node(cls, id):
return MyNode(name='mo') return MyNode(id=id, name='mo')
class Query(graphene.ObjectType): class Query(graphene.ObjectType):
@ -35,6 +35,7 @@ def test_nodefield_query():
query = ''' query = '''
query RebelsShipsQuery { query RebelsShipsQuery {
myNode(id:"TXlOb2RlOjE=") { myNode(id:"TXlOb2RlOjE=") {
id
name name
}, },
allMyNodes (customArg:"1") { allMyNodes (customArg:"1") {
@ -52,6 +53,7 @@ def test_nodefield_query():
''' '''
expected = { expected = {
'myNode': { 'myNode': {
'id': 'TXlOb2RlOjE=',
'name': 'mo' 'name': 'mo'
}, },
'allMyNodes': { 'allMyNodes': {

View File

@ -15,8 +15,9 @@ def assert_conversion(django_field, graphene_field, *args):
field = django_field(*args, help_text='Custom Help Text') field = django_field(*args, help_text='Custom Help Text')
graphene_type = convert_django_field(field) graphene_type = convert_django_field(field)
assert isinstance(graphene_type, graphene_field) assert isinstance(graphene_type, graphene_field)
assert graphene_type.description == 'Custom Help Text' field = graphene_type.as_field()
return graphene_type assert field.description == 'Custom Help Text'
return field
def test_should_unknown_django_field_raise_exception(): def test_should_unknown_django_field_raise_exception():
@ -26,86 +27,86 @@ def test_should_unknown_django_field_raise_exception():
def test_should_date_convert_string(): def test_should_date_convert_string():
assert_conversion(models.DateField, graphene.StringField) assert_conversion(models.DateField, graphene.String)
def test_should_char_convert_string(): def test_should_char_convert_string():
assert_conversion(models.CharField, graphene.StringField) assert_conversion(models.CharField, graphene.String)
def test_should_text_convert_string(): def test_should_text_convert_string():
assert_conversion(models.TextField, graphene.StringField) assert_conversion(models.TextField, graphene.String)
def test_should_email_convert_string(): def test_should_email_convert_string():
assert_conversion(models.EmailField, graphene.StringField) assert_conversion(models.EmailField, graphene.String)
def test_should_slug_convert_string(): def test_should_slug_convert_string():
assert_conversion(models.SlugField, graphene.StringField) assert_conversion(models.SlugField, graphene.String)
def test_should_url_convert_string(): def test_should_url_convert_string():
assert_conversion(models.URLField, graphene.StringField) assert_conversion(models.URLField, graphene.String)
def test_should_auto_convert_id(): def test_should_auto_convert_id():
assert_conversion(models.AutoField, graphene.IDField) assert_conversion(models.AutoField, graphene.ID)
def test_should_positive_integer_convert_int(): def test_should_positive_integer_convert_int():
assert_conversion(models.PositiveIntegerField, graphene.IntField) assert_conversion(models.PositiveIntegerField, graphene.Int)
def test_should_positive_small_convert_int(): def test_should_positive_small_convert_int():
assert_conversion(models.PositiveSmallIntegerField, graphene.IntField) assert_conversion(models.PositiveSmallIntegerField, graphene.Int)
def test_should_small_integer_convert_int(): def test_should_small_integer_convert_int():
assert_conversion(models.SmallIntegerField, graphene.IntField) assert_conversion(models.SmallIntegerField, graphene.Int)
def test_should_big_integer_convert_int(): def test_should_big_integer_convert_int():
assert_conversion(models.BigIntegerField, graphene.IntField) assert_conversion(models.BigIntegerField, graphene.Int)
def test_should_integer_convert_int(): def test_should_integer_convert_int():
assert_conversion(models.IntegerField, graphene.IntField) assert_conversion(models.IntegerField, graphene.Int)
def test_should_boolean_convert_boolean(): def test_should_boolean_convert_boolean():
field = assert_conversion(models.BooleanField, graphene.BooleanField) field = assert_conversion(models.BooleanField, graphene.Boolean)
assert field.required is True assert field.required is True
def test_should_nullboolean_convert_boolean(): def test_should_nullboolean_convert_boolean():
field = assert_conversion(models.NullBooleanField, graphene.BooleanField) field = assert_conversion(models.NullBooleanField, graphene.Boolean)
assert field.required is False assert field.required is False
def test_should_float_convert_float(): def test_should_float_convert_float():
assert_conversion(models.FloatField, graphene.FloatField) assert_conversion(models.FloatField, graphene.Float)
def test_should_manytomany_convert_connectionorlist(): def test_should_manytomany_convert_connectionorlist():
graphene_type = convert_django_field(Reporter._meta.local_many_to_many[0]) graphene_type = convert_django_field(Reporter._meta.local_many_to_many[0])
assert isinstance(graphene_type, ConnectionOrListField) assert isinstance(graphene_type, ConnectionOrListField)
assert isinstance(graphene_type.field_type, DjangoModelField) assert isinstance(graphene_type.type, DjangoModelField)
assert graphene_type.field_type.model == Reporter assert graphene_type.type.model == Reporter
def test_should_manytoone_convert_connectionorlist(): def test_should_manytoone_convert_connectionorlist():
graphene_type = convert_django_field(Reporter.articles.related) graphene_type = convert_django_field(Reporter.articles.related)
assert isinstance(graphene_type, ConnectionOrListField) assert isinstance(graphene_type, ConnectionOrListField)
assert isinstance(graphene_type.field_type, DjangoModelField) assert isinstance(graphene_type.type, DjangoModelField)
assert graphene_type.field_type.model == Article assert graphene_type.type.model == Article
def test_should_onetoone_convert_model(): def test_should_onetoone_convert_model():
field = assert_conversion(models.OneToOneField, DjangoModelField, Article) field = assert_conversion(models.OneToOneField, DjangoModelField, Article)
assert field.model == Article assert field.type.model == Article
def test_should_foreignkey_convert_model(): def test_should_foreignkey_convert_model():
field = assert_conversion(models.ForeignKey, DjangoModelField, Article) field = assert_conversion(models.ForeignKey, DjangoModelField, Article)
assert field.model == Article assert field.type.model == Article

View File

@ -2,7 +2,8 @@
from graphene import Schema from graphene import Schema
from graphene.contrib.django.types import DjangoInterface, DjangoNode from graphene.contrib.django.types import DjangoInterface, DjangoNode
from graphene.core.fields import IntField from graphene.core.fields import IntField, Field
from graphene.core.types.scalars import String, Int
from graphene.relay.fields import GlobalIDField from graphene.relay.fields import GlobalIDField
from graphql.core.type import GraphQLInterfaceType, GraphQLObjectType from graphql.core.type import GraphQLInterfaceType, GraphQLObjectType
from tests.utils import assert_equal_lists from tests.utils import assert_equal_lists
@ -57,7 +58,8 @@ def test_node_idfield():
def test_node_replacedfield(): def test_node_replacedfield():
idfield = Human._meta.fields_map['pub_date'] idfield = Human._meta.fields_map['pub_date']
assert isinstance(idfield, IntField) assert isinstance(idfield, Field)
assert schema.T(idfield).type == schema.T(Int())
def test_interface_resolve_type(): def test_interface_resolve_type():