Skip to content

Commit 369cabf

Browse files
committed
Use GraphQL-core version 3 instead of version 2
Also made some of the tests more robust.
1 parent b6d5e72 commit 369cabf

21 files changed

+153
-176
lines changed

gql/client.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import asyncio
22
from typing import Any, AsyncGenerator, Dict, Generator, Optional, Union, cast
33

4-
from graphql import build_ast_schema, build_client_schema, introspection_query, parse
5-
from graphql.execution import ExecutionResult
6-
from graphql.language.ast import Document
7-
from graphql.type import GraphQLSchema
8-
from graphql.validation import validate
4+
from graphql import (
5+
DocumentNode,
6+
ExecutionResult,
7+
GraphQLSchema,
8+
build_ast_schema,
9+
build_client_schema,
10+
get_introspection_query,
11+
parse,
12+
validate,
13+
)
914

1015
from .transport.async_transport import AsyncTransport
1116
from .transport.exceptions import TransportQueryError
@@ -32,7 +37,7 @@ def __init__(
3237
), "Cant fetch the schema from transport if is already provided"
3338
if isinstance(transport, Transport):
3439
# For sync transports, we fetch the schema directly
35-
execution_result = transport.execute(parse(introspection_query))
40+
execution_result = transport.execute(parse(get_introspection_query()))
3641
execution_result = cast(ExecutionResult, execution_result)
3742
introspection = execution_result.data
3843
if introspection:
@@ -72,11 +77,11 @@ def validate(self, document):
7277
if validation_errors:
7378
raise validation_errors[0]
7479

75-
async def execute_async(self, document: Document, *args, **kwargs) -> Dict:
80+
async def execute_async(self, document: DocumentNode, *args, **kwargs) -> Dict:
7681
async with self as session:
7782
return await session.execute(document, *args, **kwargs)
7883

79-
def execute(self, document: Document, *args, **kwargs) -> Dict:
84+
def execute(self, document: DocumentNode, *args, **kwargs) -> Dict:
8085
"""Execute the provided document AST against the configured remote server.
8186
8287
This function WILL BLOCK until the result is received from the server.
@@ -118,7 +123,7 @@ def execute(self, document: Document, *args, **kwargs) -> Dict:
118123
return result.data
119124

120125
async def subscribe_async(
121-
self, document: Document, *args, **kwargs
126+
self, document: DocumentNode, *args, **kwargs
122127
) -> AsyncGenerator[Dict, None]:
123128
async with self as session:
124129

@@ -130,7 +135,7 @@ async def subscribe_async(
130135
yield result
131136

132137
def subscribe(
133-
self, document: Document, *args, **kwargs
138+
self, document: DocumentNode, *args, **kwargs
134139
) -> Generator[Dict, None, None]:
135140
"""Execute a GraphQL subscription with a python generator.
136141
@@ -193,7 +198,7 @@ class ClientSession:
193198
def __init__(self, client: Client):
194199
self.client = client
195200

196-
async def validate(self, document: Document):
201+
async def validate(self, document: DocumentNode):
197202
""" Fetch schema from transport if needed and validate document if schema is present """
198203

199204
# Get schema from transport if needed
@@ -205,7 +210,7 @@ async def validate(self, document: Document):
205210
self.client.validate(document)
206211

207212
async def subscribe(
208-
self, document: Document, *args, **kwargs
213+
self, document: DocumentNode, *args, **kwargs
209214
) -> AsyncGenerator[Dict, None]:
210215

