Skip to content

Commit afd7aa8

Browse files
committed
Merge branch 'master' into feature/django
2 parents bfd43bc + afdddaf commit afd7aa8

File tree

8 files changed

+102
-8
lines changed

8 files changed

+102
-8
lines changed

graphene/contrib/django/utils.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import six
22
from django.db import models
33
from django.db.models.manager import Manager
4+
from django.db.models.query import QuerySet
5+
6+
from graphene.utils import LazyList
47

58
from graphene import Argument, String
69

@@ -24,9 +27,20 @@ def get_reverse_fields(model):
2427
yield related
2528

2629

30+
class WrappedQueryset(LazyList):
31+
32+
def __len__(self):
33+
# Dont calculate the length using len(queryset), as this will
34+
# evaluate the whole queryset and return it's length.
35+
# Use .count() instead
36+
return self._origin.count()
37+
38+
2739
def maybe_queryset(value):
2840
if isinstance(value, Manager):
2941
value = value.get_queryset()
42+
if isinstance(value, QuerySet):
43+
return WrappedQueryset(value)
3044
return value
3145

3246

graphene/core/classtypes/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import copy
22
import inspect
3+
from functools import partial
34
from collections import OrderedDict
45

56
import six
@@ -48,8 +49,8 @@ def construct(cls, bases, attrs):
4849

4950
if not cls._meta.abstract:
5051
from ..types import List, NonNull
51-
setattr(cls, 'NonNull', NonNull(cls))
52-
setattr(cls, 'List', List(cls))
52+
setattr(cls, 'NonNull', partial(NonNull, cls))
53+
setattr(cls, 'List', partial(List, cls))
5354

5455
return cls
5556

graphene/core/classtypes/tests/test_base.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,26 @@ class Meta:
2323
def test_classtype_definition_list():
2424
class Character(ClassType):
2525
'''Character description'''
26-
assert isinstance(Character.List, List)
27-
assert Character.List.of_type == Character
26+
assert isinstance(Character.List(), List)
27+
assert Character.List().of_type == Character
2828

2929

3030
def test_classtype_definition_nonnull():
3131
class Character(ClassType):
3232
'''Character description'''
33-
assert isinstance(Character.NonNull, NonNull)
34-
assert Character.NonNull.of_type == Character
33+
assert isinstance(Character.NonNull(), NonNull)
34+
assert Character.NonNull().of_type == Character
35+
36+
37+
def test_fieldsclasstype_definition_order():
38+
class Character(ClassType):
39+
'''Character description'''
40+
41+
class Query(FieldsClassType):
42+
name = String()
43+
char = Character.NonNull()
44+
45+
assert list(Query._meta.fields_map.keys()) == ['name', 'char']
3546

3647

3748
def test_fieldsclasstype():

graphene/relay/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from functools import wraps
55

66
import six
7+
78
from graphql_relay.connection.arrayconnection import connection_from_list
89
from graphql_relay.node.node import to_global_id
910

graphene/utils/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
from .caching import cached_property, memoize
44
from .misc import enum_to_graphql_enum
55
from .resolve_only_args import resolve_only_args
6+
from .lazylist import LazyList
67

78

89
__all__ = ['to_camel_case', 'to_snake_case', 'ProxySnakeDict',
910
'cached_property', 'memoize', 'enum_to_graphql_enum',
10-
'resolve_only_args']
11+
'resolve_only_args', 'LazyList']

graphene/utils/lazylist.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
class LazyList(object):
2+
3+
def __init__(self, origin, state=None):
4+
self._origin = origin
5+
self._state = state or []
6+
self._origin_iter = None
7+
self._finished = False
8+
9+
def __iter__(self):
10+
return self if not self._finished else iter(self._state)
11+
12+
def iter(self):
13+
return self.__iter__()
14+
15+
def __len__(self):
16+
return self._origin.__len__()
17+
18+
def __next__(self):
19+
try:
20+
if not self._origin_iter:
21+
self._origin_iter = self._origin.__iter__()
22+
n = next(self._origin_iter)
23+
except StopIteration as e:
24+
self._finished = True
25+
raise e
26+
else:
27+
self._state.append(n)
28+
return n
29+
30+
def next(self):
31+
return self.__next__()
32+
33+
def __getitem__(self, key):
34+
item = self._origin[key]
35+
if isinstance(key, slice):
36+
return self.__class__(item)
37+
return item
38+
39+
def __getattr__(self, name):
40+
return getattr(self._origin, name)
41+
42+
def __repr__(self):
43+
return "<{} {}>".format(self.__class__.__name__, repr(self._origin))

graphene/utils/tests/test_lazylist.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from py.test import raises
2+
3+
from ..lazylist import LazyList
4+
5+
6+
def test_lazymap():
7+
data = list(range(10))
8+
lm = LazyList(data)
9+
assert len(lm) == 10
10+
assert lm[1] == 1
11+
assert isinstance(lm[1:4], LazyList)
12+
assert lm.append == data.append
13+
assert repr(lm) == '<LazyList [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>'
14+
15+
16+
def test_lazymap_iter():
17+
data = list(range(2))
18+
lm = LazyList(data)
19+
iter_lm = iter(lm)
20+
assert iter_lm.next() == 0
21+
assert iter_lm.next() == 1
22+
with raises(StopIteration):
23+
iter_lm.next()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def run_tests(self):
2424

2525
setup(
2626
name='graphene',
27-
version='0.4.2',
27+
version='0.4.3',
2828

2929
description='Graphene: Python DSL for GraphQL',
3030
long_description=open('README.rst').read(),

0 commit comments

Comments
 (0)