Skip to content

Bump graphql-core to 3.2.0 #283

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 28 additions & 37 deletions gql/dsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import re
from abc import ABC, abstractmethod
from math import isfinite
from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple, Union, cast
from typing import Any, Dict, Iterable, Mapping, Optional, Tuple, Union, cast

from graphql import (
ArgumentNode,
Expand Down Expand Up @@ -61,7 +61,7 @@
is_wrapping_type,
print_ast,
)
from graphql.pyutils import FrozenList, inspect
from graphql.pyutils import inspect

from .utils import to_camel_case

Expand Down Expand Up @@ -90,17 +90,17 @@ def ast_from_serialized_value_untyped(serialized: Any) -> Optional[ValueNode]:
(key, ast_from_serialized_value_untyped(value))
for key, value in serialized.items()
)
field_nodes = (
field_nodes = tuple(
ObjectFieldNode(name=NameNode(value=field_name), value=field_value)
for field_name, field_value in field_items
if field_value
)
return ObjectValueNode(fields=FrozenList(field_nodes))
return ObjectValueNode(fields=field_nodes)

if isinstance(serialized, Iterable) and not isinstance(serialized, str):
maybe_nodes = (ast_from_serialized_value_untyped(item) for item in serialized)
nodes = filter(None, maybe_nodes)
return ListValueNode(values=FrozenList(nodes))
nodes = tuple(node for node in maybe_nodes if node)
return ListValueNode(values=nodes)

if isinstance(serialized, bool):
return BooleanValueNode(value=serialized)
Expand Down Expand Up @@ -158,8 +158,8 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]:
item_type = type_.of_type
if isinstance(value, Iterable) and not isinstance(value, str):
maybe_value_nodes = (ast_from_value(item, item_type) for item in value)
value_nodes = filter(None, maybe_value_nodes)
return ListValueNode(values=FrozenList(value_nodes))
value_nodes = tuple(node for node in maybe_value_nodes if node)
return ListValueNode(values=value_nodes)
return ast_from_value(value, item_type)

