Django integration finished

This commit is contained in:
Syrus Akbary 2015-11-11 20:02:57 -08:00
parent a55222e107
commit 7073208517
41 changed files with 274 additions and 189 deletions

View File

@ -1,4 +1,5 @@
#!/bin/bash
autoflake ./ -r --remove-unused-variables --remove-all-unused-imports --in-place
autoflake ./ -r --remove-unused-variables --remove-all-unused-imports --in-place
autopep8 ./ -r --in-place
isort -rc .

View File

@ -12,6 +12,7 @@ schema = graphene.Schema(name='Starwars Django Relay Schema')
class Ship(DjangoNode):
class Meta:
model = ShipModel
@ -21,11 +22,13 @@ class Ship(DjangoNode):
class Character(DjangoObjectType):
class Meta:
model = CharacterModel
class Faction(DjangoNode):
class Meta:
model = FactionModel
@ -35,6 +38,7 @@ class Faction(DjangoNode):
class IntroduceShip(relay.ClientIDMutation):
class Input:
ship_name = graphene.StringField(required=True)
faction_id = graphene.StringField(required=True)
@ -48,7 +52,7 @@ class IntroduceShip(relay.ClientIDMutation):
faction_id = input.get('faction_id')
ship = create_ship(ship_name, faction_id)
faction = get_faction(faction_id)
return IntroduceShip(ship=ship, faction=faction)
return IntroduceShip(ship=Ship(ship), faction=Faction(faction))
class Query(graphene.ObjectType):

View File

