Skip to content

Commit 10d22de

Browse files
author
Jean-Louis Fuchs
authored
graphql 3.0 and graphene 3.0 final rebase (#951)
1 parent 77b9832 commit 10d22de

20 files changed

+422
-316
lines changed

.github/workflows/tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
strategy:
99
max-parallel: 4
1010
matrix:
11-
django: ["1.11", "2.2", "3.0"]
11+
django: ["2.2", "3.0"]
1212
python-version: ["3.6", "3.7", "3.8"]
1313

1414
steps:

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ A [Django](https://www.djangoproject.com/) integration for [Graphene](http://gra
2828
For installing graphene, just run this command in your shell
2929

3030
```bash
31-
pip install "graphene-django>=2.0"
31+
pip install "graphene-django>=3"
3232
```
3333

3434
### Settings

README.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ For installing graphene, just run this command in your shell
2323

2424
.. code:: bash
2525
26-
pip install "graphene-django>=2.0"
26+
pip install "graphene-django>=3"
2727
2828
Settings
2929
~~~~~~~~

docs/authorization.rst

+1-10
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,7 @@ To restrict users from accessing the GraphQL API page the standard Django LoginR
166166
167167
After this, you can use the new ``PrivateGraphQLView`` in the project's URL Configuration file ``url.py``:
168168

169-
For Django 1.11:
170-
171-
.. code:: python
172-
173-
urlpatterns = [
174-
# some other urls
175-
url(r'^graphql$', PrivateGraphQLView.as_view(graphiql=True, schema=schema)),
176-
]
177-
178-
For Django 2.0 and above:
169+
For Django 2.2 and above:
179170

180171
.. code:: python
181172

docs/filtering.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ Filtering
22
=========
33

44
Graphene integrates with
5-
`django-filter <https://django-filter.readthedocs.io/en/master/>`__ to provide filtering of results. See the `usage
6-
documentation <https://django-filter.readthedocs.io/en/master/guide/usage.html#the-filter>`__
5+
`django-filter <https://django-filter.readthedocs.io/en/master/>`__ to provide filtering of results.
6+
See the `usage documentation <https://django-filter.readthedocs.io/en/master/guide/usage.html#the-filter>`__
77
for details on the format for ``filter_fields``.
88

99
This filtering is automatically available when implementing a ``relay.Node``.

docs/installation.rst

+2-14
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Requirements
88

99
Graphene-Django currently supports the following versions of Django:
1010

11-
* >= Django 1.11
11+
* >= Django 2.2
1212

1313
Installation
1414
------------
@@ -32,19 +32,7 @@ Add ``graphene_django`` to the ``INSTALLED_APPS`` in the ``settings.py`` file of
3232
3333
We need to add a ``graphql`` URL to the ``urls.py`` of your Django project:
3434

35-
For Django 1.11:
36-
37-
.. code:: python
38-
39-
from django.conf.urls import url
40-
from graphene_django.views import GraphQLView
41-
42-
urlpatterns = [
43-
# ...
44-
url(r"graphql", GraphQLView.as_view(graphiql=True)),
45-
]
46-
47-
For Django 2.0 and above:
35+
For Django 2.2 and above:
4836

4937
.. code:: python
5038

graphene_django/converter.py

+18-10
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33

44
from django.db import models
55
from django.utils.encoding import force_str
6+
from django.utils.functional import Promise
67
from django.utils.module_loading import import_string
7-
88
from graphene import (
99
ID,
10+
UUID,
1011
Boolean,
12+
Date,
13+
DateTime,
1114
Dynamic,
1215
Enum,
1316
Field,
@@ -16,25 +19,23 @@
1619
List,
1720
NonNull,
1821
String,
19-
UUID,
20-
DateTime,
21-
Date,
2222
Time,
2323
)
2424
from graphene.types.json import JSONString
2525
from graphene.utils.str_converters import to_camel_case, to_const
26-
from graphql import assert_valid_name
26+
from graphql import GraphQLError, assert_valid_name
27+
from graphql.pyutils import register_description
2728

28-
from .settings import graphene_settings
2929
from .compat import ArrayField, HStoreField, JSONField, RangeField
30-
from .fields import DjangoListField, DjangoConnectionField
30+
from .fields import DjangoConnectionField, DjangoListField
31+
from .settings import graphene_settings
3132

3233

3334
def convert_choice_name(name):
3435
name = to_const(force_str(name))
3536
try:
3637
assert_valid_name(name)
37-
except AssertionError:
38+
except GraphQLError:
3839
name = "A_%s" % name
3940
return name
4041

@@ -52,7 +53,9 @@ def get_choices(choices):
5253
while name in converted_names:
5354
name += "_" + str(len(converted_names))
5455
converted_names.append(name)
55-
description = help_text
56+
description = str(
57+
help_text
58+
) # TODO: translatable description: https://github.com/graphql-python/graphql-core-next/issues/58
5659
yield name, value, description
5760

5861

@@ -64,7 +67,7 @@ def convert_choices_to_named_enum_with_descriptions(name, choices):
6467
class EnumWithDescriptionsType(object):
6568
@property
6669
def description(self):
67-
return named_choices_descriptions[self.name]
70+
return str(named_choices_descriptions[self.name])
6871

6972
return Enum(name, list(named_choices), type=EnumWithDescriptionsType)
7073

@@ -276,3 +279,8 @@ def convert_postgres_range_to_string(field, registry=None):
276279
if not isinstance(inner_type, (List, NonNull)):
277280
inner_type = type(inner_type)
278281
return List(inner_type, description=field.help_text, required=not field.null)
282+
283+
284+
# Register Django lazy()-wrapped values as GraphQL description/help_text.
285+
# This is needed for using lazy translations, see https://github.com/graphql-python/graphql-core-next/issues/58.
286+
register_description(Promise)

graphene_django/debug/middleware.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def get_debug_promise(self):
1717
if not self.debug_promise:
1818
self.debug_promise = Promise.all(self.promises)
1919
self.promises = []
20-
return self.debug_promise.then(self.on_resolve_all_promises)
20+
return self.debug_promise.then(self.on_resolve_all_promises).get()
2121

2222
def on_resolve_all_promises(self, values):
2323
if self.promises:

graphene_django/debug/tests/test_query.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class Meta:
6868

6969
class Query(graphene.ObjectType):
7070
reporter = graphene.Field(ReporterType)
71-
debug = graphene.Field(DjangoDebug, name="__debug")
71+
debug = graphene.Field(DjangoDebug, name="_debug")
7272

7373
def resolve_reporter(self, info, **args):
7474
return Reporter.objects.first()
@@ -82,7 +82,7 @@ def resolve_reporter(self, info, **args):
8282
pets { edges { node { lastName } } }
8383
} } }
8484
}
85-
__debug {
85+
_debug {
8686
sql {
8787
rawSql
8888
}
@@ -110,12 +110,12 @@ def resolve_reporter(self, info, **args):
110110
)
111111
assert not result.errors
112112
query = str(Reporter.objects.order_by("pk")[:1].query)
113-
assert result.data["__debug"]["sql"][0]["rawSql"] == query
114-
assert "COUNT" in result.data["__debug"]["sql"][1]["rawSql"]
115-
assert "tests_reporter_pets" in result.data["__debug"]["sql"][2]["rawSql"]
116-
assert "COUNT" in result.data["__debug"]["sql"][3]["rawSql"]
117-
assert "tests_reporter_pets" in result.data["__debug"]["sql"][4]["rawSql"]
118-
assert len(result.data["__debug"]["sql"]) == 5
113+
assert result.data["_debug"]["sql"][0]["rawSql"] == query
114+
assert "COUNT" in result.data["_debug"]["sql"][1]["rawSql"]
115+
assert "tests_reporter_pets" in result.data["_debug"]["sql"][2]["rawSql"]
116+
assert "COUNT" in result.data["_debug"]["sql"][3]["rawSql"]
117+
assert "tests_reporter_pets" in result.data["_debug"]["sql"][4]["rawSql"]
118+
assert len(result.data["_debug"]["sql"]) == 5
119119

120120
assert result.data["reporter"] == expected["reporter"]
121121

graphene_django/fields.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from functools import partial
22

33
from django.db.models.query import QuerySet
4-
from graphql_relay.connection.arrayconnection import connection_from_list_slice
4+
from graphql_relay.connection.arrayconnection import connection_from_array_slice
55
from promise import Promise
66

77
from graphene import NonNull
8-
from graphene.relay import ConnectionField, PageInfo
8+
from graphene.relay import ConnectionField
9+
from graphene.relay.connection import connection_adapter, page_info_adapter
910
from graphene.types import Field, List
1011

1112
from .settings import graphene_settings
@@ -122,15 +123,15 @@ def resolve_connection(cls, connection, args, iterable):
122123
_len = iterable.count()
123124
else:
124125
_len = len(iterable)
125-
connection = connection_from_list_slice(
126+
connection = connection_from_array_slice(
126127
iterable,
127128
args,
128129
slice_start=0,
129-
list_length=_len,
130-
list_slice_length=_len,
131-
connection_type=connection,
130+
array_length=_len,
131+
array_slice_length=_len,
132+
connection_type=partial(connection_adapter, connection),
132133
edge_type=connection.Edge,
133-
pageinfo_type=PageInfo,
134+
page_info_type=page_info_adapter,
134135
)
135136
connection.iterable = iterable
136137
connection.length = _len

graphene_django/filter/tests/test_fields.py

+71-35
Original file line numberDiff line numberDiff line change
@@ -806,38 +806,56 @@ class Query(ObjectType):
806806

807807
assert str(schema) == dedent(
808808
"""\
809-
schema {
810-
query: Query
809+
type Query {
810+
pets(before: String = null, after: String = null, first: Int = null, last: Int = null, age: Int = null): PetTypeConnection
811811
}
812812
813-
interface Node {
814-
id: ID!
813+
type PetTypeConnection {
814+
\"""Pagination data for this connection.\"""
815+
pageInfo: PageInfo!
816+
817+
\"""Contains the nodes in this connection.\"""
818+
edges: [PetTypeEdge]!
815819
}
816820
821+
\"""
822+
The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.
823+
\"""
817824
type PageInfo {
825+
\"""When paginating forwards, are there more items?\"""
818826
hasNextPage: Boolean!
827+
828+
\"""When paginating backwards, are there more items?\"""
819829
hasPreviousPage: Boolean!
830+
831+
\"""When paginating backwards, the cursor to continue.\"""
820832
startCursor: String
833+
834+
\"""When paginating forwards, the cursor to continue.\"""
821835
endCursor: String
822836
}
823-
824-
type PetType implements Node {
825-
age: Int!
826-
id: ID!
827-
}
828-
829-
type PetTypeConnection {
830-
pageInfo: PageInfo!
831-
edges: [PetTypeEdge]!
832-
}
833-
837+
838+
\"""A Relay edge containing a `PetType` and its cursor.\"""
834839
type PetTypeEdge {
840+
\"""The item at the end of the edge\"""
835841
node: PetType
842+
843+
\"""A cursor for use in pagination\"""
836844
cursor: String!
837845
}
838-
839-
type Query {
840-
pets(before: String, after: String, first: Int, last: Int, age: Int): PetTypeConnection
846+
847+
type PetType implements Node {
848+
\"""\"""
849+
age: Int!
850+
851+
\"""The ID of the object\"""
852+
id: ID!
853+
}
854+
855+
\"""An object with an ID\"""
856+
interface Node {
857+
\"""The ID of the object\"""
858+
id: ID!
841859
}
842860
"""
843861
)
@@ -858,40 +876,58 @@ class Query(ObjectType):
858876

859877
assert str(schema) == dedent(
860878
"""\
861-
schema {
862-
query: Query
879+
type Query {
880+
pets(before: String = null, after: String = null, first: Int = null, last: Int = null, age: Int = null, age_Isnull: Boolean = null, age_Lt: Int = null): PetTypeConnection
863881
}
864882
865-
interface Node {
866-
id: ID!
883+
type PetTypeConnection {
884+
\"""Pagination data for this connection.\"""
885+
pageInfo: PageInfo!
886+
887+
\"""Contains the nodes in this connection.\"""
888+
edges: [PetTypeEdge]!
867889
}
868890
891+
\"""
892+
The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.
893+
\"""
869894
type PageInfo {
895+
\"""When paginating forwards, are there more items?\"""
870896
hasNextPage: Boolean!
897+
898+
\"""When paginating backwards, are there more items?\"""
871899
hasPreviousPage: Boolean!
872-
startCursor: String
873-
endCursor: String
874-
}
875900
876-
type PetType implements Node {
877-
age: Int!
878-
id: ID!
879-
}
901+
\"""When paginating backwards, the cursor to continue.\"""
902+
startCursor: String
880903
881-
type PetTypeConnection {
882-
pageInfo: PageInfo!
883-
edges: [PetTypeEdge]!
904+
\"""When paginating forwards, the cursor to continue.\"""
905+
endCursor: String
884906
}
885907
908+
\"""A Relay edge containing a `PetType` and its cursor.\"""
886909
type PetTypeEdge {
910+
\"""The item at the end of the edge\"""
887911
node: PetType
912+
913+
\"""A cursor for use in pagination\"""
888914
cursor: String!
889915
}
890916
891-
type Query {
892-
pets(before: String, after: String, first: Int, last: Int, age: Int, age_Isnull: Boolean, age_Lt: Int): PetTypeConnection
917+
type PetType implements Node {
918+
\"""\"""
919+
age: Int!
920+
921+
\"""The ID of the object\"""
922+
id: ID!
893923
}
894-
"""
924+
925+
\"""An object with an ID\"""
926+
interface Node {
927+
\"""The ID of the object\"""
928+
id: ID!
929+
}
930+
"""
895931
)
896932

897933

0 commit comments

Comments
 (0)