Skip to content

Commit bf16f1e

Browse files
authored
Bump graphql-core to 3.2.0 (#283)
* Fix error 'graphql.error.graphql_error.GraphQLError: Names must only contain [_a-zA-Z0-9] but 'meta-field' does not.' * Don't use format_error * Put the is_finite method in the test file * Fix StarWars schema Fixes 'Support for returning GraphQLObjectType from resolve_type was removed in GraphQL-core 3.2, please return type name instead' * fix print_ast removing last newline * Fix error: AttributeError: 'ParseResultVisitor' object has no attribute 'enter_leave_map' * Rename specifiedByUrl to specifiedByURL See graphql/graphql-js#3156 * Bump graphql-core version to stable 3.2 This new version of GraphQL-core replaces the FrozenLists in AST nodes with tuples, so we need to make the appropriate changes in dsl.py. * Fix Introspection directive typing
1 parent 5440c6c commit bf16f1e

File tree

13 files changed

+195
-164
lines changed

13 files changed

+195
-164
lines changed

gql/dsl.py

+28-37
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import re
77
from abc import ABC, abstractmethod
88
from math import isfinite
9-
from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple, Union, cast
9+
from typing import Any, Dict, Iterable, Mapping, Optional, Tuple, Union, cast
1010

1111
from graphql import (
1212
ArgumentNode,
@@ -61,7 +61,7 @@
6161
is_wrapping_type,
6262
print_ast,
6363
)
64-
from graphql.pyutils import FrozenList, inspect
64+
from graphql.pyutils import inspect
6565

6666
from .utils import to_camel_case
6767

@@ -90,17 +90,17 @@ def ast_from_serialized_value_untyped(serialized: Any) -> Optional[ValueNode]:
9090
(key, ast_from_serialized_value_untyped(value))
9191
for key, value in serialized.items()
9292
)
93-
field_nodes = (
93+
field_nodes = tuple(
9494
ObjectFieldNode(name=NameNode(value=field_name), value=field_value)
9595
for field_name, field_value in field_items
9696
if field_value
9797
)
98-
return ObjectValueNode(fields=FrozenList(field_nodes))
98+
return ObjectValueNode(fields=field_nodes)
9999

100100
if isinstance(serialized, Iterable) and not isinstance(serialized, str):
101101
maybe_nodes = (ast_from_serialized_value_untyped(item) for item in serialized)
102-
nodes = filter(None, maybe_nodes)
103-
return ListValueNode(values=FrozenList(nodes))
102+
nodes = tuple(node for node in maybe_nodes if node)
103+
return ListValueNode(values=nodes)
104104

105105
if isinstance(serialized, bool):
106106
return BooleanValueNode(value=serialized)
@@ -158,8 +158,8 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]:
158158
item_type = type_.of_type
159159
if isinstance(value, Iterable) and not isinstance(value, str):
160160
maybe_value_nodes = (ast_from_value(item, item_type) for item in value)
161-
value_nodes = filter(None, maybe_value_nodes)
162-
return ListValueNode(values=FrozenList(value_nodes))
161+
value_nodes = tuple(node for node in maybe_value_nodes if node)
162+
return ListValueNode(values=value_nodes)
163163
return ast_from_value(value, item_type)
164164

