Skip to content

Commit 16f4787

Browse files
committed
Add update_schema_scalar to update a single scalar with name
+ raises TypeError and KeyError instead of GraphQLErrors
1 parent 7d83add commit 16f4787

File tree

5 files changed

+70
-29
lines changed

5 files changed

+70
-29
lines changed

docs/usage/custom_scalars_and_enums.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,19 +92,22 @@ where the serialize and parse_value methods simply return the serialized value w
9292

9393
In that case, if you want gql to parse custom scalars to a more useful Python representation,
9494
or to serialize custom scalars variables from a Python representation,
95-
then you can use the :func:`update_schema_scalars <gql.utilities.update_schema_scalars>` method
96-
to modify the definition of the scalars in your schema so that gql could do the parsing/serialization.
95+
then you can use the :func:`update_schema_scalars <gql.utilities.update_schema_scalars>`
96+
or :func:`update_schema_scalar <gql.utilities.update_schema_scalar>` methods
97+
to modify the definition of a scalar in your schema so that gql could do the parsing/serialization.
9798

9899
.. code-block:: python
99100
100-
from gql.utilities import update_schema_scalars
101+
from gql.utilities import update_schema_scalar
101102
102103
with open('path/to/schema.graphql') as f:
103104
schema_str = f.read()
104105
105106
client = Client(schema=schema_str, ...)
106107
107-
update_schema_scalars(client.schema, [DatetimeScalar])
108+
update_schema_scalar(client.schema, "Datetime", DatetimeScalar)
109+
110+
# or update_schema_scalars(client.schema, [DatetimeScalar])
108111
109112
.. _enums:
110113

gql/utilities/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from .parse_result import parse_result
22
from .update_schema_enum import update_schema_enum
3-
from .update_schema_scalars import update_schema_scalars
3+
from .update_schema_scalars import update_schema_scalar, update_schema_scalars
44

55
__all__ = [
66
"update_schema_scalars",
7+
"update_schema_scalar",
78
"update_schema_enum",
89
"parse_result",
910
]

gql/utilities/update_schema_enum.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ class Color(Enum):
2525
2626
:param schema: a GraphQL Schema already containing the GraphQLEnumType type.
2727
:param name: the name of the enum in the GraphQL schema
28-
:values: Either a Python Enum or a dict of values. The keys of the provided
28+
:param values: Either a Python Enum or a dict of values. The keys of the provided
2929
values should correspond to the keys of the existing enum in the schema.
30-
:use_enum_values: By default, we configure the GraphQLEnumType to serialize
30+
:param use_enum_values: By default, we configure the GraphQLEnumType to serialize
3131
to enum instances (ie: .parse_value() returns Color.RED).
3232
If use_enum_values is set to True, then .parse_value() returns 0.
3333
use_enum_values=True is the defaut behaviour when passing an Enum
Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,35 @@
11
from typing import Iterable, List
22

3-
from graphql import GraphQLError, GraphQLScalarType, GraphQLSchema
3+
from graphql import GraphQLScalarType, GraphQLSchema
4+
5+
6+
def update_schema_scalar(schema: GraphQLSchema, name: str, scalar: GraphQLScalarType):
7+
"""Update the scalar in a schema with the scalar provided.
8+
9+
This can be used to update the default Custom Scalar implementation
10+
when the schema has been provided from a text file or from introspection.
11+
"""
12+
13+
if not isinstance(scalar, GraphQLScalarType):
14+
raise TypeError("Scalars should be instances of GraphQLScalarType.")
15+
16+
schema_scalar = schema.get_type(name)
17+
18+
if schema_scalar is None:
19+
raise KeyError(f"Scalar '{name}' not found in schema.")
20+
21+
if not isinstance(schema_scalar, GraphQLScalarType):
22+
raise TypeError(
23+
f'The type "{name}" is not a GraphQLScalarType,'
24+
f"it is a {type(schema_scalar)}"
25+
)
26+
27+
# Update the conversion methods
28+
# Using setattr because mypy has a false positive
29+
# https://github.com/python/mypy/issues/2427
30+
setattr(schema_scalar, "serialize", scalar.serialize)
31+
setattr(schema_scalar, "parse_value", scalar.parse_value)
32+
setattr(schema_scalar, "parse_literal", scalar.parse_literal)
433

534