@ -14,7 +14,6 @@ from graphene.core.types import (
Mutation,
BaseType,
LazyType,
OrderedType,
Argument,
Field,
InputField,
@ -28,7 +27,6 @@ from graphene.core.types import (
)
from graphene.core.fields import (
Field,
StringField,
IntField,
BooleanField,
@ -42,7 +40,7 @@ from graphene.decorators import (
resolve_only_args
)
__all__ = ['Enum', 'Argument', 'String', 'Int', 'ID', 'signals', 'Schema',
'ObjectType', 'Interface', 'Mutation', 'Field', 'StringField',
__all__ = ['Enum', 'Argument', 'String', 'Int', 'Boolean', 'Float', 'ID', 'List', 'NonNull', 'signals', 'Schema',
'BaseType', 'LazyType', 'ObjectType', 'Interface', 'Mutation', 'Field', 'InputField', 'StringField',
'IntField', 'BooleanField', 'IDField', 'ListField', 'NonNullField',
'FloatField', 'resolve_only_args']

View File

@ -3,9 +3,7 @@ from singledispatch import singledispatch
from graphene.contrib.django.fields import (ConnectionOrListField,
DjangoModelField)
from graphene.core.fields import (BooleanField, FloatField, IDField, IntField,
StringField)
from graphene.core.types.scalars import Boolean, Float, ID, Int, String
from graphene.core.types.scalars import ID, Boolean, Float, Int, String
try:
UUIDField = models.UUIDField

View File

@ -1,7 +1,9 @@
from graphene import relay
from graphene.contrib.django.utils import get_type_for_model, lazy_map
from graphene.core.fields import Field, ListField
from graphene.core.exceptions import SkipField
from graphene.core.fields import Field
from graphene.core.types.base import FieldType
from graphene.core.types.definitions import List
from graphene.relay.utils import is_node
@ -12,7 +14,10 @@ class DjangoConnectionField(relay.ConnectionField):
return lazy_map(value, self.type.get_object_type(schema))
class LazyListField(ListField):
class LazyListField(Field):
def get_type(self, schema):
return List(self.type)
def resolver(self, instance, args, info):
schema = info.schema.graphene_schema
@ -51,6 +56,8 @@ class DjangoModelField(FieldType):
self.parent,
)
)
if not _type:
raise SkipField()
return schema.T(_type)
def get_object_type(self, schema):

View File

@ -1,7 +1,6 @@
from django.db import models
from py.test import raises
from pytest import raises
import graphene
from graphene.contrib.django.converter import convert_django_field

View File

@ -1,40 +1,21 @@
from py.test import raises
from pytest import raises
import graphene
from graphene import relay
from graphene.contrib.django import DjangoNode, DjangoObjectType
from tests.utils import assert_equal_lists
from .models import Article, Reporter
def test_should_raise_if_no_model():
with raises(Exception) as excinfo:
class Character1(DjangoObjectType):
pass
assert 'model in the Meta' in str(excinfo.value)
def test_should_raise_if_model_is_invalid():
with raises(Exception) as excinfo:
class Character2(DjangoObjectType):
class Meta:
model = 1
assert 'not a Django model' in str(excinfo.value)
def test_should_raise_if_model_is_invalid():
with raises(Exception) as excinfo:
class ReporterTypeError(DjangoObjectType):
def test_should_query_only_fields():
with raises(Exception):
class ReporterType(DjangoObjectType):
class Meta:
model = Reporter
only_fields = ('articles', )
schema = graphene.Schema(query=ReporterTypeError)
schema = graphene.Schema(query=ReporterType)
query = '''
query ReporterQuery {
articles
@ -44,24 +25,13 @@ def test_should_raise_if_model_is_invalid():
assert not result.errors
def test_should_map_fields_correctly():
class ReporterType2(DjangoObjectType):
class Meta:
model = Reporter
assert_equal_lists(
ReporterType2._meta.fields_map.keys(),
['articles', 'first_name', 'last_name', 'email', 'pets', 'id']
)
def test_should_map_fields():
def test_should_query_well():
class ReporterType(DjangoObjectType):
class Meta:
model = Reporter
class Query2(graphene.ObjectType):
class Query(graphene.ObjectType):
reporter = graphene.Field(ReporterType)
def resolve_reporter(self, *args, **kwargs):
@ -83,53 +53,41 @@ def test_should_map_fields():
'email': ''
}
}
Schema = graphene.Schema(query=Query2)
result = Schema.execute(query)
schema = graphene.Schema(query=Query)
result = schema.execute(query)
assert not result.errors
assert result.data == expected
def test_should_map_only_few_fields():
class Reporter2(DjangoObjectType):
class Meta:
model = Reporter
only_fields = ('id', 'email')
assert_equal_lists(
Reporter2._meta.fields_map.keys(),
['id', 'email']
)
def test_should_node():
class ReporterNodeType(DjangoNode):
class ReporterNode(DjangoNode):
class Meta:
model = Reporter
@classmethod
def get_node(cls, id):
return ReporterNodeType(Reporter(id=2, first_name='Cookie Monster'))
return ReporterNode(Reporter(id=2, first_name='Cookie Monster'))
def resolve_articles(self, *args, **kwargs):
return [ArticleNodeType(Article(headline='Hi!'))]
return [ArticleNode(Article(headline='Hi!'))]
class ArticleNodeType(DjangoNode):
class ArticleNode(DjangoNode):
class Meta:
model = Article
@classmethod
def get_node(cls, id):
return ArticleNodeType(Article(id=1, headline='Article node'))
return ArticleNode(Article(id=1, headline='Article node'))
class Query1(graphene.ObjectType):
class Query(graphene.ObjectType):
node = relay.NodeField()
reporter = graphene.Field(ReporterNodeType)
article = graphene.Field(ArticleNodeType)
reporter = graphene.Field(ReporterNode)
article = graphene.Field(ArticleNode)
def resolve_reporter(self, *args, **kwargs):
return ReporterNodeType(Reporter(id=1, first_name='ABA', last_name='X'))
return ReporterNode(Reporter(id=1, first_name='ABA', last_name='X'))
query = '''
query ReporterQuery {
@ -146,12 +104,12 @@ def test_should_node():
lastName,
email
}
myArticle: node(id:"QXJ0aWNsZU5vZGVUeXBlOjE=") {
myArticle: node(id:"QXJ0aWNsZU5vZGU6MQ==") {
id
... on ReporterNodeType {
... on ReporterNode {
firstName
}
... on ArticleNodeType {
... on ArticleNode {
headline
}
}
@ -159,7 +117,7 @@ def test_should_node():
'''
expected = {
'reporter': {
'id': 'UmVwb3J0ZXJOb2RlVHlwZTox',
'id': 'UmVwb3J0ZXJOb2RlOjE=',
'firstName': 'ABA',
'lastName': 'X',
'email': '',
@ -172,11 +130,11 @@ def test_should_node():
},
},
'myArticle': {
'id': 'QXJ0aWNsZU5vZGVUeXBlOjE=',
'id': 'QXJ0aWNsZU5vZGU6MQ==',
'headline': 'Article node'
}
}
Schema = graphene.Schema(query=Query1)
result = Schema.execute(query)
schema = graphene.Schema(query=Query)
result = schema.execute(query)
assert not result.errors
assert result.data == expected

View File

@ -0,0 +1,45 @@
from py.test import raises
from graphene.contrib.django import DjangoObjectType
from tests.utils import assert_equal_lists
from .models import Reporter
def test_should_raise_if_no_model():
with raises(Exception) as excinfo:
class Character1(DjangoObjectType):
pass
assert 'model in the Meta' in str(excinfo.value)
def test_should_raise_if_model_is_invalid():
with raises(Exception) as excinfo:
class Character2(DjangoObjectType):
class Meta:
model = 1
assert 'not a Django model' in str(excinfo.value)
def test_should_map_fields_correctly():
class ReporterType2(DjangoObjectType):
class Meta:
model = Reporter
assert_equal_lists(
ReporterType2._meta.fields_map.keys(),
['articles', 'first_name', 'last_name', 'email', 'pets', 'id']
)
def test_should_map_only_few_fields():
class Reporter2(DjangoObjectType):
class Meta:
model = Reporter
only_fields = ('id', 'email')
assert_equal_lists(
Reporter2._meta.fields_map.keys(),
['id', 'email']
)

View File

@ -2,14 +2,16 @@
from graphene import Schema
from graphene.contrib.django.types import DjangoInterface, DjangoNode
from graphene.core.fields import IntField, Field
from graphene.core.types.scalars import String, Int
from graphene.core.fields import Field, IntField
from graphene.core.types.scalars import Int
from graphene.relay.fields import GlobalIDField
from graphql.core.type import GraphQLInterfaceType, GraphQLObjectType
from tests.utils import assert_equal_lists
from .models import Article, Reporter
schema = Schema()
class Character(DjangoInterface):
'''Character description'''
@ -17,6 +19,7 @@ class Character(DjangoInterface):
model = Reporter
@schema.register
class Human(DjangoNode):
'''Human description'''
@ -28,14 +31,12 @@ class Human(DjangoNode):
class Meta:
model = Article
schema = Schema()
def test_django_interface():
assert DjangoNode._meta.is_interface is True
def test_pseudo_interface():
def test_pseudo_interface_registered():
object_type = schema.T(Character)
assert Character._meta.is_interface is True
assert isinstance(object_type, GraphQLInterfaceType)

View File

@ -6,7 +6,7 @@ def format_response(response):
def test_client_get_no_query(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
settings.ROOT_URLCONF = 'graphene.contrib.django.tests.test_urls'
response = client.get('/graphql')
json_response = format_response(response)
assert json_response == {'errors': [
@ -14,7 +14,7 @@ def test_client_get_no_query(settings, client):
def test_client_post_no_query(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
settings.ROOT_URLCONF = 'graphene.contrib.django.tests.test_urls'
response = client.post('/graphql', {})
json_response = format_response(response)
assert json_response == {'errors': [
@ -22,7 +22,7 @@ def test_client_post_no_query(settings, client):
def test_client_post_malformed_json(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
settings.ROOT_URLCONF = 'graphene.contrib.django.tests.test_urls'
response = client.post('/graphql', 'MALFORMED', 'application/json')
json_response = format_response(response)
assert json_response == {'errors': [
@ -30,7 +30,7 @@ def test_client_post_malformed_json(settings, client):
def test_client_post_empty_query(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
settings.ROOT_URLCONF = 'graphene.contrib.django.tests.test_urls'
response = client.post(
'/graphql', json.dumps({'query': ''}), 'application/json')
json_response = format_response(response)
@ -39,7 +39,7 @@ def test_client_post_empty_query(settings, client):
def test_client_post_bad_query(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
settings.ROOT_URLCONF = 'graphene.contrib.django.tests.test_urls'
response = client.post(
'/graphql', json.dumps({'query': '{ MALFORMED'}), 'application/json')
json_response = format_response(response)
@ -49,7 +49,7 @@ def test_client_post_bad_query(settings, client):
def test_client_get_good_query(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
settings.ROOT_URLCONF = 'graphene.contrib.django.tests.test_urls'
response = client.get('/graphql', {'query': '{ headline }'})
json_response = format_response(response)
expected_json = {
@ -61,7 +61,7 @@ def test_client_get_good_query(settings, client):
def test_client_get_good_query_with_raise(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
settings.ROOT_URLCONF = 'graphene.contrib.django.tests.test_urls'
response = client.get('/graphql', {'query': '{ raises }'})
json_response = format_response(response)
assert json_response['errors'][0][
@ -70,7 +70,7 @@ def test_client_get_good_query_with_raise(settings, client):
def test_client_post_good_query(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
settings.ROOT_URLCONF = 'graphene.contrib.django.tests.test_urls'
response = client.post(
'/graphql', json.dumps({'query': '{ headline }'}), 'application/json')
json_response = format_response(response)

View File

@ -0,0 +1,2 @@
class SkipField(Exception):
pass

View File

@ -1,15 +1,17 @@
import warnings
from .types.base import FieldType
from .types.field import Field
from .types.scalars import String, Int, Boolean, ID, Float
from .types.definitions import List, NonNull
from .types.field import Field
from .types.scalars import ID, Boolean, Float, Int, String
class DeprecatedField(FieldType):
def __init__(self, *args, **kwargs):
cls = self.__class__
warnings.warn("Using {} is not longer supported".format(cls.__name__), FutureWarning)
warnings.warn("Using {} is not longer supported".format(
cls.__name__), FutureWarning)
if 'resolve' in kwargs:
kwargs['resolver'] = kwargs.pop('resolve')
return super(DeprecatedField, self).__init__(*args, **kwargs)
@ -41,3 +43,7 @@ class ListField(DeprecatedField, List):
class NonNullField(DeprecatedField, NonNull):
pass
__all__ = ['Field', 'StringField', 'IntField', 'BooleanField',
'IDField', 'FloatField', 'ListField', 'NonNullField']

View File

@ -2,13 +2,13 @@ import inspect
from collections import OrderedDict
from graphene import signals
from graphene.core.types.base import BaseType
from graphene.core.types.objecttype import BaseObjectType
from graphql.core.execution.executor import Executor
from graphql.core.execution.middlewares.sync import \
SynchronousExecutionMiddleware
from graphql.core.type import GraphQLSchema as _GraphQLSchema
from graphql.core.utils.introspection_query import introspection_query
from graphene.core.types.base import BaseType
from graphene.core.types.objecttype import BaseObjectType
class GraphQLSchema(_GraphQLSchema):
@ -40,7 +40,8 @@ class Schema(object):
if object_type not in self._types:
internal_type = object_type.internal_type(self)
self._types[object_type] = internal_type
is_objecttype = inspect.isclass(object_type) and issubclass(object_type, BaseObjectType)
is_objecttype = inspect.isclass(
object_type) and issubclass(object_type, BaseObjectType)
if is_objecttype:
self.register(object_type)
return self._types[object_type]
@ -68,7 +69,8 @@ class Schema(object):
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)
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
return object_type

View File

@ -30,7 +30,7 @@ schema = Schema(query=Query, mutation=MyResultMutation)
def test_mutation_input():
assert schema.T(ChangeNumber.arguments).keys() == ['to']
assert list(schema.T(ChangeNumber.arguments).keys()) == ['to']
def test_execute_mutations():

View File

@ -1,16 +1,16 @@
from py.test import raises
from pytest import raises
from graphene.core.fields import Field, NonNullField, StringField
from graphene.core.options import Options
from graphene.core.fields import (BooleanField, Field, FloatField, IDField,
IntField, NonNullField, StringField)
from graphene.core.schema import Schema
from graphene.core.types import ObjectType
from graphql.core.type import (GraphQLBoolean, GraphQLField, GraphQLID,
GraphQLInt, GraphQLNonNull, GraphQLString)
from graphql.core.type import (GraphQLBoolean, GraphQLField, GraphQLFloat,
GraphQLID, GraphQLInt, GraphQLNonNull,
GraphQLString)
class ot(ObjectType):
class MyOt(ObjectType):
def resolve_customdoc(self, *args, **kwargs):
'''Resolver documentation'''
return None
@ -23,53 +23,77 @@ schema = Schema()
def test_field_no_contributed_raises_error():
f = Field(GraphQLString)
with raises(Exception) as excinfo:
with raises(Exception):
schema.T(f)
def test_field_type():
f = Field(GraphQLString)
f.contribute_to_class(ot, 'field_name')
f.contribute_to_class(MyOt, 'field_name')
assert isinstance(schema.T(f), GraphQLField)
assert schema.T(f).type == GraphQLString
def test_field_name_automatic_camelcase():
f = Field(GraphQLString)
f.contribute_to_class(ot, 'field_name')
f.contribute_to_class(MyOt, 'field_name')
assert f.name == 'fieldName'
def test_field_name_use_name_if_exists():
f = Field(GraphQLString, name='my_custom_name')
f.contribute_to_class(ot, 'field_name')
f.contribute_to_class(MyOt, 'field_name')
assert f.name == 'my_custom_name'
def test_stringfield_type():
f = StringField()
f.contribute_to_class(ot, 'field_name')
f.contribute_to_class(MyOt, 'field_name')
assert schema.T(f) == GraphQLString
def test_idfield_type():
f = IDField()
f.contribute_to_class(MyOt, 'field_name')
assert schema.T(f) == GraphQLID
def test_booleanfield_type():
f = BooleanField()
f.contribute_to_class(MyOt, 'field_name')
assert schema.T(f) == GraphQLBoolean
def test_intfield_type():
f = IntField()
f.contribute_to_class(MyOt, 'field_name')
assert schema.T(f) == GraphQLInt
def test_floatfield_type():
f = FloatField()
f.contribute_to_class(MyOt, 'field_name')
assert schema.T(f) == GraphQLFloat
def test_nonnullfield_type():
f = NonNullField(StringField())
f.contribute_to_class(ot, 'field_name')
f.contribute_to_class(MyOt, 'field_name')
assert isinstance(schema.T(f), GraphQLNonNull)
def test_stringfield_type_required():
f = StringField(required=True).as_field()
f.contribute_to_class(ot, 'field_name')
f.contribute_to_class(MyOt, 'field_name')
assert isinstance(schema.T(f), GraphQLField)
assert isinstance(schema.T(f).type, GraphQLNonNull)
def test_field_resolve():
f = StringField(required=True, resolve=lambda *args: 'RESOLVED').as_field()
f.contribute_to_class(ot, 'field_name')
f.contribute_to_class(MyOt, 'field_name')
field_type = schema.T(f)
assert 'RESOLVED' == field_type.resolver(ot, None, None)
assert 'RESOLVED' == field_type.resolver(MyOt, None, None)
def test_field_resolve_type_custom():
@ -123,17 +147,17 @@ def test_field_hash():
def test_field_none_type_raises_error():
s = Schema()
f = Field(None)
f.contribute_to_class(ot, 'field_name')
f.contribute_to_class(MyOt, 'field_name')
with raises(Exception) as excinfo:
s.T(f)
assert str(
excinfo.value) == "Internal type for field ot.field_name is None"
excinfo.value) == "Internal type for field MyOt.field_name is None"
def test_field_str():
f = StringField().as_field()
f.contribute_to_class(ot, 'field_name')
assert str(f) == "ot.field_name"
f.contribute_to_class(MyOt, 'field_name')
assert str(f) == "MyOt.field_name"
def test_field_repr():
@ -143,12 +167,12 @@ def test_field_repr():
def test_field_repr_contributed():
f = StringField().as_field()
f.contribute_to_class(ot, 'field_name')
f.contribute_to_class(MyOt, 'field_name')
assert repr(f) == "<graphene.core.types.field.Field: field_name>"
def test_field_resolve_objecttype_cos():
f = StringField().as_field()
f.contribute_to_class(ot, 'customdoc')
f.contribute_to_class(MyOt, 'customdoc')
field = schema.T(f)
assert field.description == 'Resolver documentation'

View File

@ -1,6 +1,4 @@
from py.test import raises
from pytest import raises
from graphene.core.fields import StringField
from graphene.core.options import Options

View File

@ -1,13 +1,9 @@
from py.test import raises
from pytest import raises
from graphene import Interface, ObjectType, Schema
from graphene.core.fields import Field, ListField, StringField
from graphene.core.types.base import LazyType
from graphql.core import graphql
from graphql.core.type import (GraphQLInterfaceType, GraphQLObjectType,
GraphQLSchema)
from tests.utils import assert_equal_lists
schema = Schema(name='My own schema')

View File

@ -1,6 +1,9 @@
from .objecttype import ObjectTypeMeta, BaseObjectType, ObjectType, Interface, Mutation, InputObjectType
from .base import BaseType, LazyType, OrderedType
from .argument import Argument
from .field import Field, InputField
from .scalars import String, Int, Boolean, ID, Float
from .argument import Argument, ArgumentsGroup, to_arguments
from .definitions import List, NonNull
from .objecttype import ObjectTypeMeta, BaseObjectType, Interface, ObjectType, Mutation, InputObjectType
from .scalars import String, ID, Boolean, Int, Float, Scalar
from .field import Field, InputField
__all__ = ['BaseType', 'LazyType', 'OrderedType', 'Argument', 'ArgumentsGroup', 'to_arguments', 'List', 'NonNull', 'Field', 'InputField',
'Interface', 'BaseObjectType', 'ObjectTypeMeta', 'ObjectType', 'Mutation', 'InputObjectType', 'String', 'ID', 'Boolean', 'Int', 'Float', 'Scalar']

View File

@ -3,11 +3,12 @@ from itertools import chain
from graphql.core.type import GraphQLArgument
from .base import BaseType, OrderedType, ArgumentType
from ...utils import to_camel_case
from .base import ArgumentType, BaseType, OrderedType
class Argument(OrderedType):
def __init__(self, type, description=None, default=None, name=None, _creation_counter=None):
super(Argument, self).__init__(_creation_counter=_creation_counter)
self.name = name
@ -23,6 +24,7 @@ class Argument(OrderedType):
class ArgumentsGroup(BaseType):
def __init__(self, *args, **kwargs):
arguments = to_arguments(*args, **kwargs)
self.arguments = OrderedDict([(arg.name, arg) for arg in arguments])
@ -58,7 +60,8 @@ def to_arguments(*args, **kwargs):
if name:
argument.name = to_camel_case(name)
assert argument.name, 'Argument in field must have a name'
assert argument.name not in arguments, 'Found more than one Argument with same name {}'.format(argument.name)
assert argument.name not in arguments, 'Found more than one Argument with same name {}'.format(
argument.name)
arguments[argument.name] = argument
return sorted(arguments.values())

View File

@ -1,8 +1,10 @@
import six
from functools import total_ordering
import six
class BaseType(object):
@classmethod
def internal_type(cls, schema):
return getattr(cls, 'T', None)
@ -16,6 +18,7 @@ class MountType(BaseType):
class LazyType(MountType):
def __init__(self, type):
self.type = type
@ -57,13 +60,13 @@ class OrderedType(MountType):
def __lt__(self, other):
# This is needed because bisect does not take a comparison function.
if type(self) == type(other):
if isinstance(other, OrderedType):
return self.creation_counter < other.creation_counter
return NotImplemented
def __gt__(self, other):
# This is needed because bisect does not take a comparison function.
if type(self) == type(other):
if isinstance(other, OrderedType):
return self.creation_counter > other.creation_counter
return NotImplemented
@ -72,6 +75,7 @@ class OrderedType(MountType):
class MirroredType(OrderedType):
def __init__(self, *args, **kwargs):
_creation_counter = kwargs.pop('_creation_counter', None)
super(MirroredType, self).__init__(_creation_counter=_creation_counter)
@ -80,12 +84,14 @@ class MirroredType(OrderedType):
class ArgumentType(MirroredType):
def as_argument(self):
from .argument import Argument
return Argument(self, _creation_counter=self.creation_counter, *self.args, **self.kwargs)
class FieldType(MirroredType):
def contribute_to_class(self, cls, name):
from ..types import BaseObjectType, InputObjectType
if issubclass(cls, InputObjectType):

View File

@ -1,12 +1,14 @@
import six
from graphql.core.type import (GraphQLList, GraphQLNonNull)
from .base import MountType, MountedType, LazyType
from graphql.core.type import GraphQLList, GraphQLNonNull
from .base import LazyType, MountedType, MountType
class OfType(MountedType):
def __init__(self, of_type, *args, **kwargs):
if isinstance(of_type, six.string_types) and of_type != 'self':
if isinstance(of_type, six.string_types):
of_type = LazyType(of_type)
self.of_type = of_type
super(OfType, self).__init__(*args, **kwargs)

View File

@ -1,14 +1,15 @@
import six
from collections import OrderedDict
from functools import wraps
import six
from graphql.core.type import GraphQLField, GraphQLInputObjectField
from .base import MountType, LazyType, OrderedType
from .argument import ArgumentsGroup
from .definitions import NonNull
from ...utils import to_camel_case, ProxySnakeDict
from ...utils import ProxySnakeDict, to_camel_case
from ..types import BaseObjectType, InputObjectType
from .argument import ArgumentsGroup
from .base import LazyType, MountType, OrderedType
from .definitions import NonNull
def make_args_snake_case(resolver):
@ -24,6 +25,7 @@ class Empty(object):
class Field(OrderedType):
def __init__(self, type, description=None, args=None, name=None, resolver=None, required=False, default=None, *args_list, **kwargs):
_creation_counter = kwargs.pop('_creation_counter', None)
super(Field, self).__init__(_creation_counter=_creation_counter)
@ -40,7 +42,8 @@ class Field(OrderedType):
self.default = default
def contribute_to_class(self, cls, attname):
assert issubclass(cls, BaseObjectType), 'Field {} cannot be mounted in {}'.format(self, cls)
assert issubclass(
cls, BaseObjectType), 'Field {} cannot be mounted in {}'.format(self, cls)
if not self.name:
self.name = to_camel_case(attname)
self.attname = attname
@ -104,11 +107,18 @@ class Field(OrderedType):
""" Return "object_type.field_name". """
return '%s.%s' % (self.object_type.__name__, self.attname)
def __eq__(self, other):
eq = super(Field, self).__eq__(other)
if type(self) == type(other):
return eq and self.object_type == other.object_type
return NotImplemented
def __hash__(self):
return hash((self.creation_counter, self.object_type))
class InputField(OrderedType):
def __init__(self, type, description=None, default=None, name=None, _creation_counter=None, required=False):
super(InputField, self).__init__(_creation_counter=_creation_counter)
self.name = name
@ -119,7 +129,8 @@ class InputField(OrderedType):
self.default = default
def contribute_to_class(self, cls, attname):
assert issubclass(cls, InputObjectType), 'InputField {} cannot be mounted in {}'.format(self, cls)
assert issubclass(
cls, InputObjectType), 'InputField {} cannot be mounted in {}'.format(self, cls)
if not self.name:
self.name = to_camel_case(attname)
self.attname = attname

View File

@ -6,9 +6,10 @@ from functools import partial
import six
from graphene import signals
from graphene.core.exceptions import SkipField
from graphene.core.options import Options
from graphene.core.types.base import BaseType
from graphene.core.types.argument import ArgumentsGroup
from graphene.core.types.base import BaseType
from graphql.core.type import (GraphQLArgument, GraphQLInputObjectType,
GraphQLInterfaceType, GraphQLObjectType)
@ -176,23 +177,32 @@ class BaseObjectType(BaseType):
@classmethod
def internal_type(cls, schema):
fields = lambda: OrderedDict([(f.name, schema.T(f))
for f in cls._meta.fields])
if cls._meta.is_interface:
return GraphQLInterfaceType(
cls._meta.type_name,
description=cls._meta.description,
resolve_type=partial(cls.resolve_type, schema),
fields=fields
fields=partial(cls.get_fields, schema)
)
return GraphQLObjectType(
cls._meta.type_name,
description=cls._meta.description,
interfaces=[schema.T(i) for i in cls._meta.interfaces],
fields=fields,
fields=partial(cls.get_fields, schema),
is_type_of=getattr(cls, 'is_type_of', None)
)
@classmethod
def get_fields(cls, schema):
fields = []
for field in cls._meta.fields:
try:
fields.append((field.name, schema.T(field)))
except SkipField:
continue
return OrderedDict(fields)
class Interface(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
pass
@ -203,14 +213,16 @@ class ObjectType(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
class Mutation(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
@classmethod
def _prepare_class(cls):
input_class = getattr(cls, 'Input', None)
if input_class:
items = dict(input_class.__dict__)
items = dict(vars(input_class))
items.pop('__dict__', None)
items.pop('__doc__', None)
items.pop('__module__', None)
items.pop('__weakref__', None)
arguments = ArgumentsGroup(**items)
cls.add_to_class('arguments', arguments)
delattr(cls, 'Input')
@ -221,6 +233,7 @@ class Mutation(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
class InputObjectType(ObjectType):
@classmethod
def internal_type(cls, schema):
fields = lambda: OrderedDict([(f.name, schema.T(f))

View File

@ -25,6 +25,7 @@ class Float(MountedType):
class Scalar(MountedType):
@classmethod
def internal_type(cls, schema):
serialize = getattr(cls, 'serialize')

View File

@ -1,10 +1,11 @@
from pytest import raises
from graphene.core.schema import Schema
from graphene.core.types import ObjectType
from graphql.core.type import GraphQLArgument
from ..argument import Argument, to_arguments
from ..scalars import String
from graphene.core.types import ObjectType
from graphene.core.schema import Schema
def test_argument_internal_type():
@ -26,7 +27,8 @@ def test_to_arguments():
other_kwarg=String(),
)
assert [a.name for a in arguments] == ['myArg', 'otherArg', 'myKwarg', 'otherKwarg']
assert [a.name for a in arguments] == [
'myArg', 'otherArg', 'myKwarg', 'otherKwarg']
def test_to_arguments_no_name():

View File

@ -1,9 +1,10 @@
from mock import patch
from ..base import OrderedType, MountedType
from ..field import Field, InputField
from graphene.core.types import InputObjectType, ObjectType
from ..argument import Argument
from graphene.core.types import ObjectType, InputObjectType
from ..base import MountedType, OrderedType
from ..field import Field, InputField
def test_orderedtype_equal():
@ -26,14 +27,16 @@ def test_type_as_field_called(Field):
resolver = lambda x: x
a = MountedType(2, description='A', resolver=resolver)
a.as_field()
Field.assert_called_with(a, 2, _creation_counter=a.creation_counter, description='A', resolver=resolver)
Field.assert_called_with(
a, 2, _creation_counter=a.creation_counter, description='A', resolver=resolver)
@patch('graphene.core.types.argument.Argument')
def test_type_as_argument_called(Argument):
a = MountedType(2, description='A')
a.as_argument()
Argument.assert_called_with(a, 2, _creation_counter=a.creation_counter, description='A')
Argument.assert_called_with(
a, 2, _creation_counter=a.creation_counter, description='A')
def test_type_as_field():

View File

@ -1,8 +1,8 @@
from graphql.core.type import (GraphQLList, GraphQLString, GraphQLNonNull)
from graphene.core.schema import Schema
from graphql.core.type import GraphQLList, GraphQLNonNull, GraphQLString
from ..definitions import List, NonNull
from ..scalars import String
from graphene.core.schema import Schema
schema = Schema()

View File

@ -1,11 +1,12 @@
from graphql.core.type import GraphQLField, GraphQLInputObjectField, GraphQLString
from graphene.core.schema import Schema
from graphene.core.types import InputObjectType, ObjectType
from graphql.core.type import (GraphQLField, GraphQLInputObjectField,
GraphQLString)
from ..field import Field, InputField
from ..scalars import String
from ..base import LazyType
from ..definitions import List
from graphene.core.types import ObjectType, InputObjectType
from graphene.core.schema import Schema
from ..field import Field, InputField
from ..scalars import String
def test_field_internal_type():
@ -81,8 +82,10 @@ def test_field_string_reference():
class MyObjectType(ObjectType):
my_field = field
schema = Schema(query=MyObjectType)
assert isinstance(field.type, LazyType)
assert field.type.type_str == 'MyObjectType'
assert schema.T(field.type) == schema.T(MyObjectType)
def test_field_custom_arguments():

View File

@ -1,8 +1,8 @@
from graphene.core.schema import Schema
from graphql.core.type import (GraphQLBoolean, GraphQLFloat, GraphQLID,
GraphQLInt, GraphQLScalarType, GraphQLString)
from ..scalars import String, Int, Boolean, ID, Float, Scalar
from graphene.core.schema import Schema
from ..scalars import ID, Boolean, Float, Int, Scalar, String
schema = Schema()

View File

@ -1,8 +1,7 @@
from collections import Iterable
from graphene.core.fields import Field, IDField
from graphene.core.types.scalars import String, ID, Int
from graphql.core.type import GraphQLArgument, GraphQLID, GraphQLNonNull
from graphene.core.fields import Field
from graphene.core.types.scalars import ID, Int, String
from graphql_relay.connection.arrayconnection import connection_from_list
from graphql_relay.node.node import from_global_id
@ -23,7 +22,6 @@ class ConnectionField(Field):
def wrap_resolved(self, value, instance, args, info):
return value
def resolver(self, instance, args, info):
from graphene.relay.types import PageInfo
schema = info.schema.graphene_schema
@ -59,7 +57,7 @@ class ConnectionField(Field):
assert is_node(node), 'Only nodes have connections.'
schema.register(node)
connection_type = self.get_connection_type(node)
return schema.T(connection_type)
return connection_type
class NodeField(Field):
@ -67,7 +65,8 @@ class NodeField(Field):
def __init__(self, object_type=None, *args, **kwargs):
from graphene.relay.types import Node
id = kwargs.pop('id', None) or ID(description='The ID of an object')
super(NodeField, self).__init__(object_type or Node, id=id, *args, **kwargs)
super(NodeField, self).__init__(
object_type or Node, id=id, *args, **kwargs)
self.field_object_type = object_type
def id_fetcher(self, global_id, info):
@ -89,6 +88,7 @@ class NodeField(Field):
class GlobalIDField(Field):
'''The ID of an object'''
def __init__(self, *args, **kwargs):
super(GlobalIDField, self).__init__(ID(), *args, **kwargs)
self.required = True
@ -100,4 +100,4 @@ class GlobalIDField(Field):
super(GlobalIDField, self).contribute_to_class(cls, name)
def resolver(self, instance, args, info):
return self.object_type.to_global_id(instance, args, info)
return instance.to_global_id()

View File

View File

@ -1,8 +1,6 @@
import graphene
from graphene import relay
from graphene.core.schema import Schema
from graphene.core.types import InputObjectType
from graphql.core.type import GraphQLInputObjectField
my_id = 0
@ -35,7 +33,7 @@ schema = Schema(query=Query, mutation=MyResultMutation)
def test_mutation_arguments():
assert ChangeNumber.arguments
assert list(ChangeNumber.arguments) == ['input']
_input = ChangeNumber.arguments['input']
ChangeNumber.arguments['input']
# inner_type = _input.get_object_type(schema)
# client_mutation_id_field = inner_type._meta.fields_map[

View File

@ -1,8 +1,8 @@
from graphene.core.fields import BooleanField, Field, ListField, StringField
from graphene.core.types import (InputObjectType, Interface, Mutation,
ObjectType)
from graphene.core.types.base import LazyType
from graphene.core.types.argument import ArgumentsGroup
from graphene.core.types.base import LazyType
from graphene.core.types.definitions import NonNull
from graphene.relay.fields import GlobalIDField
from graphene.utils import memoize
@ -74,10 +74,9 @@ class BaseNode(object):
assert hasattr(
cls, 'get_node'), 'get_node classmethod not found in %s Node' % cls
@classmethod
def to_global_id(cls, instance, args, info):
type_name = cls._meta.type_name
return to_global_id(type_name, instance.id)
def to_global_id(self):
type_name = self._meta.type_name
return to_global_id(type_name, self.id)
connection_type = Connection
edge_type = Edge
@ -105,13 +104,16 @@ class ClientIDMutation(Mutation):
@classmethod
def _prepare_class(cls):
Input = getattr(cls, 'Input', None)
if Input:
input_class = getattr(cls, 'Input', None)
if input_class:
assert hasattr(
cls, 'mutate_and_get_payload'), 'You have to implement mutate_and_get_payload'
items = dict(Input.__dict__)
items = dict(vars(input_class))
items.pop('__dict__', None)
items.pop('__doc__', None)
items.pop('__module__', None)
items.pop('__weakref__', None)
new_input_type = type('{}Input'.format(
cls._meta.type_name), (MutationInputType, ), items)
cls.add_to_class('input_type', new_input_type)

View File

@ -2,7 +2,6 @@ SECRET_KEY = 1
INSTALLED_APPS = [
'examples.starwars_django',
'tests.contrib_django',
]
DATABASES = {