Improved syntax. Added autolinter. Added automatic flake8 checker in tests. Fixed #17

This commit is contained in:
Syrus Akbary 2015-10-31 13:46:43 -07:00
parent 9ea57ecc5f
commit d46e957863
52 changed files with 254 additions and 337 deletions

View File

@ -13,6 +13,6 @@ install:
- python setup.py develop - python setup.py develop
script: script:
- py.test --cov=graphene - py.test --cov=graphene
# - flake8 - flake8
after_success: after_success:
- coveralls - coveralls

4
bin/autolinter Executable file
View File

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

View File

@ -1,8 +1,8 @@
from graphql.core.type import GraphQLEnumValue
import graphene import graphene
from graphene import resolve_only_args from graphene import resolve_only_args
from graphql.core.type import GraphQLEnumValue
from .data import getHero, getHuman, getCharacter, getDroid from .data import getCharacter, getDroid, getHero, getHuman
Episode = graphene.Enum('Episode', dict( Episode = graphene.Enum('Episode', dict(
NEWHOPE=GraphQLEnumValue(4), NEWHOPE=GraphQLEnumValue(4),

View File

@ -1,9 +1,10 @@
from ..schema import Schema, Query
from graphql.core import graphql
from ..data import setup from ..data import setup
from ..schema import Schema
setup() setup()
def test_hero_name_query(): def test_hero_name_query():
query = ''' query = '''
query HeroNameQuery { query HeroNameQuery {

View File

@ -1,4 +1,4 @@
from .models import Ship, Faction, Character from .models import Character, Faction, Ship
def initialize(): def initialize():

View File

@ -1,4 +1,5 @@
from __future__ import absolute_import from __future__ import absolute_import
from django.db import models from django.db import models

View File

@ -1,24 +1,18 @@
import graphene import graphene
from graphene import resolve_only_args, relay from graphene import relay, resolve_only_args
from graphene.contrib.django import ( from graphene.contrib.django import DjangoNode, DjangoObjectType
DjangoObjectType,
DjangoNode from .data import (create_ship, get_empire, get_faction, get_rebels, get_ship,
) get_ships)
from .models import ( from .models import Character as CharacterModel
Ship as ShipModel, Faction as FactionModel, Character as CharacterModel) from .models import Faction as FactionModel
from .data import ( from .models import Ship as ShipModel
get_faction,
get_ship,
get_ships,
get_rebels,
get_empire,
create_ship
)
schema = graphene.Schema(name='Starwars Django Relay Schema') schema = graphene.Schema(name='Starwars Django Relay Schema')
class Ship(DjangoNode): class Ship(DjangoNode):
class Meta: class Meta:
model = ShipModel model = ShipModel
@ -29,11 +23,13 @@ class Ship(DjangoNode):
@schema.register @schema.register
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
@ -43,6 +39,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)

View File

@ -1,9 +1,7 @@
import pytest import pytest
from graphql.core import graphql
from ..models import *
from ..schema import schema
from ..data import initialize from ..data import initialize
from ..schema import schema
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db

View File

@ -1,6 +1,7 @@
import pytest import pytest
from ..schema import schema
from ..data import initialize from ..data import initialize
from ..schema import schema
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db

View File

@ -1,8 +1,6 @@
import pytest import pytest
from pytest import raises
from graphql.core import graphql
from ..data import initialize
from ..data import initialize
from ..schema import schema from ..schema import schema
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db

View File

@ -3,7 +3,7 @@ data = {}
def setup(): def setup():
global data global data
from .schema import Ship, Faction from .schema import Ship, Faction
xwing = Ship( xwing = Ship(
id='1', id='1',

View File

@ -1,13 +1,7 @@
import graphene import graphene
from graphene import resolve_only_args, relay from graphene import relay, resolve_only_args
from .data import ( from .data import create_ship, get_empire, get_faction, get_rebels, get_ship
get_faction,
get_ship,
get_rebels,
get_empire,
create_ship,
)
schema = graphene.Schema(name='Starwars Relay Schema') schema = graphene.Schema(name='Starwars Relay Schema')
@ -38,6 +32,7 @@ class Faction(relay.Node):
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)

View File

@ -1,5 +1,5 @@
from ..schema import schema
from ..data import setup from ..data import setup
from ..schema import schema
setup() setup()

View File

@ -1,5 +1,5 @@
from ..schema import schema
from ..data import setup from ..data import setup
from ..schema import schema
setup() setup()

View File

@ -1,5 +1,5 @@
from ..schema import schema
from ..data import setup from ..data import setup
from ..schema import schema
setup() setup()

View File

@ -1,15 +1,10 @@
from singledispatch import singledispatch
from django.db import models from django.db import models
from singledispatch import singledispatch
from graphene.core.fields import ( from graphene.contrib.django.fields import (ConnectionOrListField,
StringField, DjangoModelField)
IDField, from graphene.core.fields import (BooleanField, FloatField, IDField, IntField,
IntField, StringField)
BooleanField,
FloatField,
ListField
)
from graphene.contrib.django.fields import ConnectionOrListField, DjangoModelField
try: try:
UUIDField = models.UUIDField UUIDField = models.UUIDField
@ -32,12 +27,12 @@ def convert_django_field(field):
@convert_django_field.register(models.SlugField) @convert_django_field.register(models.SlugField)
@convert_django_field.register(models.URLField) @convert_django_field.register(models.URLField)
@convert_django_field.register(UUIDField) @convert_django_field.register(UUIDField)
def _(field): def convert_field_to_string(field):
return StringField(description=field.help_text) return StringField(description=field.help_text)
@convert_django_field.register(models.AutoField) @convert_django_field.register(models.AutoField)
def _(field): def convert_field_to_id(field):
return IDField(description=field.help_text) return IDField(description=field.help_text)
@ -46,34 +41,34 @@ def _(field):
@convert_django_field.register(models.SmallIntegerField) @convert_django_field.register(models.SmallIntegerField)
@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 _(field): def convert_field_to_int(field):
return IntField(description=field.help_text) return IntField(description=field.help_text)
@convert_django_field.register(models.BooleanField) @convert_django_field.register(models.BooleanField)
def _(field): def convert_field_to_boolean(field):
return BooleanField(description=field.help_text, required=True) return BooleanField(description=field.help_text, required=True)
@convert_django_field.register(models.NullBooleanField) @convert_django_field.register(models.NullBooleanField)
def _(field): def convert_field_to_nullboolean(field):
return BooleanField(description=field.help_text) return BooleanField(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 _(field): def convert_field_to_float(field):
return FloatField(description=field.help_text) return FloatField(description=field.help_text)
@convert_django_field.register(models.ManyToManyField) @convert_django_field.register(models.ManyToManyField)
@convert_django_field.register(models.ManyToOneRel) @convert_django_field.register(models.ManyToOneRel)
def _(field): def convert_field_to_list_or_connection(field):
model_field = DjangoModelField(field.related_model) model_field = DjangoModelField(field.related_model)
return ConnectionOrListField(model_field) return ConnectionOrListField(model_field)
@convert_django_field.register(models.OneToOneField) @convert_django_field.register(models.OneToOneField)
@convert_django_field.register(models.ForeignKey) @convert_django_field.register(models.ForeignKey)
def _(field): def convert_field_to_djangomodel(field):
return DjangoModelField(field.related_model, description=field.help_text) return DjangoModelField(field.related_model, description=field.help_text)

View File

@ -1,21 +1,18 @@
from graphene.core.fields import (
ListField
)
from graphene import relay from graphene import relay
from graphene.core.fields import Field, LazyField
from graphene.relay.utils import is_node
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.relay.utils import is_node
class DjangoConnectionField(relay.ConnectionField): 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.get_object_type(schema))
class LazyListField(ListField): class LazyListField(ListField):
def resolve(self, instance, args, info): def resolve(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).resolve(instance, args, info)
@ -23,6 +20,7 @@ class LazyListField(ListField):
class ConnectionOrListField(LazyField): class ConnectionOrListField(LazyField):
def get_field(self, schema): def get_field(self, schema):
model_field = self.field_type model_field = self.field_type
field_object_type = model_field.get_object_type(schema) field_object_type = model_field.get_object_type(schema)
@ -35,6 +33,7 @@ class ConnectionOrListField(LazyField):
class DjangoModelField(Field): class DjangoModelField(Field):
def __init__(self, model, *args, **kwargs): def __init__(self, model, *args, **kwargs):
super(DjangoModelField, self).__init__(None, *args, **kwargs) super(DjangoModelField, self).__init__(None, *args, **kwargs)
self.model = model self.model = model

View File

@ -1,9 +1,10 @@
import inspect import inspect
from django.db import models from django.db import models
from graphene.core.options import Options from graphene.core.options import Options
from graphene.relay.utils import is_node
from graphene.relay.types import Node from graphene.relay.types import Node
from graphene.relay.utils import is_node
VALID_ATTRS = ('model', 'only_fields', 'exclude_fields') VALID_ATTRS = ('model', 'only_fields', 'exclude_fields')

View File

@ -1,12 +1,11 @@
import six import six
from graphene.core.types import ObjectTypeMeta, BaseObjectType
from graphene.contrib.django.options import DjangoOptions
from graphene.contrib.django.converter import convert_django_field from graphene.contrib.django.converter import convert_django_field
from graphene.contrib.django.options import DjangoOptions
from graphene.contrib.django.utils import get_reverse_fields from graphene.contrib.django.utils import get_reverse_fields
from graphene.core.types import BaseObjectType, ObjectTypeMeta
from graphene.relay.types import BaseNode
from graphene.relay.fields import GlobalIDField from graphene.relay.fields import GlobalIDField
from graphene.relay.types import BaseNode
class DjangoObjectTypeMeta(ObjectTypeMeta): class DjangoObjectTypeMeta(ObjectTypeMeta):
@ -38,6 +37,7 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
class InstanceObjectType(BaseObjectType): class InstanceObjectType(BaseObjectType):
def __init__(self, instance=None): def __init__(self, instance=None):
self.instance = instance self.instance = instance
super(InstanceObjectType, self).__init__() super(InstanceObjectType, self).__init__()

View File

@ -1,6 +1,6 @@
from django.db import models from django.db import models
from django.db.models.query import QuerySet
from django.db.models.manager import Manager from django.db.models.manager import Manager
from django.db.models.query import QuerySet
from graphene.utils import LazyMap from graphene.utils import LazyMap

View File

@ -1,8 +1,8 @@
import json import json
from django.conf import settings
from django.http import HttpResponse from django.http import HttpResponse
from django.views.generic import View from django.views.generic import View
from django.conf import settings
from graphql.core.error import GraphQLError, format_error from graphql.core.error import GraphQLError, format_error
@ -26,8 +26,8 @@ class GraphQLView(View):
def response_errors(self, *errors): def response_errors(self, *errors):
errors = [{ errors = [{
"message": str(e) "message": str(e)
} for e in errors] } for e in errors]
return HttpResponse(json.dumps({'errors': errors}), content_type='application/json') return HttpResponse(json.dumps({'errors': errors}), content_type='application/json')
def execute_query(self, request, query, *args, **kwargs): def execute_query(self, request, query, *args, **kwargs):

View File

@ -1,26 +1,21 @@
import inspect import inspect
from functools import total_ordering, wraps
import six import six
from graphene.core.scalars import GraphQLSkipField
from graphene.core.types import BaseObjectType, InputObjectType
from graphene.utils import ProxySnakeDict, enum_to_graphql_enum, to_camel_case
from graphql.core.type import (GraphQLArgument, GraphQLBoolean, GraphQLField,
GraphQLFloat, GraphQLID,
GraphQLInputObjectField, GraphQLInt,
GraphQLList, GraphQLNonNull, GraphQLString)
try: try:
from enum import Enum from enum import Enum
except ImportError: except ImportError:
class Enum(object): class Enum(object):
pass pass
from functools import total_ordering, wraps
from graphql.core.type import (
GraphQLField,
GraphQLList,
GraphQLNonNull,
GraphQLInt,
GraphQLString,
GraphQLBoolean,
GraphQLID,
GraphQLArgument,
GraphQLFloat,
GraphQLInputObjectField,
)
from graphene.utils import to_camel_case, ProxySnakeDict, enum_to_graphql_enum
from graphene.core.types import BaseObjectType, InputObjectType
from graphene.core.scalars import GraphQLSkipField
class Empty(object): class Empty(object):
@ -252,10 +247,12 @@ class FloatField(TypeField):
class ListField(Field): class ListField(Field):
def type_wrapper(self, field_type): def type_wrapper(self, field_type):
return GraphQLList(field_type) return GraphQLList(field_type)
class NonNullField(Field): class NonNullField(Field):
def type_wrapper(self, field_type): def type_wrapper(self, field_type):
return GraphQLNonNull(field_type) return GraphQLNonNull(field_type)

View File

@ -1,5 +1,6 @@
from collections import OrderedDict
from graphene.utils import cached_property from graphene.utils import cached_property
from collections import OrderedDict, namedtuple
DEFAULT_NAMES = ('description', 'name', 'is_interface', 'is_mutation', DEFAULT_NAMES = ('description', 'name', 'is_interface', 'is_mutation',
'type_name', 'interfaces', 'proxy') 'type_name', 'interfaces', 'proxy')

View File

@ -1,19 +1,16 @@
from functools import wraps
from collections import OrderedDict from collections import OrderedDict
from functools import wraps
from graphql.core.type import (
GraphQLSchema as _GraphQLSchema
)
from graphql.core.execution.executor import Executor
from graphql.core.execution.middlewares.sync import SynchronousExecutionMiddleware
from graphql.core.utils.introspection_query import introspection_query
from graphene import signals from graphene import signals
from graphene.utils import cached_property 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
class GraphQLSchema(_GraphQLSchema): class GraphQLSchema(_GraphQLSchema):
def __init__(self, schema, *args, **kwargs): def __init__(self, schema, *args, **kwargs):
self.graphene_schema = schema self.graphene_schema = schema
super(GraphQLSchema, self).__init__(*args, **kwargs) super(GraphQLSchema, self).__init__(*args, **kwargs)
@ -61,7 +58,8 @@ class Schema(object):
@property @property
def executor(self): def executor(self):
if not self._executor: if not self._executor:
self.executor = Executor([SynchronousExecutionMiddleware()], map_type=OrderedDict) self.executor = Executor(
[SynchronousExecutionMiddleware()], map_type=OrderedDict)
return self._executor return self._executor
@executor.setter @executor.setter

View File

@ -1,19 +1,14 @@
import inspect
import six
import copy import copy
import inspect
from collections import OrderedDict from collections import OrderedDict
from graphql.core.type import ( import six
GraphQLObjectType,
GraphQLInputObjectType,
GraphQLInterfaceType,
GraphQLArgument
)
from graphene import signals from graphene import signals
from graphene.core.options import Options from graphene.core.options import Options
from graphene.utils import memoize
from graphene.core.schema import register_internal_type from graphene.core.schema import register_internal_type
from graphql.core.type import (GraphQLArgument, GraphQLInputObjectType,
GraphQLInterfaceType, GraphQLObjectType)
class ObjectTypeMeta(type): class ObjectTypeMeta(type):
@ -45,14 +40,15 @@ class ObjectTypeMeta(type):
else: else:
meta = attr_meta meta = attr_meta
base_meta = getattr(new_class, '_meta', None) getattr(new_class, '_meta', None)
new_class.add_to_class('_meta', new_class.options_cls(meta)) new_class.add_to_class('_meta', new_class.options_cls(meta))
new_class._meta.is_interface = new_class.is_interface(parents) new_class._meta.is_interface = new_class.is_interface(parents)
new_class._meta.is_mutation = new_class.is_mutation(parents) new_class._meta.is_mutation = new_class.is_mutation(parents)
assert not (new_class._meta.is_interface and new_class._meta.is_mutation) assert not (
new_class._meta.is_interface and new_class._meta.is_mutation)
input_class = None input_class = None
if new_class._meta.is_mutation: if new_class._meta.is_mutation:
@ -63,12 +59,14 @@ class ObjectTypeMeta(type):
new_class.add_to_class(obj_name, obj) new_class.add_to_class(obj_name, obj)
if new_class._meta.is_mutation: if new_class._meta.is_mutation:
assert hasattr(new_class, 'mutate'), "All mutations must implement mutate method" assert hasattr(
new_class, 'mutate'), "All mutations must implement mutate method"
if input_class: if input_class:
items = dict(input_class.__dict__) items = dict(input_class.__dict__)
items.pop('__dict__', None) items.pop('__dict__', None)
input_type = type('{}Input'.format(new_class._meta.type_name), (ObjectType, ), items) input_type = type('{}Input'.format(
new_class._meta.type_name), (ObjectType, ), items)
new_class.add_to_class('input_type', input_type) new_class.add_to_class('input_type', input_type)
new_class.add_extra_fields() new_class.add_extra_fields()
@ -166,7 +164,8 @@ class BaseObjectType(object):
except AttributeError: except AttributeError:
pass pass
if kwargs: if kwargs:
raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0]) raise TypeError(
"'%s' is an invalid keyword argument for this function" % list(kwargs)[0])
signals.post_init.send(self.__class__, instance=self) signals.post_init.send(self.__class__, instance=self)
@ -215,12 +214,14 @@ class ObjectType(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
class Mutation(six.with_metaclass(ObjectTypeMeta, BaseObjectType)): class Mutation(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
@classmethod @classmethod
def get_input_type(cls): def get_input_type(cls):
return getattr(cls, 'input_type', None) return getattr(cls, 'input_type', None)
class InputObjectType(ObjectType): class InputObjectType(ObjectType):
@classmethod @classmethod
@register_internal_type @register_internal_type
def internal_type(cls, schema): def internal_type(cls, schema):

View File

@ -15,4 +15,4 @@ from graphene.relay.types import (
from graphene.relay.utils import is_node from graphene.relay.utils import is_node
__all__ = ['ConnectionField', 'NodeField', 'GlobalIDField', 'Node', __all__ = ['ConnectionField', 'NodeField', 'GlobalIDField', 'Node',
'PageInfo', 'Edge', 'Connection', 'is_node'] 'PageInfo', 'Edge', 'Connection', 'ClientIDMutation', 'is_node']

View File

@ -1,21 +1,10 @@
from collections import Iterable, OrderedDict from collections import Iterable
from graphql_relay.connection.arrayconnection import (
connection_from_list
)
from graphql_relay.connection.connection import (
connection_args
)
from graphql_relay.node.node import (
from_global_id
)
from graphql.core.type import (
GraphQLNonNull,
GraphQLID,
GraphQLArgument,
)
from graphene.core.fields import Field, IDField from graphene.core.fields import Field, IDField
from graphql.core.type import GraphQLArgument, GraphQLID, GraphQLNonNull
from graphql_relay.connection.arrayconnection import connection_from_list
from graphql_relay.connection.connection import connection_args
from graphql_relay.node.node import from_global_id
class ConnectionField(Field): class ConnectionField(Field):
@ -68,6 +57,7 @@ class ConnectionField(Field):
class NodeField(Field): 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
super(NodeField, self).__init__(object_type or Node, *args, **kwargs) super(NodeField, self).__init__(object_type or Node, *args, **kwargs)
@ -84,7 +74,7 @@ class NodeField(Field):
_type, _id = resolved_global_id.type, resolved_global_id.id _type, _id = resolved_global_id.type, resolved_global_id.id
object_type = schema.get_type(_type) object_type = schema.get_type(_type)
if not is_node(object_type) or (self.field_object_type and if not is_node(object_type) or (self.field_object_type and
object_type != self.field_object_type): object_type != self.field_object_type):
return return
return object_type.get_node(_id) return object_type.get_node(_id)

View File

@ -1,18 +1,20 @@
from graphql_relay.node.node import ( from graphene.core.fields import BooleanField, Field, ListField, StringField
to_global_id from graphene.core.types import (InputObjectType, Interface, Mutation,
) ObjectType)
from graphene.core.types import Interface, ObjectType, Mutation, InputObjectType
from graphene.core.fields import BooleanField, StringField, ListField, Field
from graphene.relay.fields import GlobalIDField from graphene.relay.fields import GlobalIDField
from graphene.utils import memoize from graphene.utils import memoize
from graphql_relay.node.node import to_global_id
class PageInfo(ObjectType): class PageInfo(ObjectType):
has_next_page = BooleanField(required=True, description='When paginating forwards, are there more items?') has_next_page = BooleanField(
has_previous_page = BooleanField(required=True, description='When paginating backwards, are there more items?') required=True, description='When paginating forwards, are there more items?')
start_cursor = StringField(description='When paginating backwards, the cursor to continue.') has_previous_page = BooleanField(
end_cursor = StringField(description='When paginating forwards, the cursor to continue.') required=True, description='When paginating backwards, are there more items?')
start_cursor = StringField(
description='When paginating backwards, the cursor to continue.')
end_cursor = StringField(
description='When paginating forwards, the cursor to continue.')
class Edge(ObjectType): class Edge(ObjectType):
@ -20,8 +22,10 @@ class Edge(ObjectType):
class Meta: class Meta:
type_name = 'DefaultEdge' type_name = 'DefaultEdge'
node = Field(lambda field: field.object_type.node_type, description='The item at the end of the edge') node = Field(lambda field: field.object_type.node_type,
cursor = StringField(required=True, description='A cursor for use in pagination') description='The item at the end of the edge')
cursor = StringField(
required=True, description='A cursor for use in pagination')
@classmethod @classmethod
@memoize @memoize
@ -36,8 +40,10 @@ class Connection(ObjectType):
class Meta: class Meta:
type_name = 'DefaultConnection' type_name = 'DefaultConnection'
page_info = Field(PageInfo, required=True, description='The Information to aid in pagination') page_info = Field(PageInfo, required=True,
edges = ListField(lambda field: field.object_type.edge_type, description='Information to aid in pagination.') description='The Information to aid in pagination')
edges = ListField(lambda field: field.object_type.edge_type,
description='Information to aid in pagination.')
_connection_data = None _connection_data = None
@ -57,6 +63,7 @@ class Connection(ObjectType):
class BaseNode(object): class BaseNode(object):
@classmethod @classmethod
def _prepare_class(cls): def _prepare_class(cls):
from graphene.relay.utils import is_node from graphene.relay.utils import is_node
@ -97,13 +104,16 @@ class ClientIDMutation(Mutation):
def _prepare_class(cls): def _prepare_class(cls):
input_type = getattr(cls, 'input_type', None) input_type = getattr(cls, 'input_type', None)
if input_type: if input_type:
assert hasattr(cls, 'mutate_and_get_payload'), 'You have to implement mutate_and_get_payload' assert hasattr(
new_input_inner_type = type('{}InnerInput'.format(cls._meta.type_name), (MutationInputType, input_type, ), {}) cls, 'mutate_and_get_payload'), 'You have to implement mutate_and_get_payload'
new_input_inner_type = type('{}InnerInput'.format(
cls._meta.type_name), (MutationInputType, input_type, ), {})
items = { items = {
'input': Field(new_input_inner_type) 'input': Field(new_input_inner_type)
} }
assert issubclass(new_input_inner_type, InputObjectType) assert issubclass(new_input_inner_type, InputObjectType)
input_type = type('{}Input'.format(cls._meta.type_name), (ObjectType, ), items) input_type = type('{}Input'.format(
cls._meta.type_name), (ObjectType, ), items)
setattr(cls, 'input_type', input_type) setattr(cls, 'input_type', input_type)
@classmethod @classmethod

View File

@ -1,4 +1,5 @@
class LazyMap(object): class LazyMap(object):
def __init__(self, origin, _map, state=None): def __init__(self, origin, _map, state=None):
self._origin = origin self._origin = origin
self._origin_iter = origin.__iter__() self._origin_iter = origin.__iter__()

View File

@ -1,10 +1,12 @@
from collections import OrderedDict from collections import OrderedDict
from graphql.core.type import GraphQLEnumType, GraphQLEnumValue from graphql.core.type import GraphQLEnumType, GraphQLEnumValue
def enum_to_graphql_enum(enumeration): def enum_to_graphql_enum(enumeration):
return GraphQLEnumType( return GraphQLEnumType(
name=enumeration.__name__, name=enumeration.__name__,
values=OrderedDict([(it.name, GraphQLEnumValue(it.value)) for it in enumeration]), values=OrderedDict([(it.name, GraphQLEnumValue(it.value))
for it in enumeration]),
description=enumeration.__doc__ description=enumeration.__doc__
) )

View File

@ -1,6 +1,6 @@
import sys import sys
from setuptools import setup, find_packages from setuptools import find_packages, setup
from setuptools.command.test import test as TestCommand from setuptools.command.test import test as TestCommand

View File

@ -1,6 +1,6 @@
from datetime import date from datetime import date
from .models import Reporter, Article from .models import Article, Reporter
r = Reporter(first_name='John', last_name='Smith', email='john@example.com') r = Reporter(first_name='John', last_name='Smith', email='john@example.com')
r.save() r.save()

View File

@ -1,4 +1,5 @@
from __future__ import absolute_import from __future__ import absolute_import
from django.db import models from django.db import models

View File

@ -1,16 +1,13 @@
from py.test import raises
from collections import namedtuple
from pytest import raises
import graphene
from graphene import relay
from graphene.contrib.django.converter import (
convert_django_field
)
from graphene.contrib.django.fields import (
ConnectionOrListField,
DjangoModelField
)
from django.db import models 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
from graphene.contrib.django.fields import (ConnectionOrListField,
DjangoModelField)
from .models import Article, Reporter from .models import Article, Reporter

View File

@ -1,16 +1,14 @@
from py.test import raises from py.test import raises
from collections import namedtuple
from pytest import raises from pytest import raises
import graphene import graphene
from graphene import relay from graphene import relay
from graphene.contrib.django import ( from graphene.contrib.django import DjangoNode, DjangoObjectType
DjangoObjectType,
DjangoNode
)
from .models import Reporter, Article
from tests.utils import assert_equal_lists from tests.utils import assert_equal_lists
from .models import Article, Reporter
def test_should_raise_if_no_model(): def test_should_raise_if_no_model():
with raises(Exception) as excinfo: with raises(Exception) as excinfo:

View File

@ -1,29 +1,14 @@
from py.test import raises
from collections import namedtuple
from pytest import raises
from graphene.relay.fields import (
GlobalIDField
)
from graphene.core.fields import (
Field,
StringField,
IntField
)
from graphql.core.type import (
GraphQLObjectType,
GraphQLInterfaceType
)
from graphene import Schema from graphene import Schema
from graphene.contrib.django.types import ( from graphene.contrib.django.types import DjangoInterface, DjangoNode
DjangoNode, from graphene.core.fields import IntField
DjangoInterface from graphene.relay.fields import GlobalIDField
) from graphql.core.type import GraphQLInterfaceType, GraphQLObjectType
from .models import Reporter, Article
from tests.utils import assert_equal_lists from tests.utils import assert_equal_lists
from .models import Article, Reporter
class Character(DjangoInterface): class Character(DjangoInterface):
'''Character description''' '''Character description'''
@ -82,7 +67,7 @@ def test_interface_resolve_type():
def test_object_type(): def test_object_type():
object_type = schema.T(Human) object_type = schema.T(Human)
fields_map = Human._meta.fields_map Human._meta.fields_map
assert Human._meta.is_interface is False assert Human._meta.is_interface is False
assert isinstance(object_type, GraphQLObjectType) assert isinstance(object_type, GraphQLObjectType)
assert_equal_lists( assert_equal_lists(

View File

@ -1,18 +1,15 @@
from django.conf.urls import url from django.conf.urls import url
from graphene.contrib.django.views import GraphQLView
import graphene import graphene
from graphene import Schema from graphene import Schema
from graphene.contrib.django.types import ( from graphene.contrib.django.types import DjangoNode
DjangoNode, from graphene.contrib.django.views import GraphQLView
DjangoInterface
)
from .models import Reporter, Article from .models import Article, Reporter
class Character(DjangoNode): class Character(DjangoNode):
class Meta: class Meta:
model = Reporter model = Reporter

View File

@ -1,22 +1,4 @@
import json import json
import pytest
from py.test import raises
from collections import namedtuple
from pytest import raises
from graphene.core.fields import (
Field,
StringField,
)
from graphql.core.type import (
GraphQLObjectType,
GraphQLInterfaceType
)
from graphene import Schema
from graphene.contrib.django.types import (
DjangoNode,
DjangoInterface
)
def format_response(response): def format_response(response):
@ -27,33 +9,39 @@ def test_client_get_no_query(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls' settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
response = client.get('/graphql') response = client.get('/graphql')
json_response = format_response(response) json_response = format_response(response)
assert json_response == {'errors': [{'message': 'Must provide query string.'}]} assert json_response == {'errors': [
{'message': 'Must provide query string.'}]}
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 = 'tests.contrib_django.test_urls'
response = client.post('/graphql', {}) response = client.post('/graphql', {})
json_response = format_response(response) json_response = format_response(response)
assert json_response == {'errors': [{'message': 'Must provide query string.'}]} assert json_response == {'errors': [
{'message': 'Must provide query string.'}]}
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 = 'tests.contrib_django.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': [{'message': 'Malformed json body in the post data'}]} assert json_response == {'errors': [
{'message': 'Malformed json body in the post data'}]}
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 = 'tests.contrib_django.test_urls'
response = client.post('/graphql', json.dumps({'query': ''}), 'application/json') response = client.post(
'/graphql', json.dumps({'query': ''}), 'application/json')
json_response = format_response(response) json_response = format_response(response)
assert json_response == {'errors': [{'message': 'Must provide query string.'}]} assert json_response == {'errors': [
{'message': 'Must provide query string.'}]}
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 = 'tests.contrib_django.test_urls'
response = client.post('/graphql', json.dumps({'query': '{ MALFORMED'}), 'application/json') response = client.post(
'/graphql', json.dumps({'query': '{ MALFORMED'}), 'application/json')
json_response = format_response(response) json_response = format_response(response)
assert 'errors' in json_response assert 'errors' in json_response
assert len(json_response['errors']) == 1 assert len(json_response['errors']) == 1
@ -76,13 +64,15 @@ def test_client_get_good_query_with_raise(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls' settings.ROOT_URLCONF = 'tests.contrib_django.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]['message'] == 'This field should raise exception' assert json_response['errors'][0][
'message'] == 'This field should raise exception'
assert json_response['data']['raises'] is None assert json_response['data']['raises'] is None
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 = 'tests.contrib_django.test_urls'
response = client.post('/graphql', json.dumps({'query': '{ headline }'}), 'application/json') response = client.post(
'/graphql', json.dumps({'query': '{ headline }'}), 'application/json')
json_response = format_response(response) json_response = format_response(response)
expected_json = { expected_json = {
'data': { 'data': {
@ -97,5 +87,3 @@ def test_client_post_good_query(settings, client):
# response = client.get('/graphql') # response = client.get('/graphql')
# json_response = format_response(response) # json_response = format_response(response)
# assert json_response == {'errors': [{'message': 'Must provide query string.'}]} # assert json_response == {'errors': [{'message': 'Must provide query string.'}]}

View File

@ -1,24 +1,13 @@
from py.test import raises from py.test import raises
from collections import namedtuple
from pytest import raises from pytest import raises
from graphql.core.type import ( from graphene.core.fields import Field, NonNullField, StringField
GraphQLField,
GraphQLNonNull,
GraphQLInt,
GraphQLString,
GraphQLBoolean,
GraphQLID,
)
from graphene.core.fields import (
Field,
StringField,
NonNullField
)
from graphene.core.options import Options from graphene.core.options import Options
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,
GraphQLInt, GraphQLNonNull, GraphQLString)
class ObjectType(object): class ObjectType(object):
@ -149,7 +138,8 @@ def test_field_none_type_raises_error():
f.contribute_to_class(ot, 'field_name') f.contribute_to_class(ot, 'field_name')
with raises(Exception) as excinfo: with raises(Exception) as excinfo:
f.internal_field(s) f.internal_field(s)
assert str(excinfo.value) == "Internal type for field ObjectType.field_name is None" assert str(
excinfo.value) == "Internal type for field ObjectType.field_name is None"
def test_field_str(): def test_field_str():

View File

@ -1,5 +1,5 @@
import graphene import graphene
from py.test import raises
from graphene.core.schema import Schema from graphene.core.schema import Schema
my_id = 0 my_id = 0

View File

@ -1,11 +1,8 @@
from py.test import raises
from collections import namedtuple
from pytest import raises
from graphene.core.fields import (
Field,
StringField,
)
from py.test import raises
from pytest import raises
from graphene.core.fields import StringField
from graphene.core.options import Options from graphene.core.options import Options
@ -57,7 +54,6 @@ def test_options_description():
class ObjectType(object): class ObjectType(object):
'''False description''' '''False description'''
pass
opt.contribute_to_class(ObjectType, '_meta') opt.contribute_to_class(ObjectType, '_meta')
assert opt.description == 'False description' assert opt.description == 'False description'

View File

@ -1,23 +1,11 @@
from py.test import raises
from collections import namedtuple
from pytest import raises
from graphql.core import graphql
from graphene.core.fields import (
Field,
StringField,
ListField,
)
from graphql.core.type import (
GraphQLObjectType,
GraphQLSchema,
GraphQLInterfaceType
)
from graphene.core.types import (
Interface, from graphene.core.fields import Field, ListField, StringField
ObjectType
)
from graphene.core.schema import Schema from graphene.core.schema import Schema
from graphene.core.types import Interface, ObjectType
from graphql.core import graphql
from graphql.core.type import (GraphQLInterfaceType, GraphQLObjectType,
GraphQLSchema)
class Character(Interface): class Character(Interface):
@ -50,7 +38,8 @@ Human_type = schema.T(Human)
def test_type(): def test_type():
assert Human._meta.fields_map['name'].resolve(Human(object()), None, None) == 'Peter' assert Human._meta.fields_map['name'].resolve(
Human(object()), None, None) == 'Peter'
def test_query(): def test_query():

View File

@ -1,6 +1,4 @@
from graphene.core.scalars import ( from graphene.core.scalars import GraphQLSkipField
GraphQLSkipField
)
def test_skipfield_serialize(): def test_skipfield_serialize():

View File

@ -1,24 +1,12 @@
from py.test import raises from py.test import raises
from collections import namedtuple
from pytest import raises from pytest import raises
from graphene import Interface, ObjectType, Schema
from graphene.core.fields import Field, ListField, StringField
from graphql.core import graphql from graphql.core import graphql
from graphene.core.fields import ( from graphql.core.type import (GraphQLInterfaceType, GraphQLObjectType,
Field, GraphQLSchema)
StringField,
ListField,
)
from graphql.core.type import (
GraphQLObjectType,
GraphQLSchema,
GraphQLInterfaceType
)
from graphene import (
Interface,
ObjectType,
Schema
)
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')
@ -63,7 +51,7 @@ def test_schema_query():
def test_query_schema_graphql(): def test_query_schema_graphql():
a = object() object()
query = ''' query = '''
{ {
name name
@ -84,7 +72,7 @@ def test_query_schema_graphql():
def test_query_schema_execute(): def test_query_schema_execute():
a = object() object()
query = ''' query = '''
{ {
name name
@ -107,7 +95,8 @@ def test_query_schema_execute():
def test_schema_get_type_map(): def test_schema_get_type_map():
assert_equal_lists( assert_equal_lists(
schema.schema.get_type_map().keys(), schema.schema.get_type_map().keys(),
['__Field', 'String', 'Pet', 'Character', '__InputValue', '__Directive', '__TypeKind', '__Schema', '__Type', 'Human', '__EnumValue', 'Boolean'] ['__Field', 'String', 'Pet', 'Character', '__InputValue', '__Directive',
'__TypeKind', '__Schema', '__Type', 'Human', '__EnumValue', 'Boolean']
) )

View File

@ -1,22 +1,12 @@
from py.test import raises from py.test import raises
from pytest import raises from pytest import raises
from graphene.core.fields import (
IntField,
StringField,
)
from graphql.core.execution.middlewares.utils import (
tag_resolver,
resolver_has_tag
)
from graphql.core.type import (
GraphQLObjectType,
GraphQLInterfaceType
)
from graphene.core.types import ( from graphene.core.fields import IntField, StringField
Interface
)
from graphene.core.schema import Schema from graphene.core.schema import Schema
from graphene.core.types import Interface
from graphql.core.execution.middlewares.utils import (resolver_has_tag,
tag_resolver)
from graphql.core.type import GraphQLInterfaceType, GraphQLObjectType
class Character(Interface): class Character(Interface):
@ -60,7 +50,7 @@ def test_interface():
def test_interface_cannot_initialize(): def test_interface_cannot_initialize():
with raises(Exception) as excinfo: with raises(Exception) as excinfo:
c = Character() Character()
assert 'An interface cannot be initialized' == str(excinfo.value) assert 'An interface cannot be initialized' == str(excinfo.value)
@ -77,7 +67,8 @@ def test_object_type():
assert object_type.description == 'Human description' assert object_type.description == 'Human description'
assert list(object_type.get_fields().keys()) == ['name', 'friends'] assert list(object_type.get_fields().keys()) == ['name', 'friends']
# assert object_type.get_fields() == {'name': Human._meta.fields_map['name'].internal_field( # assert object_type.get_fields() == {'name': Human._meta.fields_map['name'].internal_field(
# schema), 'friends': Human._meta.fields_map['friends'].internal_field(schema)} # schema), 'friends':
# Human._meta.fields_map['friends'].internal_field(schema)}
assert object_type.get_interfaces() == [schema.T(Character)] assert object_type.get_interfaces() == [schema.T(Character)]
assert Human._meta.fields_map['name'].object_type == Human assert Human._meta.fields_map['name'].object_type == Human

View File

@ -23,7 +23,7 @@ def test_field_no_contributed_raises_error():
def test_node_should_have_same_connection_always(): def test_node_should_have_same_connection_always():
s = object() object()
connection1 = relay.Connection.for_node(OtherNode) connection1 = relay.Connection.for_node(OtherNode)
connection2 = relay.Connection.for_node(OtherNode) connection2 = relay.Connection.for_node(OtherNode)

View File

@ -1,11 +1,8 @@
from graphql.core.type import (
GraphQLInputObjectField
)
import graphene import graphene
from graphene import relay from graphene import relay
from graphene.core.types import InputObjectType
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
@ -41,11 +38,13 @@ def test_mutation_input():
assert list(ChangeNumber.input_type._meta.fields_map.keys()) == ['input'] assert list(ChangeNumber.input_type._meta.fields_map.keys()) == ['input']
_input = ChangeNumber.input_type._meta.fields_map['input'] _input = ChangeNumber.input_type._meta.fields_map['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'] client_mutation_id_field = inner_type._meta.fields_map[
'client_mutation_id']
assert issubclass(inner_type, InputObjectType) assert issubclass(inner_type, InputObjectType)
assert isinstance(client_mutation_id_field, graphene.StringField) assert isinstance(client_mutation_id_field, graphene.StringField)
assert client_mutation_id_field.object_type == inner_type assert client_mutation_id_field.object_type == inner_type
assert isinstance(client_mutation_id_field.internal_field(schema), GraphQLInputObjectField) assert isinstance(client_mutation_id_field.internal_field(
schema), GraphQLInputObjectField)
def test_execute_mutations(): def test_execute_mutations():

View File

@ -1,16 +1,13 @@
from graphql.core.type import (
GraphQLNonNull,
GraphQLID
)
import graphene import graphene
from graphene import relay from graphene import relay
from graphql.core.type import GraphQLID, GraphQLNonNull
schema = graphene.Schema() schema = graphene.Schema()
class MyConnection(relay.Connection): class MyConnection(relay.Connection):
my_custom_field = graphene.StringField(resolve=lambda instance, *_: 'Custom') my_custom_field = graphene.StringField(
resolve=lambda instance, *_: 'Custom')
class MyNode(relay.Node): class MyNode(relay.Node):
@ -23,7 +20,8 @@ class MyNode(relay.Node):
class Query(graphene.ObjectType): class Query(graphene.ObjectType):
my_node = relay.NodeField(MyNode) my_node = relay.NodeField(MyNode)
all_my_nodes = relay.ConnectionField(MyNode, connection_type=MyConnection, customArg=graphene.Argument(graphene.String)) all_my_nodes = relay.ConnectionField(
MyNode, connection_type=MyConnection, customArg=graphene.Argument(graphene.String))
def resolve_all_my_nodes(self, args, info): def resolve_all_my_nodes(self, args, info):
custom_arg = args.get('customArg') custom_arg = args.get('customArg')

View File

@ -1,6 +1,7 @@
import collections import collections
from graphql.core.type import GraphQLEnumType
from graphene.utils.misc import enum_to_graphql_enum from graphene.utils.misc import enum_to_graphql_enum
from graphql.core.type import GraphQLEnumType
item = collections.namedtuple('type', 'name value') item = collections.namedtuple('type', 'name value')
@ -10,4 +11,5 @@ class MyCustomEnum(list):
def test_enum_to_graphql_enum(): def test_enum_to_graphql_enum():
assert isinstance(enum_to_graphql_enum(MyCustomEnum([item('k', 'v')])), GraphQLEnumType) assert isinstance(enum_to_graphql_enum(
MyCustomEnum([item('k', 'v')])), GraphQLEnumType)

View File

@ -1,9 +1,11 @@
from py.test import raises from py.test import raises
from graphene.utils import ProxySnakeDict from graphene.utils import ProxySnakeDict
def test_proxy_snake_dict(): def test_proxy_snake_dict():
my_data = {'one': 1, 'two': 2, 'none': None, 'threeOrFor': 3, 'inside': {'otherCamelCase': 3}} my_data = {'one': 1, 'two': 2, 'none': None,
'threeOrFor': 3, 'inside': {'otherCamelCase': 3}}
p = ProxySnakeDict(my_data) p = ProxySnakeDict(my_data)
assert 'one' in p assert 'one' in p
assert 'two' in p assert 'two' in p

View File

@ -1,4 +1,4 @@
from graphene.utils import to_snake_case, to_camel_case from graphene.utils import to_camel_case, to_snake_case
def test_snake_case(): def test_snake_case():

11
tox.ini
View File

@ -1,5 +1,6 @@
[tox] [tox]
envlist = py27,py33,py34,py35,pypy envlist = flake8,py27,py33,py34,py35,pypy
skipsdist = true
[testenv] [testenv]
deps= deps=
@ -14,7 +15,13 @@ deps=
setenv = setenv =
PYTHONPATH = .:{envdir} PYTHONPATH = .:{envdir}
commands= commands=
py.test tests/ py.test tests/ examples/
[testenv:flake8]
deps = flake8
commands =
pip install -e .
flake8 graphene
[pytest] [pytest]
DJANGO_SETTINGS_MODULE = tests.django_settings DJANGO_SETTINGS_MODULE = tests.django_settings