Merge branch 'refs/heads/master' into docs-playground

This commit is contained in:
Syrus Akbary 2015-11-27 01:46:54 -08:00
commit 4e258b5def
18 changed files with 99 additions and 121 deletions

View File

@ -0,0 +1,31 @@
import graphene
class GeoInput(graphene.InputObjectType):
lat = graphene.Float(required=True)
lng = graphene.Float(required=True)
class Address(graphene.ObjectType):
latlng = graphene.String()
class Query(graphene.ObjectType):
address = graphene.Field(Address, geo=graphene.Argument(GeoInput))
def resolve_address(self, args, info):
geo = args.get('geo')
return Address(latlng="({},{})".format(geo.get('lat'), geo.get('lng')))
schema = graphene.Schema(query=Query)
query = '''
query something{
address(geo: {lat:32.2, lng:12}) {
latlng
}
}
'''
result = schema.execute(query)
print(result.data['address']['latlng'])

View File

@ -21,7 +21,7 @@ query = '''
id id
name name
} }
} }
''' '''
result = schema.execute(query) result = schema.execute(query)
print(result.data['patron']) print(result.data['patron'])

View File

@ -1,4 +1,5 @@
from graphene.contrib.django.types import ( from graphene.contrib.django.types import (
DjangoConnection,
DjangoObjectType, DjangoObjectType,
DjangoInterface, DjangoInterface,
DjangoNode DjangoNode
@ -9,4 +10,4 @@ from graphene.contrib.django.fields import (
) )
__all__ = ['DjangoObjectType', 'DjangoInterface', 'DjangoNode', __all__ = ['DjangoObjectType', 'DjangoInterface', 'DjangoNode',
'DjangoConnectionField', 'DjangoModelField'] 'DjangoConnection', 'DjangoConnectionField', 'DjangoModelField']

View File

@ -1,26 +1,22 @@
import warnings
from ...core.exceptions import SkipField from ...core.exceptions import SkipField
from ...core.fields import Field from ...core.fields import Field
from ...core.types.base import FieldType from ...core.types.base import FieldType
from ...core.types.definitions import List from ...core.types.definitions import List
from ...relay import ConnectionField from ...relay import ConnectionField
from ...relay.utils import is_node from ...relay.utils import is_node
from .utils import get_type_for_model, lazy_map from .utils import get_type_for_model
class DjangoConnectionField(ConnectionField): class DjangoConnectionField(ConnectionField):
def wrap_resolved(self, value, instance, args, info): def __init__(self, *args, **kwargs):
return lazy_map(value, self.type) cls = self.__class__
warnings.warn("Using {} will be not longer supported."
" Use relay.ConnectionField instead".format(cls.__name__),
class LazyListField(Field): FutureWarning)
return super(DjangoConnectionField, self).__init__(*args, **kwargs)
def get_type(self, schema):
return List(self.type)
def resolver(self, instance, args, info):
resolved = super(LazyListField, self).resolver(instance, args, info)
return lazy_map(resolved, self.type)
class ConnectionOrListField(Field): class ConnectionOrListField(Field):
@ -33,8 +29,8 @@ class ConnectionOrListField(Field):
if is_node(field_object_type): if is_node(field_object_type):
field = DjangoConnectionField(field_object_type) field = DjangoConnectionField(field_object_type)
else: else:
field = LazyListField(field_object_type) field = Field(List(field_object_type))
field.contribute_to_class(self.object_type, self.name) field.contribute_to_class(self.object_type, self.attname)
return schema.T(field) return schema.T(field)

View File

@ -69,7 +69,7 @@ def test_node_replacedfield():
def test_interface_resolve_type(): def test_interface_resolve_type():
resolve_type = Character.resolve_type(schema, Human()) resolve_type = Character._resolve_type(schema, Human())
assert isinstance(resolve_type, GraphQLObjectType) assert isinstance(resolve_type, GraphQLObjectType)

View File

@ -2,10 +2,10 @@ import six
from ...core.types import BaseObjectType, ObjectTypeMeta from ...core.types import BaseObjectType, ObjectTypeMeta
from ...relay.fields import GlobalIDField from ...relay.fields import GlobalIDField
from ...relay.types import BaseNode from ...relay.types import BaseNode, Connection
from .converter import convert_django_field from .converter import convert_django_field
from .options import DjangoOptions from .options import DjangoOptions
from .utils import get_reverse_fields from .utils import get_reverse_fields, maybe_queryset
class DjangoObjectTypeMeta(ObjectTypeMeta): class DjangoObjectTypeMeta(ObjectTypeMeta):
@ -30,7 +30,7 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
is_excluded = field.name in cls._meta.exclude_fields or is_already_created is_excluded = field.name in cls._meta.exclude_fields or is_already_created
if is_not_in_only or is_excluded: if is_not_in_only or is_excluded:
# We skip this field if we specify only_fields and is not # We skip this field if we specify only_fields and is not
# in there. Or when we excldue this field in exclude_fields # in there. Or when we exclude this field in exclude_fields
continue continue
converted_field = convert_django_field(field) converted_field = convert_django_field(field)
cls.add_to_class(field.name, converted_field) cls.add_to_class(field.name, converted_field)
@ -71,6 +71,14 @@ class DjangoInterface(six.with_metaclass(
pass pass
class DjangoConnection(Connection):
@classmethod
def from_list(cls, iterable, *args, **kwargs):
iterable = maybe_queryset(iterable)
return super(DjangoConnection, cls).from_list(iterable, *args, **kwargs)
class DjangoNode(BaseNode, DjangoInterface): class DjangoNode(BaseNode, DjangoInterface):
id = GlobalIDField() id = GlobalIDField()
@ -81,3 +89,5 @@ class DjangoNode(BaseNode, DjangoInterface):
return cls(instance) return cls(instance)
except cls._meta.model.DoesNotExist: except cls._meta.model.DoesNotExist:
return None return None
connection_type = DjangoConnection

View File

@ -1,8 +1,5 @@
from django.db import models from django.db import models
from django.db.models.manager import Manager from django.db.models.manager import Manager
from django.db.models.query import QuerySet
from ...utils import LazyMap
def get_type_for_model(schema, model): def get_type_for_model(schema, model):
@ -22,9 +19,7 @@ def get_reverse_fields(model):
yield related yield related
def lazy_map(value, func): def maybe_queryset(value):
if isinstance(value, Manager): if isinstance(value, Manager):
value = value.get_queryset() value = value.get_queryset()
if isinstance(value, QuerySet):
return LazyMap(value, func)
return value return value

View File

@ -13,7 +13,10 @@ class Character(Interface):
class Pet(ObjectType): class Pet(ObjectType):
type = String(resolver=lambda *_: 'Dog') type = String()
def resolve_type(self, args, info):
return 'Dog'
class Human(Character): class Human(Character):

View File

@ -182,7 +182,7 @@ class BaseObjectType(BaseType):
signals.post_init.send(self.__class__, instance=self) signals.post_init.send(self.__class__, instance=self)
@classmethod @classmethod
def resolve_type(cls, schema, instance, *args): def _resolve_type(cls, schema, instance, *args):
return schema.T(instance.__class__) return schema.T(instance.__class__)
@classmethod @classmethod
@ -191,7 +191,7 @@ class BaseObjectType(BaseType):
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=partial(cls.get_fields, schema) fields=partial(cls.get_fields, schema)
) )
elif cls._meta.is_union: elif cls._meta.is_union:
@ -219,6 +219,10 @@ class BaseObjectType(BaseType):
return OrderedDict(fields) return OrderedDict(fields)
@classmethod
def wrap(cls, instance, args, info):
return cls(_root=instance)
class Interface(six.with_metaclass(ObjectTypeMeta, BaseObjectType)): class Interface(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
pass pass

View File

@ -75,7 +75,7 @@ def test_union_cannot_initialize():
def test_interface_resolve_type(): def test_interface_resolve_type():
resolve_type = Character.resolve_type(schema, Human(object())) resolve_type = Character._resolve_type(schema, Human(object()))
assert isinstance(resolve_type, GraphQLObjectType) assert isinstance(resolve_type, GraphQLObjectType)

View File

@ -1,6 +1,3 @@
from collections import Iterable
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
from ..core.fields import Field from ..core.fields import Field
@ -30,24 +27,12 @@ class ConnectionField(Field):
return value return value
def resolver(self, instance, args, info): def resolver(self, instance, args, info):
from graphene.relay.types import PageInfo
schema = info.schema.graphene_schema schema = info.schema.graphene_schema
connection_type = self.get_type(schema)
resolved = super(ConnectionField, self).resolver(instance, args, info) resolved = super(ConnectionField, self).resolver(instance, args, info)
if resolved: if isinstance(resolved, connection_type):
resolved = self.wrap_resolved(resolved, instance, args, info) return resolved
assert isinstance( return connection_type.from_list(resolved, args, info)
resolved, Iterable), 'Resolved value from the connection field have to be iterable'
type = schema.T(self.type)
node = schema.objecttype(type)
connection_type = self.get_connection_type(node)
edge_type = self.get_edge_type(node)
connection = connection_from_list(
resolved, args, connection_type=connection_type,
edge_type=edge_type, pageinfo_type=PageInfo)
connection.set_connection_data(resolved)
return connection
def get_connection_type(self, node): def get_connection_type(self, node):
connection_type = self.connection_type or node.get_connection_type() connection_type = self.connection_type or node.get_connection_type()

View File

@ -1,6 +1,9 @@
import inspect import inspect
import warnings import warnings
from collections import Iterable
from functools import wraps from functools import wraps
from graphql_relay.connection.arrayconnection import connection_from_list
from graphql_relay.node.node import to_global_id from graphql_relay.node.node import to_global_id
from ..core.types import (Boolean, Field, InputObjectType, Interface, List, from ..core.types import (Boolean, Field, InputObjectType, Interface, List,
@ -63,6 +66,16 @@ class Connection(ObjectType):
(cls,), (cls,),
{'edge_type': edge_type, 'edges': edges}) {'edge_type': edge_type, 'edges': edges})
@classmethod
def from_list(cls, iterable, args, info):
assert isinstance(
iterable, Iterable), 'Resolved value from the connection field have to be iterable'
connection = connection_from_list(
iterable, args, connection_type=cls,
edge_type=cls.edge_type, pageinfo_type=PageInfo)
connection.set_connection_data(iterable)
return connection
def set_connection_data(self, data): def set_connection_data(self, data):
self._connection_data = data self._connection_data = data

View File

@ -1,4 +1,9 @@
from blinker import Signal try:
from blinker import Signal
except ImportError:
class Signal(object):
def send(self, *args, **kwargs):
pass
init_schema = Signal() init_schema = Signal()
class_prepared = Signal() class_prepared = Signal()

View File

@ -1,11 +1,10 @@
from .str_converters import to_camel_case, to_snake_case from .str_converters import to_camel_case, to_snake_case
from .proxy_snake_dict import ProxySnakeDict from .proxy_snake_dict import ProxySnakeDict
from .caching import cached_property, memoize from .caching import cached_property, memoize
from .lazymap import LazyMap
from .misc import enum_to_graphql_enum from .misc import enum_to_graphql_enum
from .resolve_only_args import resolve_only_args from .resolve_only_args import resolve_only_args
__all__ = ['to_camel_case', 'to_snake_case', 'ProxySnakeDict', __all__ = ['to_camel_case', 'to_snake_case', 'ProxySnakeDict',
'cached_property', 'memoize', 'LazyMap', 'enum_to_graphql_enum', 'cached_property', 'memoize', 'enum_to_graphql_enum',
'resolve_only_args'] 'resolve_only_args']

View File

@ -1,43 +0,0 @@
class LazyMap(object):
def __init__(self, origin, _map, state=None):
self._origin = origin
self._origin_iter = origin.__iter__()
self._state = state or []
self._finished = False
self._map = _map
def __iter__(self):
return self if not self._finished else iter(self._state)
def iter(self):
return self.__iter__()
def __len__(self):
return self._origin.__len__()
def __next__(self):
try:
n = next(self._origin_iter)
n = self._map(n)
except StopIteration as e:
self._finished = True
raise e
else:
self._state.append(n)
return n
def next(self):
return self.__next__()
def __getitem__(self, key):
item = self._origin[key]
if isinstance(key, slice):
return LazyMap(item, self._map)
return self._map(item)
def __getattr__(self, name):
return getattr(self._origin, name)
def __repr__(self):
return "<LazyMap %s>" % repr(self._origin)

View File

@ -1,23 +0,0 @@
from py.test import raises
from ..lazymap import LazyMap
def test_lazymap():
data = list(range(10))
lm = LazyMap(data, lambda x: 2 * x)
assert len(lm) == 10
assert lm[1] == 2
assert isinstance(lm[1:4], LazyMap)
assert lm.append == data.append
assert repr(lm) == '<LazyMap [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>'
def test_lazymap_iter():
data = list(range(2))
lm = LazyMap(data, lambda x: 2 * x)
iter_lm = iter(lm)
assert iter_lm.next() == 0
assert iter_lm.next() == 2
with raises(StopIteration):
iter_lm.next()

View File

@ -4,3 +4,6 @@ max-line-length = 120
[coverage:run] [coverage:run]
omit = core/ntypes/tests/* omit = core/ntypes/tests/*
[isort]
known_first_party=graphene

View File

@ -24,7 +24,7 @@ class PyTest(TestCommand):
setup( setup(
name='graphene', name='graphene',
version='0.4.1.1', version='0.4.2',
description='Graphene: Python DSL for GraphQL', description='Graphene: Python DSL for GraphQL',
long_description=open('README.rst').read(), long_description=open('README.rst').read(),
@ -55,7 +55,6 @@ setup(
install_requires=[ install_requires=[
'six>=1.10.0', 'six>=1.10.0',
'blinker',
'graphql-core==0.4.9', 'graphql-core==0.4.9',
'graphql-relay==0.3.3' 'graphql-relay==0.3.3'
], ],