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 #!/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 . isort -rc .

View File

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

View File

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

View File

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

View File

@ -1,7 +1,9 @@
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, ListField from graphene.core.exceptions import SkipField
from graphene.core.fields import Field
from graphene.core.types.base import FieldType from graphene.core.types.base import FieldType
from graphene.core.types.definitions import List
from graphene.relay.utils import is_node 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)) 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): def resolver(self, instance, args, info):
schema = info.schema.graphene_schema schema = info.schema.graphene_schema
@ -51,6 +56,8 @@ class DjangoModelField(FieldType):
self.parent, self.parent,
) )
) )
if not _type:
raise SkipField()
return schema.T(_type) return schema.T(_type)
def get_object_type(self, schema): def get_object_type(self, schema):

View File

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

View File

@ -1,40 +1,21 @@
from py.test import raises from py.test import raises
from pytest import raises
import graphene import graphene
from graphene import relay from graphene import relay
from graphene.contrib.django import DjangoNode, DjangoObjectType from graphene.contrib.django import DjangoNode, DjangoObjectType
from tests.utils import assert_equal_lists
from .models import Article, Reporter from .models import Article, Reporter
def test_should_raise_if_no_model(): def test_should_query_only_fields():
with raises(Exception) as excinfo: with raises(Exception):
class Character1(DjangoObjectType): class ReporterType(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):
class Meta: class Meta:
model = Reporter model = Reporter
only_fields = ('articles', ) only_fields = ('articles', )
schema = graphene.Schema(query=ReporterTypeError) schema = graphene.Schema(query=ReporterType)
query = ''' query = '''
query ReporterQuery { query ReporterQuery {
articles articles
@ -44,24 +25,13 @@ def test_should_raise_if_model_is_invalid():
assert not result.errors assert not result.errors
def test_should_map_fields_correctly(): def test_should_query_well():
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():
class ReporterType(DjangoObjectType): class ReporterType(DjangoObjectType):
class Meta: class Meta:
model = Reporter model = Reporter
class Query2(graphene.ObjectType): class Query(graphene.ObjectType):
reporter = graphene.Field(ReporterType) reporter = graphene.Field(ReporterType)
def resolve_reporter(self, *args, **kwargs): def resolve_reporter(self, *args, **kwargs):
@ -83,53 +53,41 @@ def test_should_map_fields():
'email': '' 'email': ''
} }
} }
Schema = graphene.Schema(query=Query2) schema = graphene.Schema(query=Query)
result = Schema.execute(query) result = schema.execute(query)
assert not result.errors assert not result.errors
assert result.data == expected 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(): def test_should_node():
class ReporterNodeType(DjangoNode): class ReporterNode(DjangoNode):
class Meta: class Meta:
model = Reporter model = Reporter
@classmethod @classmethod
def get_node(cls, id): 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): def resolve_articles(self, *args, **kwargs):
return [ArticleNodeType(Article(headline='Hi!'))] return [ArticleNode(Article(headline='Hi!'))]
class ArticleNodeType(DjangoNode): class ArticleNode(DjangoNode):
class Meta: class Meta:
model = Article model = Article
@classmethod @classmethod
def get_node(cls, id): 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() node = relay.NodeField()
reporter = graphene.Field(ReporterNodeType) reporter = graphene.Field(ReporterNode)
article = graphene.Field(ArticleNodeType) article = graphene.Field(ArticleNode)
def resolve_reporter(self, *args, **kwargs): 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 = '''
query ReporterQuery { query ReporterQuery {
@ -146,12 +104,12 @@ def test_should_node():
lastName, lastName,
email email
} }
myArticle: node(id:"QXJ0aWNsZU5vZGVUeXBlOjE=") { myArticle: node(id:"QXJ0aWNsZU5vZGU6MQ==") {
id id
... on ReporterNodeType { ... on ReporterNode {
firstName firstName
} }
... on ArticleNodeType { ... on ArticleNode {
headline headline
} }
} }
@ -159,7 +117,7 @@ def test_should_node():
''' '''
expected = { expected = {
'reporter': { 'reporter': {
'id': 'UmVwb3J0ZXJOb2RlVHlwZTox', 'id': 'UmVwb3J0ZXJOb2RlOjE=',
'firstName': 'ABA', 'firstName': 'ABA',
'lastName': 'X', 'lastName': 'X',
'email': '', 'email': '',
@ -172,11 +130,11 @@ def test_should_node():
}, },
}, },
'myArticle': { 'myArticle': {
'id': 'QXJ0aWNsZU5vZGVUeXBlOjE=', 'id': 'QXJ0aWNsZU5vZGU6MQ==',
'headline': 'Article node' 'headline': 'Article node'
} }
} }
Schema = graphene.Schema(query=Query1) schema = graphene.Schema(query=Query)
result = Schema.execute(query) result = schema.execute(query)
assert not result.errors assert not result.errors
assert result.data == expected 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 import Schema
from graphene.contrib.django.types import DjangoInterface, DjangoNode from graphene.contrib.django.types import DjangoInterface, DjangoNode
from graphene.core.fields import IntField, Field from graphene.core.fields import Field, IntField
from graphene.core.types.scalars import String, Int from graphene.core.types.scalars import 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
from .models import Article, Reporter from .models import Article, Reporter
schema = Schema()
class Character(DjangoInterface): class Character(DjangoInterface):
'''Character description''' '''Character description'''
@ -17,6 +19,7 @@ class Character(DjangoInterface):
model = Reporter model = Reporter
@schema.register
class Human(DjangoNode): class Human(DjangoNode):
'''Human description''' '''Human description'''
@ -28,14 +31,12 @@ class Human(DjangoNode):
class Meta: class Meta:
model = Article model = Article
schema = Schema()
def test_django_interface(): def test_django_interface():
assert DjangoNode._meta.is_interface is True assert DjangoNode._meta.is_interface is True
def test_pseudo_interface(): def test_pseudo_interface_registered():
object_type = schema.T(Character) object_type = schema.T(Character)
assert Character._meta.is_interface is True assert Character._meta.is_interface is True
assert isinstance(object_type, GraphQLInterfaceType) assert isinstance(object_type, GraphQLInterfaceType)

View File

@ -6,7 +6,7 @@ def format_response(response):
def test_client_get_no_query(settings, client): 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') response = client.get('/graphql')
json_response = format_response(response) json_response = format_response(response)
assert json_response == {'errors': [ assert json_response == {'errors': [
@ -14,7 +14,7 @@ def test_client_get_no_query(settings, client):
def test_client_post_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', {}) response = client.post('/graphql', {})
json_response = format_response(response) json_response = format_response(response)
assert json_response == {'errors': [ assert json_response == {'errors': [
@ -22,7 +22,7 @@ def test_client_post_no_query(settings, client):
def test_client_post_malformed_json(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') response = client.post('/graphql', 'MALFORMED', 'application/json')
json_response = format_response(response) json_response = format_response(response)
assert json_response == {'errors': [ assert json_response == {'errors': [
@ -30,7 +30,7 @@ def test_client_post_malformed_json(settings, client):
def test_client_post_empty_query(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( response = client.post(
'/graphql', json.dumps({'query': ''}), 'application/json') '/graphql', json.dumps({'query': ''}), 'application/json')
json_response = format_response(response) 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): 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( response = client.post(
'/graphql', json.dumps({'query': '{ MALFORMED'}), 'application/json') '/graphql', json.dumps({'query': '{ MALFORMED'}), 'application/json')
json_response = format_response(response) 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): 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 }'}) response = client.get('/graphql', {'query': '{ headline }'})
json_response = format_response(response) json_response = format_response(response)
expected_json = { expected_json = {
@ -61,7 +61,7 @@ def test_client_get_good_query(settings, client):
def test_client_get_good_query_with_raise(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 }'}) response = client.get('/graphql', {'query': '{ raises }'})
json_response = format_response(response) json_response = format_response(response)
assert json_response['errors'][0][ 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): 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( response = client.post(
'/graphql', json.dumps({'query': '{ headline }'}), 'application/json') '/graphql', json.dumps({'query': '{ headline }'}), 'application/json')
json_response = format_response(response) json_response = format_response(response)

View File

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

View File

@ -1,15 +1,17 @@
import warnings import warnings
from .types.base import FieldType 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.definitions import List, NonNull
from .types.field import Field
from .types.scalars import ID, Boolean, Float, Int, String
class DeprecatedField(FieldType): class DeprecatedField(FieldType):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
cls = self.__class__ 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: if 'resolve' in kwargs:
kwargs['resolver'] = kwargs.pop('resolve') kwargs['resolver'] = kwargs.pop('resolve')
return super(DeprecatedField, self).__init__(*args, **kwargs) return super(DeprecatedField, self).__init__(*args, **kwargs)
@ -41,3 +43,7 @@ class ListField(DeprecatedField, List):
class NonNullField(DeprecatedField, NonNull): class NonNullField(DeprecatedField, NonNull):
pass pass
__all__ = ['Field', 'StringField', 'IntField', 'BooleanField',
'IDField', 'FloatField', 'ListField', 'NonNullField']

View File

@ -2,13 +2,13 @@ import inspect
from collections import OrderedDict from collections import OrderedDict
from graphene import signals 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.executor import Executor
from graphql.core.execution.middlewares.sync import \ from graphql.core.execution.middlewares.sync import \
SynchronousExecutionMiddleware SynchronousExecutionMiddleware
from graphql.core.type import GraphQLSchema as _GraphQLSchema from graphql.core.type import GraphQLSchema as _GraphQLSchema
from graphql.core.utils.introspection_query import introspection_query 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): class GraphQLSchema(_GraphQLSchema):
@ -40,7 +40,8 @@ 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
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: if is_objecttype:
self.register(object_type) self.register(object_type)
return self._types[object_type] return self._types[object_type]
@ -68,7 +69,8 @@ class Schema(object):
type_name = object_type._meta.type_name type_name = object_type._meta.type_name
registered_object_type = self._types_names.get(type_name, None) registered_object_type = self._types_names.get(type_name, None)
if registered_object_type: 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 self._types_names[object_type._meta.type_name] = object_type
return object_type return object_type

View File

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

View File

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

View File

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

View File

@ -1,13 +1,9 @@
from py.test import raises from py.test import raises
from pytest import raises
from graphene import Interface, ObjectType, Schema from graphene import Interface, ObjectType, Schema
from graphene.core.fields import Field, ListField, StringField from graphene.core.fields import Field, ListField, StringField
from graphene.core.types.base import LazyType from graphene.core.types.base import LazyType
from graphql.core import graphql from graphql.core import graphql
from graphql.core.type import (GraphQLInterfaceType, GraphQLObjectType,
GraphQLSchema)
from tests.utils import assert_equal_lists from tests.utils import assert_equal_lists
schema = Schema(name='My own schema') 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 .base import BaseType, LazyType, OrderedType
from .argument import Argument from .argument import Argument, ArgumentsGroup, to_arguments
from .field import Field, InputField
from .scalars import String, Int, Boolean, ID, Float
from .definitions import List, NonNull 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 graphql.core.type import GraphQLArgument
from .base import BaseType, OrderedType, ArgumentType
from ...utils import to_camel_case from ...utils import to_camel_case
from .base import ArgumentType, BaseType, OrderedType
class Argument(OrderedType): class Argument(OrderedType):
def __init__(self, type, description=None, default=None, name=None, _creation_counter=None): def __init__(self, type, description=None, default=None, name=None, _creation_counter=None):
super(Argument, self).__init__(_creation_counter=_creation_counter) super(Argument, self).__init__(_creation_counter=_creation_counter)
self.name = name self.name = name
@ -23,6 +24,7 @@ class Argument(OrderedType):
class ArgumentsGroup(BaseType): class ArgumentsGroup(BaseType):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
arguments = to_arguments(*args, **kwargs) arguments = to_arguments(*args, **kwargs)
self.arguments = OrderedDict([(arg.name, arg) for arg in arguments]) self.arguments = OrderedDict([(arg.name, arg) for arg in arguments])
@ -58,7 +60,8 @@ def to_arguments(*args, **kwargs):
if name: if name:
argument.name = to_camel_case(name) argument.name = to_camel_case(name)
assert argument.name, 'Argument in field must have a 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 arguments[argument.name] = argument
return sorted(arguments.values()) return sorted(arguments.values())

View File

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

View File

@ -1,12 +1,14 @@
import six 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): class OfType(MountedType):
def __init__(self, of_type, *args, **kwargs): 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) of_type = LazyType(of_type)
self.of_type = of_type self.of_type = of_type
super(OfType, self).__init__(*args, **kwargs) super(OfType, self).__init__(*args, **kwargs)

View File

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

View File

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

View File

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

View File

@ -1,10 +1,11 @@
from pytest import raises from pytest import raises
from graphene.core.schema import Schema
from graphene.core.types import ObjectType
from graphql.core.type import GraphQLArgument from graphql.core.type import GraphQLArgument
from ..argument import Argument, to_arguments from ..argument import Argument, to_arguments
from ..scalars import String from ..scalars import String
from graphene.core.types import ObjectType
from graphene.core.schema import Schema
def test_argument_internal_type(): def test_argument_internal_type():
@ -26,7 +27,8 @@ def test_to_arguments():
other_kwarg=String(), 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(): def test_to_arguments_no_name():

View File

@ -1,9 +1,10 @@
from mock import patch from mock import patch
from ..base import OrderedType, MountedType from graphene.core.types import InputObjectType, ObjectType
from ..field import Field, InputField
from ..argument import Argument 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(): def test_orderedtype_equal():
@ -26,14 +27,16 @@ def test_type_as_field_called(Field):
resolver = lambda x: x resolver = lambda x: x
a = MountedType(2, description='A', resolver=resolver) a = MountedType(2, description='A', resolver=resolver)
a.as_field() 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') @patch('graphene.core.types.argument.Argument')
def test_type_as_argument_called(Argument): def test_type_as_argument_called(Argument):
a = MountedType(2, description='A') a = MountedType(2, description='A')
a.as_argument() 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(): 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 ..definitions import List, NonNull
from ..scalars import String from ..scalars import String
from graphene.core.schema import Schema
schema = 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 ..base import LazyType
from ..definitions import List from ..definitions import List
from graphene.core.types import ObjectType, InputObjectType from ..field import Field, InputField
from graphene.core.schema import Schema from ..scalars import String
def test_field_internal_type(): def test_field_internal_type():
@ -81,8 +82,10 @@ def test_field_string_reference():
class MyObjectType(ObjectType): class MyObjectType(ObjectType):
my_field = field my_field = field
schema = Schema(query=MyObjectType)
assert isinstance(field.type, LazyType) assert isinstance(field.type, LazyType)
assert field.type.type_str == 'MyObjectType' assert schema.T(field.type) == schema.T(MyObjectType)
def test_field_custom_arguments(): 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, from graphql.core.type import (GraphQLBoolean, GraphQLFloat, GraphQLID,
GraphQLInt, GraphQLScalarType, GraphQLString) GraphQLInt, GraphQLScalarType, GraphQLString)
from ..scalars import String, Int, Boolean, ID, Float, Scalar from ..scalars import ID, Boolean, Float, Int, Scalar, String
from graphene.core.schema import Schema
schema = Schema() schema = Schema()

View File

@ -1,8 +1,7 @@
from collections import Iterable from collections import Iterable
from graphene.core.fields import Field, IDField from graphene.core.fields import Field
from graphene.core.types.scalars import String, ID, Int from graphene.core.types.scalars import ID, Int, String
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
@ -23,7 +22,6 @@ class ConnectionField(Field):
def wrap_resolved(self, value, instance, args, info): def wrap_resolved(self, value, instance, args, info):
return value return value
def resolver(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
@ -59,7 +57,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 schema.T(connection_type) return connection_type
class NodeField(Field): class NodeField(Field):
@ -67,7 +65,8 @@ class NodeField(Field):
def __init__(self, object_type=None, *args, **kwargs): def __init__(self, object_type=None, *args, **kwargs):
from graphene.relay.types import Node from graphene.relay.types import Node
id = kwargs.pop('id', None) or ID(description='The ID of an object') 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 self.field_object_type = object_type
def id_fetcher(self, global_id, info): def id_fetcher(self, global_id, info):
@ -89,6 +88,7 @@ class NodeField(Field):
class GlobalIDField(Field): class GlobalIDField(Field):
'''The ID of an object''' '''The ID of an object'''
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(GlobalIDField, self).__init__(ID(), *args, **kwargs) super(GlobalIDField, self).__init__(ID(), *args, **kwargs)
self.required = True self.required = True
@ -100,4 +100,4 @@ class GlobalIDField(Field):
super(GlobalIDField, self).contribute_to_class(cls, name) super(GlobalIDField, self).contribute_to_class(cls, name)
def resolver(self, instance, args, info): 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 import graphene
from graphene import relay from graphene import relay
from graphene.core.schema import Schema from graphene.core.schema import Schema
from graphene.core.types import InputObjectType
from graphql.core.type import GraphQLInputObjectField
my_id = 0 my_id = 0
@ -35,7 +33,7 @@ schema = Schema(query=Query, mutation=MyResultMutation)
def test_mutation_arguments(): def test_mutation_arguments():
assert ChangeNumber.arguments assert ChangeNumber.arguments
assert list(ChangeNumber.arguments) == ['input'] assert list(ChangeNumber.arguments) == ['input']
_input = ChangeNumber.arguments['input'] ChangeNumber.arguments['input']
# inner_type = _input.get_object_type(schema) # inner_type = _input.get_object_type(schema)
# client_mutation_id_field = inner_type._meta.fields_map[ # 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.fields import BooleanField, Field, ListField, StringField
from graphene.core.types import (InputObjectType, Interface, Mutation, from graphene.core.types import (InputObjectType, Interface, Mutation,
ObjectType) ObjectType)
from graphene.core.types.base import LazyType
from graphene.core.types.argument import ArgumentsGroup from graphene.core.types.argument import ArgumentsGroup
from graphene.core.types.base import LazyType
from graphene.core.types.definitions import NonNull from graphene.core.types.definitions import NonNull
from graphene.relay.fields import GlobalIDField from graphene.relay.fields import GlobalIDField
from graphene.utils import memoize from graphene.utils import memoize
@ -74,10 +74,9 @@ class BaseNode(object):
assert hasattr( assert hasattr(
cls, 'get_node'), 'get_node classmethod not found in %s Node' % cls cls, 'get_node'), 'get_node classmethod not found in %s Node' % cls
@classmethod def to_global_id(self):
def to_global_id(cls, instance, args, info): type_name = self._meta.type_name
type_name = cls._meta.type_name return to_global_id(type_name, self.id)
return to_global_id(type_name, instance.id)
connection_type = Connection connection_type = Connection
edge_type = Edge edge_type = Edge
@ -105,13 +104,16 @@ class ClientIDMutation(Mutation):
@classmethod @classmethod
def _prepare_class(cls): def _prepare_class(cls):
Input = getattr(cls, 'Input', None) input_class = getattr(cls, 'Input', None)
if Input: if input_class:
assert hasattr( assert hasattr(
cls, 'mutate_and_get_payload'), 'You have to implement mutate_and_get_payload' 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('__dict__', None)
items.pop('__doc__', None)
items.pop('__module__', None)
items.pop('__weakref__', None)
new_input_type = type('{}Input'.format( new_input_type = type('{}Input'.format(
cls._meta.type_name), (MutationInputType, ), items) cls._meta.type_name), (MutationInputType, ), items)
cls.add_to_class('input_type', new_input_type) cls.add_to_class('input_type', new_input_type)

View File

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