# Populate the fields of the input object by creating ASTs from each value in the
Expand All @@ -173,12 +173,12 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]:
for field_name, field in type_.fields.items()
if field_name in value
)
field_nodes = (
field_nodes = tuple(
ObjectFieldNode(name=NameNode(value=field_name), value=field_value)
for field_name, field_value in field_items
if field_value
)
return ObjectValueNode(fields=FrozenList(field_nodes))
return ObjectValueNode(fields=field_nodes)

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

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

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

# Update the current selection list with new selections
self.selection_set.selections = FrozenList(
self.selection_set.selections + added_selections
)
self.selection_set.selections = self.selection_set.selections + added_selections

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

Expand Down Expand Up @@ -470,9 +468,7 @@ def executable_ast(self) -> OperationDefinitionNode:
return OperationDefinitionNode(
operation=OperationType(self.operation_type),
selection_set=self.selection_set,
variable_definitions=FrozenList(
self.variable_definitions.get_ast_definitions()
),
variable_definitions=self.variable_definitions.get_ast_definitions(),
**({"name": NameNode(value=self.name)} if self.name else {}),
)

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

def get_ast_definitions(self) -> List[VariableDefinitionNode]:
def get_ast_definitions(self) -> Tuple[VariableDefinitionNode, ...]:
"""
:meta private:

Return a list of VariableDefinitionNodes for each variable with a type
"""
return [
return tuple(
VariableDefinitionNode(
type=var.type, variable=var.ast_variable, default_value=None,
)
for var in self.variables.values()
if var.type is not None # only variables used
]
)


class DSLType:
Expand Down Expand Up @@ -770,7 +766,7 @@ def __init__(
"""
self.parent_type = parent_type
self.field = field
self.ast_field = FieldNode(name=NameNode(value=name), arguments=FrozenList())
self.ast_field = FieldNode(name=NameNode(value=name), arguments=())

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

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

assert self.ast_field.arguments is not None

self.ast_field.arguments = FrozenList(
self.ast_field.arguments
+ [
ArgumentNode(
name=NameNode(value=name),
value=ast_from_value(value, self._get_argument(name).type),
)
for name, value in kwargs.items()
]
self.ast_field.arguments = self.ast_field.arguments + tuple(
ArgumentNode(
name=NameNode(value=name),
value=ast_from_value(value, self._get_argument(name).type),
)
for name, value in kwargs.items()
)

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

meta_type = GraphQLObjectType(
"meta-field",
"meta_field",
fields={
"__typename": GraphQLField(GraphQLString),
"__schema": GraphQLField(
Expand Down Expand Up @@ -1022,9 +1015,7 @@ def executable_ast(self) -> FragmentDefinitionNode:
return FragmentDefinitionNode(
type_condition=NamedTypeNode(name=NameNode(value=self._type.name)),
selection_set=self.selection_set,
variable_definitions=FrozenList(
self.variable_definitions.get_ast_definitions()
),
variable_definitions=self.variable_definitions.get_ast_definitions(),
name=NameNode(value=self.name),
)

Expand Down
29 changes: 19 additions & 10 deletions gql/utilities/build_client_schema.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
from typing import Dict

from graphql import GraphQLSchema
from graphql import GraphQLSchema, IntrospectionQuery
from graphql import build_client_schema as build_client_schema_orig
from graphql.pyutils import inspect
from graphql.utilities.get_introspection_query import (
DirectiveLocation,
IntrospectionDirective,
)

__all__ = ["build_client_schema"]


INCLUDE_DIRECTIVE_JSON = {
INCLUDE_DIRECTIVE_JSON: IntrospectionDirective = {
"name": "include",
"description": (
"Directs the executor to include this field or fragment "
"only when the `if` argument is true."
),
"locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"],
"locations": [
DirectiveLocation.FIELD,
DirectiveLocation.FRAGMENT_SPREAD,
DirectiveLocation.INLINE_FRAGMENT,
],
"args": [
{
"name": "if",
Expand All @@ -28,13 +34,17 @@
],
}

SKIP_DIRECTIVE_JSON = {
SKIP_DIRECTIVE_JSON: IntrospectionDirective = {
"name": "skip",
"description": (
"Directs the executor to skip this field or fragment "
"when the `if` argument is true."
),
"locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"],
"locations": [
DirectiveLocation.FIELD,
DirectiveLocation.FRAGMENT_SPREAD,
DirectiveLocation.INLINE_FRAGMENT,
],
"args": [
{
"name": "if",
Expand All @@ -50,7 +60,7 @@
}


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

if directives is None:
directives = []
schema_introspection["directives"] = directives
schema_introspection["directives"] = directives = []

if not any(directive["name"] == "skip" for directive in directives):
directives.append(SKIP_DIRECTIVE_JSON)
Expand Down
2 changes: 1 addition & 1 deletion gql/utilities/get_introspection_query_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def get_introspection_query_ast(
if descriptions:
fragment_FullType.select(ds.__Type.description)
if specified_by_url:
fragment_FullType.select(ds.__Type.specifiedByUrl)
fragment_FullType.select(ds.__Type.specifiedByURL)

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

Expand Down
2 changes: 2 additions & 0 deletions gql/utilities/parse_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ def __init__(

self.result_stack: List[Any] = []

super().__init__()

@property
def current_result(self):
try:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from setuptools import setup, find_packages

install_requires = [
"graphql-core>=3.1.5,<3.2",
"graphql-core>=3.2,<3.3",
"yarl>=1.6,<2.0",
]

Expand Down
10 changes: 9 additions & 1 deletion tests/custom_scalars/test_money.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import asyncio
from math import isfinite
from typing import Any, Dict, NamedTuple, Optional

import pytest
from graphql import graphql_sync
from graphql.error import GraphQLError
from graphql.language import ValueNode
from graphql.pyutils import inspect, is_finite
from graphql.pyutils import inspect
from graphql.type import (
GraphQLArgument,
GraphQLField,
Expand Down Expand Up @@ -34,6 +35,13 @@ class Money(NamedTuple):
currency: str


def is_finite(value: Any) -> bool:
"""Return true if a value is a finite number."""
return (isinstance(value, int) and not isinstance(value, bool)) or (
isinstance(value, float) and isfinite(value)
)


def serialize_money(output_value: Any) -> Dict[str, Any]:
if not isinstance(output_value, Money):
raise GraphQLError("Cannot serialize money value: " + inspect(output_value))
Expand Down
10 changes: 5 additions & 5 deletions tests/fixtures/vcr_cassettes/queries.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interactions:
{\n ...TypeRef\n }\n defaultValue\n}\n\nfragment TypeRef on __Type {\n kind\n name\n ofType
{\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType
{\n kind\n name\n ofType {\n kind\n name\n ofType
{\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n}\n"}'
{\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n}"}'
headers:
Accept:
- '*/*'
Expand Down Expand Up @@ -202,7 +202,7 @@ interactions:
message: OK
- request:
body: '{"query": "{\n myFavoriteFilm: film(id: \"RmlsbToz\") {\n id\n title\n episodeId\n characters(first:
5) {\n edges {\n node {\n name\n }\n }\n }\n }\n}\n"}'
5) {\n edges {\n node {\n name\n }\n }\n }\n }\n}"}'
headers:
Accept:
- '*/*'
Expand Down Expand Up @@ -248,7 +248,7 @@ interactions:
code: 200
message: OK
- request:
body: '{"query": "query Planet($id: ID!) {\n planet(id: $id) {\n id\n name\n }\n}\n",
body: '{"query": "query Planet($id: ID!) {\n planet(id: $id) {\n id\n name\n }\n}",
"variables": {"id": "UGxhbmV0OjEw"}}'
headers:
Accept:
Expand Down Expand Up @@ -294,7 +294,7 @@ interactions:
message: OK
- request:
body: '{"query": "query Planet1 {\n planet(id: \"UGxhbmV0OjEw\") {\n id\n name\n }\n}\n\nquery
Planet2 {\n planet(id: \"UGxhbmV0OjEx\") {\n id\n name\n }\n}\n", "operationName":
Planet2 {\n planet(id: \"UGxhbmV0OjEx\") {\n id\n name\n }\n}", "operationName":
"Planet2"}'
headers:
Accept:
Expand Down Expand Up @@ -339,7 +339,7 @@ interactions:
code: 200
message: OK
- request:
body: '{"query": "query Planet($id: ID!) {\n planet(id: $id) {\n id\n name\n }\n}\n"}'
body: '{"query": "query Planet($id: ID!) {\n planet(id: $id) {\n id\n name\n }\n}"}'
headers:
Accept:
- '*/*'
Expand Down
Loading