165165
# Populate the fields of the input object by creating ASTs from each value in the
@@ -173,12 +173,12 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]:
173173
for field_name, field in type_.fields.items()
174174
if field_name in value
175175
)
176-
field_nodes = (
176+
field_nodes = tuple(
177177
ObjectFieldNode(name=NameNode(value=field_name), value=field_value)
178178
for field_name, field_value in field_items
179179
if field_value
180180
)
181-
return ObjectValueNode(fields=FrozenList(field_nodes))
181+
return ObjectValueNode(fields=field_nodes)
182182

183183
if is_leaf_type(type_):
184184
# Since value is an internally represented value, it must be serialized to an
@@ -314,7 +314,7 @@ def __init__(
314314
self, *fields: "DSLSelectable", **fields_with_alias: "DSLSelectableWithAlias",
315315
):
316316
""":meta private:"""
317-
self.selection_set = SelectionSetNode(selections=FrozenList([]))
317+
self.selection_set = SelectionSetNode(selections=())
318318

319319
if fields or fields_with_alias:
320320
self.select(*fields, **fields_with_alias)
@@ -355,14 +355,12 @@ def select(
355355
raise GraphQLError(f"Invalid field for {self!r}: {field!r}")
356356

357357
# Get a list of AST Nodes for each added field
358-
added_selections: List[
359-
Union[FieldNode, InlineFragmentNode, FragmentSpreadNode]
360-
] = [field.ast_field for field in added_fields]
358+
added_selections: Tuple[
359+
Union[FieldNode, InlineFragmentNode, FragmentSpreadNode], ...
360+
] = tuple(field.ast_field for field in added_fields)
361361

362362
# Update the current selection list with new selections
363-
self.selection_set.selections = FrozenList(
364-
self.selection_set.selections + added_selections
365-
)
363+
self.selection_set.selections = self.selection_set.selections + added_selections
366364

367365
log.debug(f"Added fields: {added_fields} in {self!r}")
368366

@@ -470,9 +468,7 @@ def executable_ast(self) -> OperationDefinitionNode:
470468
return OperationDefinitionNode(
471469
operation=OperationType(self.operation_type),
472470
selection_set=self.selection_set,
473-
variable_definitions=FrozenList(
474-
self.variable_definitions.get_ast_definitions()
475-
),
471+
variable_definitions=self.variable_definitions.get_ast_definitions(),
476472
**({"name": NameNode(value=self.name)} if self.name else {}),
477473
)
478474

@@ -548,19 +544,19 @@ def __getattr__(self, name: str) -> "DSLVariable":
548544
self.variables[name] = DSLVariable(name)
549545
return self.variables[name]
550546

551-
def get_ast_definitions(self) -> List[VariableDefinitionNode]:
547+
def get_ast_definitions(self) -> Tuple[VariableDefinitionNode, ...]:
552548
"""
553549
:meta private:
554550
555551
Return a list of VariableDefinitionNodes for each variable with a type
556552
"""
557-
return [
553+
return tuple(
558554
VariableDefinitionNode(
559555
type=var.type, variable=var.ast_variable, default_value=None,
560556
)
561557
for var in self.variables.values()
562558
if var.type is not None # only variables used
563-
]
559+
)
564560

565561

566562
class DSLType:
@@ -770,7 +766,7 @@ def __init__(
770766
"""
771767
self.parent_type = parent_type
772768
self.field = field
773-
self.ast_field = FieldNode(name=NameNode(value=name), arguments=FrozenList())
769+
self.ast_field = FieldNode(name=NameNode(value=name), arguments=())
774770

775771
log.debug(f"Creating {self!r}")
776772

@@ -803,15 +799,12 @@ def args(self, **kwargs) -> "DSLField":
803799

804800
assert self.ast_field.arguments is not None
805801

806-
self.ast_field.arguments = FrozenList(
807-
self.ast_field.arguments
808-
+ [
809-
ArgumentNode(
810-
name=NameNode(value=name),
811-
value=ast_from_value(value, self._get_argument(name).type),
812-
)
813-
for name, value in kwargs.items()
814-
]
802+
self.ast_field.arguments = self.ast_field.arguments + tuple(
803+
ArgumentNode(
804+
name=NameNode(value=name),
805+
value=ast_from_value(value, self._get_argument(name).type),
806+
)
807+
for name, value in kwargs.items()
815808
)
816809

817810
log.debug(f"Added arguments {kwargs} in field {self!r})")
@@ -856,7 +849,7 @@ class DSLMetaField(DSLField):
856849
"""
857850

858851
meta_type = GraphQLObjectType(
859-
"meta-field",
852+
"meta_field",
860853
fields={
861854
"__typename": GraphQLField(GraphQLString),
862855
"__schema": GraphQLField(
@@ -1022,9 +1015,7 @@ def executable_ast(self) -> FragmentDefinitionNode:
10221015
return FragmentDefinitionNode(
10231016
type_condition=NamedTypeNode(name=NameNode(value=self._type.name)),
10241017
selection_set=self.selection_set,
1025-
variable_definitions=FrozenList(
1026-
self.variable_definitions.get_ast_definitions()
1027-
),
1018+
variable_definitions=self.variable_definitions.get_ast_definitions(),
10281019
name=NameNode(value=self.name),
10291020
)
10301021

gql/utilities/build_client_schema.py

+19-10
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1-
from typing import Dict
2-
3-
from graphql import GraphQLSchema
1+
from graphql import GraphQLSchema, IntrospectionQuery
42
from graphql import build_client_schema as build_client_schema_orig
53
from graphql.pyutils import inspect
4+
from graphql.utilities.get_introspection_query import (
5+
DirectiveLocation,
6+
IntrospectionDirective,
7+
)
68

79
__all__ = ["build_client_schema"]
810

911

10-
INCLUDE_DIRECTIVE_JSON = {
12+
INCLUDE_DIRECTIVE_JSON: IntrospectionDirective = {
1113
"name": "include",
1214
"description": (
1315
"Directs the executor to include this field or fragment "
1416
"only when the `if` argument is true."
1517
),
16-
"locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"],
18+
"locations": [
19+
DirectiveLocation.FIELD,
20+
DirectiveLocation.FRAGMENT_SPREAD,
21+
DirectiveLocation.INLINE_FRAGMENT,
22+
],
1723
"args": [
1824
{
1925
"name": "if",
@@ -28,13 +34,17 @@
2834
],
2935
}
3036

31-
SKIP_DIRECTIVE_JSON = {
37+
SKIP_DIRECTIVE_JSON: IntrospectionDirective = {
3238
"name": "skip",
3339
"description": (
3440
"Directs the executor to skip this field or fragment "
3541
"when the `if` argument is true."
3642
),
37-
"locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"],
43+
"locations": [
44+
DirectiveLocation.FIELD,
45+
DirectiveLocation.FRAGMENT_SPREAD,
46+
DirectiveLocation.INLINE_FRAGMENT,
47+
],
3848
"args": [
3949
{
4050
"name": "if",
@@ -50,7 +60,7 @@
5060
}
5161

5262

53-
def build_client_schema(introspection: Dict) -> GraphQLSchema:
63+
def build_client_schema(introspection: IntrospectionQuery) -> GraphQLSchema:
5464
"""This is an alternative to the graphql-core function
5565
:code:`build_client_schema` but with default include and skip directives
5666
added to the schema to fix
@@ -77,8 +87,7 @@ def build_client_schema(introspection: Dict) -> GraphQLSchema:
7787
directives = schema_introspection.get("directives", None)
7888

7989
if directives is None:
80-
directives = []
81-
schema_introspection["directives"] = directives
90+
schema_introspection["directives"] = directives = []
8291

8392
if not any(directive["name"] == "skip" for directive in directives):
8493
directives.append(SKIP_DIRECTIVE_JSON)

gql/utilities/get_introspection_query_ast.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def get_introspection_query_ast(
5959
if descriptions:
6060
fragment_FullType.select(ds.__Type.description)
6161
if specified_by_url:
62-
fragment_FullType.select(ds.__Type.specifiedByUrl)
62+
fragment_FullType.select(ds.__Type.specifiedByURL)
6363

6464
fields = ds.__Type.fields(includeDeprecated=True).select(ds.__Field.name)
6565

gql/utilities/parse_result.py

+2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ def __init__(
102102

103103
self.result_stack: List[Any] = []
104104

105+
super().__init__()
106+
105107
@property
106108
def current_result(self):
107109
try:

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from setuptools import setup, find_packages
44

55
install_requires = [
6-
"graphql-core>=3.1.5,<3.2",
6+
"graphql-core>=3.2,<3.3",
77
"yarl>=1.6,<2.0",
88
]
99

tests/custom_scalars/test_money.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import asyncio
2+
from math import isfinite
23
from typing import Any, Dict, NamedTuple, Optional
34

45
import pytest
56
from graphql import graphql_sync
67
from graphql.error import GraphQLError
78
from graphql.language import ValueNode
8-
from graphql.pyutils import inspect, is_finite
9+
from graphql.pyutils import inspect
910
from graphql.type import (
1011
GraphQLArgument,
1112
GraphQLField,
@@ -34,6 +35,13 @@ class Money(NamedTuple):
3435
currency: str
3536

3637

38+
def is_finite(value: Any) -> bool:
39+
"""Return true if a value is a finite number."""
40+
return (isinstance(value, int) and not isinstance(value, bool)) or (
41+
isinstance(value, float) and isfinite(value)
42+
)
43+
44+
3745
def serialize_money(output_value: Any) -> Dict[str, Any]:
3846
if not isinstance(output_value, Money):
3947
raise GraphQLError("Cannot serialize money value: " + inspect(output_value))

tests/fixtures/vcr_cassettes/queries.yaml

+5-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ interactions:
1212
{\n ...TypeRef\n }\n defaultValue\n}\n\nfragment TypeRef on __Type {\n kind\n name\n ofType
1313
{\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType
1414
{\n kind\n name\n ofType {\n kind\n name\n ofType
15-
{\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n}\n"}'
15+
{\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n}"}'
1616
headers:
1717
Accept:
1818
- '*/*'
@@ -202,7 +202,7 @@ interactions:
202202
message: OK
203203
- request:
204204
body: '{"query": "{\n myFavoriteFilm: film(id: \"RmlsbToz\") {\n id\n title\n episodeId\n characters(first:
205-
5) {\n edges {\n node {\n name\n }\n }\n }\n }\n}\n"}'
205+
5) {\n edges {\n node {\n name\n }\n }\n }\n }\n}"}'
206206
headers:
207207
Accept:
208208
- '*/*'
@@ -248,7 +248,7 @@ interactions:
248248
code: 200
249249
message: OK
250250
- request:
251-
body: '{"query": "query Planet($id: ID!) {\n planet(id: $id) {\n id\n name\n }\n}\n",
251+
body: '{"query": "query Planet($id: ID!) {\n planet(id: $id) {\n id\n name\n }\n}",
252252
"variables": {"id": "UGxhbmV0OjEw"}}'
253253
headers:
254254
Accept:
@@ -294,7 +294,7 @@ interactions:
294294
message: OK
295295
- request:
296296
body: '{"query": "query Planet1 {\n planet(id: \"UGxhbmV0OjEw\") {\n id\n name\n }\n}\n\nquery
297-
Planet2 {\n planet(id: \"UGxhbmV0OjEx\") {\n id\n name\n }\n}\n", "operationName":
297+
Planet2 {\n planet(id: \"UGxhbmV0OjEx\") {\n id\n name\n }\n}", "operationName":
298298
"Planet2"}'
299299
headers:
300300
Accept:
@@ -339,7 +339,7 @@ interactions:
339339
code: 200
340340
message: OK
341341
- request:
342-
body: '{"query": "query Planet($id: ID!) {\n planet(id: $id) {\n id\n name\n }\n}\n"}'
342+
body: '{"query": "query Planet($id: ID!) {\n planet(id: $id) {\n id\n name\n }\n}"}'
343343
headers:
344344
Accept:
345345
- '*/*'

0 commit comments

Comments
 (0)