mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-23 01:56:54 +03:00
Merge branch 'master' into feature/django
This commit is contained in:
commit
afd7aa8d72
|
@ -1,6 +1,9 @@
|
||||||
import six
|
import six
|
||||||
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 graphene.utils import LazyList
|
||||||
|
|
||||||
from graphene import Argument, String
|
from graphene import Argument, String
|
||||||
|
|
||||||
|
@ -24,9 +27,20 @@ def get_reverse_fields(model):
|
||||||
yield related
|
yield related
|
||||||
|
|
||||||
|
|
||||||
|
class WrappedQueryset(LazyList):
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
# Dont calculate the length using len(queryset), as this will
|
||||||
|
# evaluate the whole queryset and return it's length.
|
||||||
|
# Use .count() instead
|
||||||
|
return self._origin.count()
|
||||||
|
|
||||||
|
|
||||||
def maybe_queryset(value):
|
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 WrappedQueryset(value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import copy
|
import copy
|
||||||
import inspect
|
import inspect
|
||||||
|
from functools import partial
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
@ -48,8 +49,8 @@ class ClassTypeMeta(type):
|
||||||
|
|
||||||
if not cls._meta.abstract:
|
if not cls._meta.abstract:
|
||||||
from ..types import List, NonNull
|
from ..types import List, NonNull
|
||||||
setattr(cls, 'NonNull', NonNull(cls))
|
setattr(cls, 'NonNull', partial(NonNull, cls))
|
||||||
setattr(cls, 'List', List(cls))
|
setattr(cls, 'List', partial(List, cls))
|
||||||
|
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
|
|
|
@ -23,15 +23,26 @@ def test_classtype_advanced():
|
||||||
def test_classtype_definition_list():
|
def test_classtype_definition_list():
|
||||||
class Character(ClassType):
|
class Character(ClassType):
|
||||||
'''Character description'''
|
'''Character description'''
|
||||||
assert isinstance(Character.List, List)
|
assert isinstance(Character.List(), List)
|
||||||
assert Character.List.of_type == Character
|
assert Character.List().of_type == Character
|
||||||
|
|
||||||
|
|
||||||
def test_classtype_definition_nonnull():
|
def test_classtype_definition_nonnull():
|
||||||
class Character(ClassType):
|
class Character(ClassType):
|
||||||
'''Character description'''
|
'''Character description'''
|
||||||
assert isinstance(Character.NonNull, NonNull)
|
assert isinstance(Character.NonNull(), NonNull)
|
||||||
assert Character.NonNull.of_type == Character
|
assert Character.NonNull().of_type == Character
|
||||||
|
|
||||||
|
|
||||||
|
def test_fieldsclasstype_definition_order():
|
||||||
|
class Character(ClassType):
|
||||||
|
'''Character description'''
|
||||||
|
|
||||||
|
class Query(FieldsClassType):
|
||||||
|
name = String()
|
||||||
|
char = Character.NonNull()
|
||||||
|
|
||||||
|
assert list(Query._meta.fields_map.keys()) == ['name', 'char']
|
||||||
|
|
||||||
|
|
||||||
def test_fieldsclasstype():
|
def test_fieldsclasstype():
|
||||||
|
|
|
@ -4,6 +4,7 @@ from collections import Iterable
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from graphql_relay.connection.arrayconnection import connection_from_list
|
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
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,9 @@ from .proxy_snake_dict import ProxySnakeDict
|
||||||
from .caching import cached_property, memoize
|
from .caching import cached_property, memoize
|
||||||
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
|
||||||
|
from .lazylist import LazyList
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['to_camel_case', 'to_snake_case', 'ProxySnakeDict',
|
__all__ = ['to_camel_case', 'to_snake_case', 'ProxySnakeDict',
|
||||||
'cached_property', 'memoize', 'enum_to_graphql_enum',
|
'cached_property', 'memoize', 'enum_to_graphql_enum',
|
||||||
'resolve_only_args']
|
'resolve_only_args', 'LazyList']
|
||||||
|
|
43
graphene/utils/lazylist.py
Normal file
43
graphene/utils/lazylist.py
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
class LazyList(object):
|
||||||
|
|
||||||
|
def __init__(self, origin, state=None):
|
||||||
|
self._origin = origin
|
||||||
|
self._state = state or []
|
||||||
|
self._origin_iter = None
|
||||||
|
self._finished = False
|
||||||
|
|
||||||
|
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:
|
||||||
|
if not self._origin_iter:
|
||||||
|
self._origin_iter = self._origin.__iter__()
|
||||||
|
n = next(self._origin_iter)
|
||||||
|
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 self.__class__(item)
|
||||||
|
return item
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self._origin, name)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<{} {}>".format(self.__class__.__name__, repr(self._origin))
|
23
graphene/utils/tests/test_lazylist.py
Normal file
23
graphene/utils/tests/test_lazylist.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
from py.test import raises
|
||||||
|
|
||||||
|
from ..lazylist import LazyList
|
||||||
|
|
||||||
|
|
||||||
|
def test_lazymap():
|
||||||
|
data = list(range(10))
|
||||||
|
lm = LazyList(data)
|
||||||
|
assert len(lm) == 10
|
||||||
|
assert lm[1] == 1
|
||||||
|
assert isinstance(lm[1:4], LazyList)
|
||||||
|
assert lm.append == data.append
|
||||||
|
assert repr(lm) == '<LazyList [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>'
|
||||||
|
|
||||||
|
|
||||||
|
def test_lazymap_iter():
|
||||||
|
data = list(range(2))
|
||||||
|
lm = LazyList(data)
|
||||||
|
iter_lm = iter(lm)
|
||||||
|
assert iter_lm.next() == 0
|
||||||
|
assert iter_lm.next() == 1
|
||||||
|
with raises(StopIteration):
|
||||||
|
iter_lm.next()
|
2
setup.py
2
setup.py
|
@ -24,7 +24,7 @@ class PyTest(TestCommand):
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='graphene',
|
name='graphene',
|
||||||
version='0.4.2',
|
version='0.4.3',
|
||||||
|
|
||||||
description='Graphene: Python DSL for GraphQL',
|
description='Graphene: Python DSL for GraphQL',
|
||||||
long_description=open('README.rst').read(),
|
long_description=open('README.rst').read(),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user