Skip to content

Commit 4c69f4f

Browse files
committed
Switch to GraphQL-core 3.2
Replicates graphql/graphql-relay-js@d4c533f
1 parent 97ee4df commit 4c69f4f

18 files changed

+122
-266
lines changed

README.md

Lines changed: 72 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -63,47 +63,53 @@ from graphql_relay import connection_definitions
6363
### Connections
6464

6565
Helper functions are provided for both building the GraphQL types
66-
for connections and for implementing the `resolver` method for fields
66+
for connections and for implementing the `resolve` method for fields
6767
returning those types.
6868

6969
- `connection_args` returns the arguments that fields should provide when
70-
they return a connection type.
70+
they return a connection type that supports bidirectional pagination.
71+
- `forward_connection_args` returns the arguments that fields should provide when
72+
they return a connection type that only supports forward pagination.
73+
- `backward_connection_args` returns the arguments that fields should provide when
74+
they return a connection type that only supports backward pagination.
7175
- `connection_definitions` returns a `connection_type` and its associated
7276
`edgeType`, given a name and a node type.
7377
- `connection_from_array` is a helper method that takes an array and the
7478
arguments from `connection_args`, does pagination and filtering, and returns
75-
an object in the shape expected by a `connection_type`'s `resolver` function.
79+
an object in the shape expected by a `connection_type`'s `resolve` function.
7680
- `cursor_for_object_in_connection` is a helper method that takes an array and a
7781
member object, and returns a cursor for use in the mutation payload.
82+
- `offset_to_cursor` takes the index of a member object in an array
83+
and returns an opaque cursor for use in the mutation payload.
84+
- `cursor_to_offset` takes an opaque cursor (created with `offset_to_cursor`)
85+
and returns the corresponding array index.
7886

7987
An example usage of these methods from the [test schema](tests/star_wars_schema.py):
8088

8189
```python
82-
ship_edge, ship_connection = connection_definitions('Ship', shipType)
90+
ship_edge, ship_connection = connection_definitions(ship_type, "Ship")
8391

84-
factionType = GraphQLObjectType(
85-
name='Faction',
86-
description='A faction in the Star Wars saga',
92+
faction_type = GraphQLObjectType(
93+
name="Faction",
94+
description="A faction in the Star Wars saga",
8795
fields=lambda: {
88-
'id': global_id_field('Faction'),
89-
'name': GraphQLField(
90-
GraphQLString,
91-
description='The name of the faction.',
92-
),
93-
'ships': GraphQLField(
96+
"id": global_id_field("Faction"),
97+
"name": GraphQLField(GraphQLString, description="The name of the faction."),
98+
"ships": GraphQLField(
9499
ship_connection,
95-
description='The ships used by the faction.',
100+
description="The ships used by the faction.",
96101
args=connection_args,
97102
resolve=lambda faction, _info, **args: connection_from_array(
98-
[getShip(ship) for ship in faction.ships], args),
99-
)
103+
[get_ship(ship) for ship in faction.ships], args
104+
),
105+
),
100106
},
101-
interfaces=[node_interface]
107+
interfaces=[node_interface],
102108
)
103109
```
104110

