Skip to content

Commit dbc2ee4

Browse files
authored
Merge pull request #1 from graphql-python/master
Sync with original repo.
2 parents e94716d + 2594cdb commit dbc2ee4

File tree

14 files changed

+124
-30
lines changed

14 files changed

+124
-30
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ htmlcov/
4242
.coverage
4343
.coverage.*
4444
.cache
45+
.pytest_cache
4546
nosetests.xml
4647
coverage.xml
4748
*,cover

UPGRADE-v2.0.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ developer has to write to use them.
2121

2222

2323
> The type metaclasses are now deleted as they are no longer necessary. If your code was depending
24-
> on this strategy for creating custom attrs, see an [example on how to do it in 2.0](https://github.com/graphql-python/graphene/blob/2.0/graphene/tests/issues/test_425.py).
24+
> on this strategy for creating custom attrs, see an [example on how to do it in 2.0](https://github.com/graphql-python/graphene/blob/v2.0.0/graphene/tests/issues/test_425.py).
2525
2626
## Deprecations
2727

docs/relay/nodes.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ Example of a custom node:
5555
return '{}:{}'.format(type, id)
5656
5757
@staticmethod
58-
def get_node_from_global_id(info, global_id, only_node=None):
58+
def get_node_from_global_id(info, global_id, only_type=None):
5959
type, id = global_id.split(':')
60-
if only_node:
60+
if only_type:
6161
# We assure that the node type that we want to retrieve
6262
# is the same that was indicated in the field type
63-
assert type == only_node._meta.name, 'Received not compatible node.'
63+
assert type == only_type._meta.name, 'Received not compatible node.'
6464
6565
if type == 'User':
6666
return get_user(id)

docs/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Required library
22
Sphinx==1.5.3
33
# Docs template
4-
https://github.com/graphql-python/graphene-python.org/archive/docs.zip
4+
http://graphene-python.org/sphinx_graphene_theme.zip

docs/types/list-and-nonnull.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,24 @@ Lists work in a similar way: We can use a type modifier to mark a type as a
4848
``List``, which indicates that this field will return a list of that type.
4949
It works the same for arguments, where the validation step will expect a list
5050
for that value.
51+
52+
NonNull Lists
53+
-------------
54+
55+
By default items in a list will be considered nullable. To define a list without
56+
any nullable items the type needs to be marked as ``NonNull``. For example:
57+
58+
.. code:: python
59+
60+
import graphene
61+
62+
class Character(graphene.ObjectType):
63+
appears_in = graphene.List(graphene.NonNull(graphene.String))
64+
65+
The above results in the type definition:
66+
67+
.. code::
68+
69+
type Character {
70+
appearsIn: [String!]
71+
}

graphene/relay/connection.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,19 @@ def __init__(self, type, *args, **kwargs):
9999
def type(self):
100100
type = super(IterableConnectionField, self).type
101101
connection_type = type
102-
if is_node(type):
102+
if isinstance(type, NonNull):
103+
connection_type = type.of_type
104+
105+
if is_node(connection_type):
103106
raise Exception(
104107
"ConnectionField's now need a explicit ConnectionType for Nodes.\n"
105-
"Read more: https://github.com/graphql-python/graphene/blob/2.0/UPGRADE-v2.0.md#node-connections"
108+
"Read more: https://github.com/graphql-python/graphene/blob/v2.0.0/UPGRADE-v2.0.md#node-connections"
106109
)
107110

108111
assert issubclass(connection_type, Connection), (
109112
'{} type have to be a subclass of Connection. Received "{}".'
110113
).format(self.__class__.__name__, connection_type)
111-
return connection_type
114+
return type
112115

113116
@classmethod
114117
def resolve_connection(cls, connection_type, args, resolved):
@@ -133,6 +136,9 @@ def resolve_connection(cls, connection_type, args, resolved):
133136
def connection_resolver(cls, resolver, connection_type, root, info, **args):
134137
resolved = resolver(root, info, **args)
135138

139+
if isinstance(connection_type, NonNull):
140+
connection_type = connection_type.of_type
141+
136142
on_resolve = partial(cls.resolve_connection, connection_type, args)
137143
if is_thenable(resolved):
138144
return Promise.resolve(resolved).then(on_resolve)

graphene/relay/tests/test_connection.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22

3-
from ...types import Argument, Field, Int, List, NonNull, ObjectType, String
3+
from ...types import Argument, Field, Int, List, NonNull, ObjectType, String, Schema
44
from ..connection import Connection, ConnectionField, PageInfo
55
from ..node import Node
66

@@ -155,3 +155,23 @@ class Meta:
155155
'last': Argument(Int),
156156
'extra': Argument(String),
157157
}
158+
159+
160+
def test_connectionfield_required():
161+
class MyObjectConnection(Connection):
162+
163+
class Meta:
164+
node = MyObject
165+
166+
class Query(ObjectType):
167+
test_connection = ConnectionField(MyObjectConnection, required=True)
168+
169+
def resolve_test_connection(root, info, **args):
170+
return []
171+
172+
schema = Schema(query=Query)
173+
executed = schema.execute(
174+
'{ testConnection { edges { cursor } } }'
175+
)
176+
assert not executed.errors
177+
assert executed.data == {'testConnection': {'edges': []}}

graphene/types/abstracttype.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ class AbstractType(SubclassWithMeta):
77
def __init_subclass__(cls, *args, **kwargs):
88
warn_deprecation(
99
"Abstract type is deprecated, please use normal object inheritance instead.\n"
10-
"See more: https://github.com/graphql-python/graphene/blob/2.0/UPGRADE-v2.0.md#deprecations"
10+
"See more: https://github.com/graphql-python/graphene/blob/v2.0.0/UPGRADE-v2.0.md#deprecations"
1111
)
1212
super(AbstractType, cls).__init_subclass__(*args, **kwargs)

graphene/types/enum.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ class EnumOptions(BaseOptions):
2727
class EnumMeta(SubclassWithMeta_Meta):
2828

2929
def __new__(cls, name, bases, classdict, **options):
30-
enum = PyEnum(cls.__name__, OrderedDict(classdict, __eq__=eq_enum))
30+
enum_members = OrderedDict(classdict, __eq__=eq_enum)
31+
# We remove the Meta attribute from the class to not collide
32+
# with the enum values.
33+
enum_members.pop('Meta', None)
34+
enum = PyEnum(cls.__name__, enum_members)
3135
return SubclassWithMeta_Meta.__new__(cls, name, bases, OrderedDict(classdict, __enum__=enum), **options)
3236

3337
def get(cls, value):

graphene/types/mutation.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ def __init_subclass_with_meta__(cls, resolver=None, output=None, arguments=None,
5050
warn_deprecation((
5151
"Please use {name}.Arguments instead of {name}.Input."
5252
"Input is now only used in ClientMutationID.\n"
53-
"Read more: https://github.com/graphql-python/graphene/blob/2.0/UPGRADE-v2.0.md#mutation-input"
53+
"Read more:"
54+
" https://github.com/graphql-python/graphene/blob/v2.0.0/UPGRADE-v2.0.md#mutation-input"
5455
).format(name=cls.__name__))
5556

5657
if input_class:
@@ -75,7 +76,12 @@ def __init_subclass_with_meta__(cls, resolver=None, output=None, arguments=None,
7576
super(Mutation, cls).__init_subclass_with_meta__(_meta=_meta, **options)
7677

7778
@classmethod
78-
def Field(cls, *args, **kwargs):
79+
def Field(cls, name=None, description=None, deprecation_reason=None):
7980
return Field(
80-
cls._meta.output, args=cls._meta.arguments, resolver=cls._meta.resolver
81+
cls._meta.output,
82+
args=cls._meta.arguments,
83+
resolver=cls._meta.resolver,
84+
name=name,
85+
description=description,
86+
deprecation_reason=deprecation_reason,
8187
)

0 commit comments

Comments
 (0)