211216
# Fetch schema from transport if needed and validate document if schema is present
@@ -227,7 +232,7 @@ async def subscribe(
227232
elif result.data is not None:
228233
yield result.data
229234

230-
async def execute(self, document: Document, *args, **kwargs) -> Dict:
235+
async def execute(self, document: DocumentNode, *args, **kwargs) -> Dict:
231236

232237
# Fetch schema from transport if needed and validate document if schema is present
233238
await self.validate(document)
@@ -245,7 +250,9 @@ async def execute(self, document: Document, *args, **kwargs) -> Dict:
245250
return result.data
246251

247252
async def fetch_schema(self) -> None:
248-
execution_result = await self.transport.execute(parse(introspection_query))
253+
execution_result = await self.transport.execute(
254+
parse(get_introspection_query())
255+
)
249256
self.client.introspection = execution_result.data
250257
self.client.schema = build_client_schema(self.client.introspection)
251258

gql/dsl.py

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
from functools import partial
22

33
import six
4-
from graphql.language import ast
5-
from graphql.language.printer import print_ast
6-
from graphql.type import (
4+
from graphql import (
5+
ArgumentNode,
6+
DocumentNode,
7+
EnumValueNode,
8+
FieldNode,
79
GraphQLEnumType,
8-
GraphQLInputObjectField,
10+
GraphQLInputField,
911
GraphQLInputObjectType,
1012
GraphQLList,
1113
GraphQLNonNull,
14+
ListValueNode,
15+
NameNode,
16+
ObjectFieldNode,
17+
ObjectValueNode,
18+
OperationDefinitionNode,
19+
OperationType,
20+
SelectionSetNode,
21+
ast_from_value,
22+
print_ast,
1223
)
13-
from graphql.utils.ast_from_value import ast_from_value
24+
from graphql.pyutils import FrozenList
1425

1526
from .utils import to_camel_case
1627

@@ -43,8 +54,8 @@ def execute(self, document):
4354

4455

4556
class DSLType(object):
46-
def __init__(self, type):
47-
self.type = type
57+
def __init__(self, type_):
58+
self.type = type_
4859

4960
def __getattr__(self, name):
5061
formatted_name, field_def = self.get_field(name)
@@ -72,30 +83,40 @@ def selections(*fields):
7283
class DSLField(object):
7384
def __init__(self, name, field):
7485
self.field = field
75-
self.ast_field = ast.Field(name=ast.Name(value=name), arguments=[])
86+
self.ast_field = FieldNode(name=NameNode(value=name), arguments=FrozenList())
7687
self.selection_set = None
7788

7889
def select(self, *fields):
79-
if not self.ast_field.selection_set:
80-
self.ast_field.selection_set = ast.SelectionSet(selections=[])
81-
self.ast_field.selection_set.selections.extend(selections(*fields))
90+
selection_set = self.ast_field.selection_set
91+
added_selections = selections(*fields)
92+
if selection_set:
93+
selection_set.selections = FrozenList(
94+
selection_set.selections + added_selections
95+
)
96+
else:
97+
self.ast_field.selection_set = SelectionSetNode(
98+
selections=FrozenList(added_selections)
99+
)
82100
return self
83101

84102
def __call__(self, **kwargs):
85103
return self.args(**kwargs)
86104

87105
def alias(self, alias):
88-
self.ast_field.alias = ast.Name(value=alias)
106+
self.ast_field.alias = NameNode(value=alias)
89107
return self
90108

91109
def args(self, **kwargs):
110+
added_args = []
92111
for name, value in kwargs.items():
93112
arg = self.field.args.get(name)
94113
arg_type_serializer = get_arg_serializer(arg.type)
95114
serialized_value = arg_type_serializer(value)
96-
self.ast_field.arguments.append(
97-
ast.Argument(name=ast.Name(value=name), value=serialized_value)
115+
added_args.append(
116+
ArgumentNode(name=NameNode(value=name), value=serialized_value)
98117
)
118+
ast_field = self.ast_field
119+
ast_field.arguments = FrozenList(ast_field.arguments + added_args)
99120
return self
100121

101122
@property
@@ -116,11 +137,13 @@ def selection_field(field):
116137
def query(*fields, **kwargs):
117138
if "operation" not in kwargs:
118139
kwargs["operation"] = "query"
119-
return ast.Document(
140+
return DocumentNode(
120141
definitions=[
121-
ast.OperationDefinition(
122-
operation=kwargs["operation"],
123-
selection_set=ast.SelectionSet(selections=list(selections(*fields))),
142+
OperationDefinitionNode(
143+
operation=OperationType(kwargs["operation"]),
144+
selection_set=SelectionSetNode(
145+
selections=FrozenList(selections(*fields))
146+
),
124147
)
125148
]
126149
)
@@ -130,25 +153,25 @@ def serialize_list(serializer, list_values):
130153
assert isinstance(list_values, Iterable), 'Expected iterable, received "{}"'.format(
131154
repr(list_values)
132155
)
133-
return ast.ListValue(values=[serializer(v) for v in list_values])
156+
return ListValueNode(values=FrozenList(serializer(v) for v in list_values))
134157

135158

136159
def get_arg_serializer(arg_type):
137160
if isinstance(arg_type, GraphQLNonNull):
138161
return get_arg_serializer(arg_type.of_type)
139-
if isinstance(arg_type, GraphQLInputObjectField):
162+
if isinstance(arg_type, GraphQLInputField):
140163
return get_arg_serializer(arg_type.type)
141164
if isinstance(arg_type, GraphQLInputObjectType):
142165
serializers = {k: get_arg_serializer(v) for k, v in arg_type.fields.items()}
143-
return lambda value: ast.ObjectValue(
144-
fields=[
145-
ast.ObjectField(ast.Name(k), serializers[k](v))
166+
return lambda value: ObjectValueNode(
167+
fields=FrozenList(
168+
ObjectFieldNode(name=NameNode(value=k), value=serializers[k](v))
146169
for k, v in value.items()
147-
]
170+
)
148171
)
149172
if isinstance(arg_type, GraphQLList):
150173
inner_serializer = get_arg_serializer(arg_type.of_type)
151174
return partial(serialize_list, inner_serializer)
152175
if isinstance(arg_type, GraphQLEnumType):
153-
return lambda value: ast.EnumValue(value=arg_type.serialize(value))
154-
return lambda value: ast_from_value(arg_type.serialize(value))
176+
return lambda value: EnumValueNode(value=arg_type.serialize(value))
177+
return lambda value: ast_from_value(arg_type.serialize(value), arg_type)

gql/transport/aiohttp.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
from aiohttp.client_reqrep import Fingerprint
77
from aiohttp.helpers import BasicAuth
88
from aiohttp.typedefs import LooseCookies, LooseHeaders
9-
from graphql.execution import ExecutionResult
10-
from graphql.language.ast import Document
11-
from graphql.language.printer import print_ast
9+
from graphql import DocumentNode, ExecutionResult, print_ast
1210

1311
from .async_transport import AsyncTransport
1412
from .exceptions import (
@@ -92,7 +90,7 @@ async def close(self) -> None:
9290

9391
async def execute(
9492
self,
95-
document: Document,
93+
document: DocumentNode,
9694
variable_values: Optional[Dict[str, str]] = None,
9795
operation_name: Optional[str] = None,
9896
extra_args: Dict[str, Any] = {},
@@ -143,7 +141,7 @@ async def execute(
143141

144142
def subscribe(
145143
self,
146-
document: Document,
144+
document: DocumentNode,
147145
variable_values: Optional[Dict[str, str]] = None,
148146
operation_name: Optional[str] = None,
149147
) -> AsyncGenerator[ExecutionResult, None]:

gql/transport/async_transport.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import six
55
from graphql.execution import ExecutionResult
6-
from graphql.language.ast import Document
6+
from graphql.language.ast import DocumentNode
77

88

99
@six.add_metaclass(abc.ABCMeta)
@@ -27,7 +27,7 @@ async def close(self):
2727
@abc.abstractmethod
2828
async def execute(
2929
self,
30-
document: Document,
30+
document: DocumentNode,
3131
variable_values: Optional[Dict[str, str]] = None,
3232
operation_name: Optional[str] = None,
3333
) -> ExecutionResult:
@@ -40,7 +40,7 @@ async def execute(
4040
@abc.abstractmethod
4141
def subscribe(
4242
self,
43-
document: Document,
43+
document: DocumentNode,
4444
variable_values: Optional[Dict[str, str]] = None,
4545
operation_name: Optional[str] = None,
4646
) -> AsyncGenerator[ExecutionResult, None]:

gql/transport/local_schema.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from graphql import GraphQLSchema
22
from graphql.execution import ExecutionResult, execute
3-
from graphql.language.ast import Document
3+
from graphql.language.ast import DocumentNode
44

55
from gql.transport import Transport
66

@@ -17,7 +17,7 @@ def __init__(
1717
"""
1818
self.schema = schema
1919

20-
def execute(self, document: Document, *args, **kwargs) -> ExecutionResult:
20+
def execute(self, document: DocumentNode, *args, **kwargs) -> ExecutionResult:
2121
"""Execute the given document against the configured local schema.
2222
2323
:param document: GraphQL query as AST Node object.

gql/transport/requests.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
from typing import Any, Dict, Optional, Union
22

33
import requests
4-
from graphql.execution import ExecutionResult
5-
from graphql.language.ast import Document
6-
from graphql.language.printer import print_ast
4+
from graphql import DocumentNode, ExecutionResult, print_ast
75
from requests.adapters import HTTPAdapter, Retry
86
from requests.auth import AuthBase
97
from requests.cookies import RequestsCookieJar
@@ -76,7 +74,7 @@ def __init__(
7674

7775
def execute( # type: ignore
7876
self,
79-
document: Document,
77+
document: DocumentNode,
8078
variable_values: Optional[Dict[str, Any]] = None,
8179
timeout: Optional[int] = None,
8280
) -> ExecutionResult:

gql/transport/transport.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
import six
44
from graphql.execution import ExecutionResult
5-
from graphql.language.ast import Document
5+
from graphql.language.ast import DocumentNode
66

77

88
@six.add_metaclass(abc.ABCMeta)
99
class Transport:
1010
@abc.abstractmethod
11-
def execute(self, document: Document, *args, **kwargs) -> ExecutionResult:
11+
def execute(self, document: DocumentNode, *args, **kwargs) -> ExecutionResult:
1212
"""Execute the provided document AST for either a remote or local GraphQL Schema.
1313
1414
:param document: GraphQL query as AST Node or Document object.

gql/transport/websockets.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
from typing import Any, AsyncGenerator, Dict, Optional, Tuple, Union, cast
66

77
import websockets
8-
from graphql.execution import ExecutionResult
9-
from graphql.language.ast import Document
10-
from graphql.language.printer import print_ast
8+
from graphql import DocumentNode, ExecutionResult, print_ast
119
from websockets.client import WebSocketClientProtocol
1210
from websockets.exceptions import ConnectionClosed
1311
from websockets.http import HeadersLike
@@ -217,7 +215,7 @@ async def _send_connection_terminate_message(self) -> None:
217215

218216
async def _send_query(
219217
self,
220-
document: Document,
218+
document: DocumentNode,
221219
variable_values: Optional[Dict[str, str]] = None,
222220
operation_name: Optional[str] = None,
223221
) -> int:
@@ -361,7 +359,7 @@ async def _receive_data_loop(self) -> None:
361359

362360
async def subscribe(
363361
self,
364-
document: Document,
362+
document: DocumentNode,
365363
variable_values: Optional[Dict[str, str]] = None,
366364
operation_name: Optional[str] = None,
367365
send_stop: Optional[bool] = True,
@@ -419,7 +417,7 @@ async def subscribe(
419417

420418
async def execute(
421419
self,
422-
document: Document,
420+
document: DocumentNode,
423421
variable_values: Optional[Dict[str, str]] = None,
424422
operation_name: Optional[str] = None,
425423
) -> ExecutionResult:

0 commit comments

Comments
 (0)