635
def update_schema_scalars(schema: GraphQLSchema, scalars: List[GraphQLScalarType]):
@@ -11,22 +40,10 @@ def update_schema_scalars(schema: GraphQLSchema, scalars: List[GraphQLScalarType
1140
"""
1241

1342
if not isinstance(scalars, Iterable):
14-
raise GraphQLError("Scalars argument should be a list of scalars.")
43+
raise TypeError("Scalars argument should be a list of scalars.")
1544

1645
for scalar in scalars:
1746
if not isinstance(scalar, GraphQLScalarType):
18-
raise GraphQLError("Scalars should be instances of GraphQLScalarType.")
19-
20-
try:
21-
schema_scalar = schema.type_map[scalar.name]
22-
except KeyError:
23-
raise GraphQLError(f"Scalar '{scalar.name}' not found in schema.")
24-
25-
assert isinstance(schema_scalar, GraphQLScalarType)
47+
raise TypeError("Scalars should be instances of GraphQLScalarType.")
2648

27-
# Update the conversion methods
28-
# Using setattr because mypy has a false positive
29-
# https://github.com/python/mypy/issues/2427
30-
setattr(schema_scalar, "serialize", scalar.serialize)
31-
setattr(schema_scalar, "parse_value", scalar.parse_value)
32-
setattr(schema_scalar, "parse_literal", scalar.parse_literal)
49+
update_schema_scalar(schema, scalar.name, scalar)

tests/custom_scalars/test_money.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from gql import Client, gql
2323
from gql.transport.exceptions import TransportQueryError
24-
from gql.utilities import update_schema_scalars
24+
from gql.utilities import update_schema_scalar, update_schema_scalars
2525
from gql.variable_values import serialize_value
2626

2727
from ..conftest import MS
@@ -623,7 +623,8 @@ async def test_update_schema_scalars(event_loop, aiohttp_server):
623623

624624
# Update the schema MoneyScalar default implementation from
625625
# introspection with our provided conversion methods
626-
update_schema_scalars(session.client.schema, [MoneyScalar])
626+
# update_schema_scalars(session.client.schema, [MoneyScalar])
627+
update_schema_scalar(session.client.schema, "Money", MoneyScalar)
627628

628629
query = gql("query myquery($money: Money) {toEuros(money: $money)}")
629630

@@ -639,17 +640,24 @@ async def test_update_schema_scalars(event_loop, aiohttp_server):
639640

640641
def test_update_schema_scalars_invalid_scalar():
641642

642-
with pytest.raises(GraphQLError) as exc_info:
643+
with pytest.raises(TypeError) as exc_info:
643644
update_schema_scalars(schema, [int])
644645

645646
exception = exc_info.value
646647

647648
assert str(exception) == "Scalars should be instances of GraphQLScalarType."
648649

650+
with pytest.raises(TypeError) as exc_info:
651+
update_schema_scalar(schema, "test", int)
652+
653+
exception = exc_info.value
654+
655+
assert str(exception) == "Scalars should be instances of GraphQLScalarType."
656+
649657

650658
def test_update_schema_scalars_invalid_scalar_argument():
651659

652-
with pytest.raises(GraphQLError) as exc_info:
660+
with pytest.raises(TypeError) as exc_info:
653661
update_schema_scalars(schema, MoneyScalar)
654662

655663
exception = exc_info.value
@@ -661,12 +669,24 @@ def test_update_schema_scalars_scalar_not_found_in_schema():
661669

662670
NotFoundScalar = GraphQLScalarType(name="abcd",)
663671

664-
with pytest.raises(GraphQLError) as exc_info:
672+
with pytest.raises(KeyError) as exc_info:
665673
update_schema_scalars(schema, [MoneyScalar, NotFoundScalar])
666674

667675
exception = exc_info.value
668676

669-
assert str(exception) == "Scalar 'abcd' not found in schema."
677+
assert "Scalar 'abcd' not found in schema." in str(exception)
678+
679+
680+
def test_update_schema_scalars_scalar_type_is_not_a_scalar_in_schema():
681+
682+
with pytest.raises(TypeError) as exc_info:
683+
update_schema_scalar(schema, "CountriesBalance", MoneyScalar)
684+
685+
exception = exc_info.value
686+
687+
assert 'The type "CountriesBalance" is not a GraphQLScalarType, it is a' in str(
688+
exception
689+
)
670690

671691

672692
@pytest.mark.asyncio

0 commit comments

Comments
 (0)