105111
This shows adding a `ships` field to the `Faction` object that is a connection.
106-
It uses `connection_definitions('Ship', shipType)` to create the connection
112+
It uses `connection_definitions(ship_type, "Ship")` to create the connection
107113
type, adds `connection_args` as arguments on this function, and then implements
108114
the resolver function by passing the array of ships and the arguments to
109115
`connection_from_array`.
@@ -131,40 +137,49 @@ An example usage of these methods from the [test schema](tests/star_wars_schema.
131137
```python
132138
def get_node(global_id, _info):
133139
type_, id_ = from_global_id(global_id)
134-
if type_ == 'Faction':
135-
return getFaction(id_)
136-
elif type_ == 'Ship':
137-
return getShip(id_)
138-
else:
139-
return None
140+
if type_ == "Faction":
141+
return get_faction(id_)
142+
if type_ == "Ship":
143+
return get_ship(id_)
144+
return None # pragma: no cover
140145

141146
def get_node_type(obj, _info, _type):
142147
if isinstance(obj, Faction):
143-
return factionType
144-
else:
145-
return shipType
148+
return faction_type.name
149+
return ship_type.name
146150

147-
node_interface, node_field = node_definitions(get_node, get_node_type)
151+
node_interface, node_field = node_definitions(get_node, get_node_type)[:2]
148152

149-
factionType = GraphQLObjectType(
150-
name= 'Faction',
151-
description= 'A faction in the Star Wars saga',
152-
fields= lambda: {
153-
'id': global_id_field('Faction'),
153+
faction_type = GraphQLObjectType(
154+
name="Faction",
155+
description="A faction in the Star Wars saga",
156+
fields=lambda: {
157+
"id": global_id_field("Faction"),
158+
"name": GraphQLField(GraphQLString, description="The name of the faction."),
159+
"ships": GraphQLField(
160+
ship_connection,
161+
description="The ships used by the faction.",
162+
args=connection_args,
163+
resolve=lambda faction, _info, **args: connection_from_array(
164+
[get_ship(ship) for ship in faction.ships], args
165+
),
166+
),
154167
},
155-
interfaces= [node_interface]
168+
interfaces=[node_interface],
156169
)
157170

158-
queryType = GraphQLObjectType(
159-
name= 'Query',
160-
fields= lambda: {
161-
'node': node_field
162-
}
171+
query_type = GraphQLObjectType(
172+
name="Query",
173+
fields=lambda: {
174+
"rebels": GraphQLField(faction_type, resolve=lambda _obj, _info: get_rebels()),
175+
"empire": GraphQLField(faction_type, resolve=lambda _obj, _info: get_empire()),
176+
"node": node_field,
177+
},
163178
)
164179
```
165180

166181
This uses `node_definitions` to construct the `Node` interface and the `node`
167-
field; it uses `from_global_id` to resolve the IDs passed in in the implementation
182+
field; it uses `from_global_id` to resolve the IDs passed in the implementation
168183
of the function mapping ID to object. It then uses the `global_id_field` method to
169184
create the `id` field on `Faction`, which also ensures implements the
170185
`node_interface`. Finally, it adds the `node` field to the query type, using the
@@ -184,43 +199,35 @@ An example usage of these methods from the [test schema](tests/star_wars_schema.
184199

185200
```python
186201
class IntroduceShipMutation:
202+
187203
def __init__(self, shipId, factionId, clientMutationId=None):
188204
self.shipId = shipId
189205
self.factionId = factionId
190206
self.clientMutationId = clientMutationId
191207

192-
def mutate_and_get_payload(_info, shipName, factionId):
193-
newShip = createShip(shipName, factionId)
194-
return IntroduceShipMutation(shipId=newShip.id, factionId=factionId)
208+
def mutate_and_get_payload(_info, shipName, factionId, **_input):
209+
new_ship = create_ship(shipName, factionId)
210+
return IntroduceShipMutation(shipId=new_ship.id, factionId=factionId)
195211

196-
shipMutation = mutation_with_client_mutation_id(
197-
'IntroduceShip',
212+
ship_mutation = mutation_with_client_mutation_id(
213+
"IntroduceShip",
198214
input_fields={
199-
'shipName': GraphQLInputField(
200-
GraphQLNonNull(GraphQLString)
201-
),
202-
'factionId': GraphQLInputField(
203-
GraphQLNonNull(GraphQLID)
204-
)
215+
"shipName": GraphQLInputField(GraphQLNonNull(GraphQLString)),
216+
"factionId": GraphQLInputField(GraphQLNonNull(GraphQLID)),
205217
},
206218
output_fields={
207-
'ship': GraphQLField(
208-
shipType,
209-
resolve=lambda payload, _info: getShip(payload.shipId)
219+
"ship": GraphQLField(
220+
ship_type, resolve=lambda payload, _info: get_ship(payload.shipId)
221+
),
222+
"faction": GraphQLField(
223+
faction_type, resolve=lambda payload, _info: get_faction(payload.factionId)
210224
),
211-
'faction': GraphQLField(
212-
factionType,
213-
resolve=lambda payload, _info: getFaction(payload.factionId)
214-
)
215225
},
216-
mutate_and_get_payload=mutate_and_get_payload
226+
mutate_and_get_payload=mutate_and_get_payload,
217227
)
218228

219-
mutationType = GraphQLObjectType(
220-
'Mutation',
221-
fields=lambda: {
222-
'introduceShip': shipMutation
223-
}
229+
mutation_type = GraphQLObjectType(
230+
"Mutation", fields=lambda: {"introduceShip": ship_mutation}
224231
)
225232
```
226233

@@ -268,5 +275,5 @@ Python versions and perform all additional source code checks.
268275
You can also restrict tox to an individual environment, like this:
269276

270277
```sh
271-
poetry run tox -e py37
278+
poetry run tox -e py39
272279
```

poetry.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ packages = [
4242

4343
[tool.poetry.dependencies]
4444
python = "^3.6"
45-
graphql-core = "~3.1"
45+
graphql-core = "~3.2"
4646
typing-extensions = { version = "^4.1", python = "<3.8" }
4747

4848
[tool.poetry.dev-dependencies]

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
"Programming Language :: Python :: Implementation :: PyPy",
3333
],
3434
install_requires=[
35-
"graphql-core>=3.1,<3.2",
36-
"typing-extensions>=4,<5; python_version < '3.8'",
35+
"graphql-core>=3.2,<3.3",
36+
"typing-extensions>=4.1,<5; python_version < '3.8'",
3737
],
3838
python_requires=">=3.6,<4",
3939
packages=find_packages("src"),

src/graphql_relay/__init__.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
# Helper for creating mutations with client mutation IDs
3939
from .mutation.mutation import (
4040
mutation_with_client_mutation_id,
41-
resolve_maybe_thunk,
4241
MutationFn,
4342
MutationFnWithoutArgs,
4443
NullResult,
@@ -53,13 +52,6 @@
5352
# Utilities for creating global IDs in systems that don't have them
5453
from .node.node import from_global_id, global_id_field, to_global_id, ResolvedGlobalId
5554

56-
# Deprecated functions from older graphql-relay-py versions
57-
# noinspection PyProtectedMember,PyUnresolvedReferences,PyDeprecation
58-
from .connection.array_connection import ( # noqa: F401
59-
connection_from_list,
60-
connection_from_list_slice,
61-
)
62-
6355
__version__ = version
6456
__version_info__ = version_info
6557
__version_js__ = version_js
@@ -99,7 +91,6 @@
9991
"page_info_type",
10092
"plural_identifying_root_field",
10193
"ResolvedGlobalId",
102-
"resolve_maybe_thunk",
10394
"SizedSliceable",
10495
"to_global_id",
10596
"version",

src/graphql_relay/connection/array_connection.py

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import warnings
21
from typing import Any, Iterator, Optional, Sequence
32

43
try:
@@ -71,33 +70,6 @@ def connection_from_array(
7170
)
7271

7372

74-
def connection_from_list(
75-
data: Sequence,
76-
args: Optional[ConnectionArguments] = None,
77-
connection_type: ConnectionConstructor = Connection,
78-
edge_type: EdgeConstructor = Edge,
79-
pageinfo_type: PageInfoConstructor = PageInfo,
80-
) -> ConnectionType:
81-
"""Deprecated alias for connection_from_array.
82-
83-
We're now using the JavaScript terminology in Python as well, since list
84-
is too narrow a type and there is no other really appropriate type name.
85-
"""
86-
warnings.warn(
87-
"connection_from_list() has been deprecated."
88-
" Please use connection_from_array() instead.",
89-
DeprecationWarning,
90-
stacklevel=2,
91-
)
92-
return connection_from_array_slice(
93-
data,
94-
args,
95-
connection_type=connection_type,
96-
edge_type=edge_type,
97-
page_info_type=pageinfo_type,
98-
)
99-
100-
10173
def connection_from_array_slice(
10274
array_slice: SizedSliceable,
10375
args: Optional[ConnectionArguments] = None,
@@ -183,39 +155,6 @@ def connection_from_array_slice(
183155
)
184156

185157

186-
def connection_from_list_slice(
187-
list_slice: Sequence,
188-
args: Optional[ConnectionArguments] = None,
189-
connection_type: ConnectionConstructor = Connection,
190-
edge_type: EdgeConstructor = Edge,
191-
pageinfo_type: PageInfoConstructor = PageInfo,
192-
slice_start: int = 0,
193-
list_length: int = 0,
194-
list_slice_length: Optional[int] = None,
195-
) -> ConnectionType:
196-
"""Deprecated alias for connection_from_array_slice.
197-
198-
We're now using the JavaScript terminology in Python as well, since list
199-
is too narrow a type and there is no other really appropriate type name.
200-
"""
201-
warnings.warn(
202-
"connection_from_list_slice() has been deprecated."
203-
" Please use connection_from_array_slice() instead.",
204-
DeprecationWarning,
205-
stacklevel=2,
206-
)
207-
return connection_from_array_slice(
208-
list_slice,
209-
args,
210-
slice_start=slice_start,
211-
array_length=list_length,
212-
array_slice_length=list_slice_length,
213-
connection_type=connection_type,
214-
edge_type=edge_type,
215-
page_info_type=pageinfo_type,
216-
)
217-
218-
219158
PREFIX = "arrayconnection:"
220159

221160

src/graphql_relay/connection/arrayconnection.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@
1111
SizedSliceable,
1212
)
1313

14-
# Deprecated functions from older graphql-relay-py versions
15-
# noinspection PyProtectedMember,PyUnresolvedReferences,PyDeprecation
16-
from .array_connection import ( # noqa: F401
17-
connection_from_list,
18-
connection_from_list_slice,
19-
)
20-
2114
warnings.warn(
2215
"The 'arrayconnection' module is deprecated. "
2316
"Functions should be imported from the top-level package instead.",

0 commit comments

Comments
 (0)