Skip to content

Commit 7ee7a2b

Browse files
committed
Extract "identity_func" function to be used instead of lambda x: x
In theory should result in slightly smaller memory footprint and faster execution. In practice, it simplifies testing of scalar's default behavior. Replicates graphql/graphql-js@3d06795
1 parent ee1270f commit 7ee7a2b

File tree

10 files changed

+58
-16
lines changed

10 files changed

+58
-16
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ a query language for APIs created by Facebook.
1313
[![Code Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
1414

1515
The current version 1.0.5 of GraphQL-core-next is up-to-date with GraphQL.js version
16-
14.3.1. All parts of the API are covered by an extensive test suite of currently 1784
16+
14.3.1. All parts of the API are covered by an extensive test suite of currently 1786
1717
unit tests.
1818

1919

docs/modules/pyutils.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ PyUtils
1212
.. autofunction:: did_you_mean
1313
.. autoclass:: EventEmitter
1414
.. autoclass:: EventEmitterAsyncIterator
15+
.. autofunction:: identity_func
1516
.. autofunction:: inspect
1617
.. autofunction:: is_finite
1718
.. autofunction:: is_integer

graphql/pyutils/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from .dedent import dedent
1414
from .did_you_mean import did_you_mean
1515
from .event_emitter import EventEmitter, EventEmitterAsyncIterator
16+
from .identity_func import identity_func
1617
from .inspect import inspect
1718
from .is_finite import is_finite
1819
from .is_integer import is_integer
@@ -32,6 +33,7 @@
3233
"did_you_mean",
3334
"EventEmitter",
3435
"EventEmitterAsyncIterator",
36+
"identity_func",
3537
"inspect",
3638
"is_finite",
3739
"is_integer",

graphql/pyutils/identity_func.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from typing import cast, Any, TypeVar
2+
3+
from ..error import INVALID
4+
5+
__all__ = ["identity_func"]
6+
7+
8+
T = TypeVar("T")
9+
10+
11+
def identity_func(x: T = cast(Any, INVALID), *_args: Any) -> T:
12+
"""Return the first received argument."""
13+
return x

graphql/type/definition.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
UnionTypeExtensionNode,
4343
ValueNode,
4444
)
45-
from ..pyutils import AwaitableOrValue, cached_property, inspect
45+
from ..pyutils import AwaitableOrValue, cached_property, identity_func, inspect
4646
from ..utilities.value_from_ast_untyped import value_from_ast_untyped
4747

4848
if TYPE_CHECKING: # pragma: no cover
@@ -278,10 +278,6 @@ def resolve_thunk(thunk: Any) -> Any:
278278
return thunk() if callable(thunk) else thunk
279279

280280

281-
def default_value_parser(value: Any) -> Any:
282-
return value
283-
284-
285281
# Unfortunately these types cannot be specified any better in Python:
286282
GraphQLScalarSerializer = Callable
287283
GraphQLScalarValueParser = Callable
@@ -357,7 +353,7 @@ def __init__(
357353
f"{name} extension AST nodes must be ScalarTypeExtensionNode."
358354
)
359355
self.serialize = serialize # type: ignore
360-
self.parse_value = parse_value or default_value_parser
356+
self.parse_value = parse_value or identity_func
361357
self.parse_literal = parse_literal or value_from_ast_untyped
362358

363359
def __repr__(self):

graphql/utilities/build_ast_schema.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
parse,
2525
Node,
2626
)
27-
from ..pyutils import inspect
27+
from ..pyutils import identity_func, inspect
2828
from ..type import (
2929
GraphQLArgument,
3030
GraphQLDeprecatedDirective,
@@ -385,7 +385,7 @@ def _make_scalar_def(ast_node: ScalarTypeDefinitionNode) -> GraphQLScalarType:
385385
name=ast_node.name.value,
386386
description=ast_node.description.value if ast_node.description else None,
387387
ast_node=ast_node,
388-
serialize=lambda value: value,
388+
serialize=identity_func,
389389
)
390390

391391
def _make_input_object_def(

graphql/utilities/build_client_schema.py

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

44
from ..error import INVALID
55
from ..language import DirectiveLocation, parse_value
6-
from ..pyutils import inspect
6+
from ..pyutils import identity_func, inspect
77
from ..type import (
88
GraphQLArgument,
99
GraphQLDirective,
@@ -126,7 +126,7 @@ def build_scalar_def(scalar_introspection: Dict) -> GraphQLScalarType:
126126
return GraphQLScalarType(
127127
name=scalar_introspection["name"],
128128
description=scalar_introspection.get("description"),
129-
serialize=lambda value: value,
129+
serialize=identity_func,
130130
)
131131

132132
def build_object_def(object_introspection: Dict) -> GraphQLObjectType:

graphql/validation/rules/values_of_correct_type.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,14 @@ def enter_enum_value(self, node: EnumValueNode, *_args):
125125
if not is_enum_type(type_):
126126
self.is_valid_scalar(node)
127127
elif node.value not in type_.values:
128-
type_ = cast(GraphQLEnumType, type_)
129128
self.report_error(
130129
GraphQLError(
131130
bad_enum_value_message(
132-
type_.name, print_ast(node), enum_type_suggestion(type_, node)
131+
type_.name,
132+
print_ast(node),
133+
enum_type_suggestion(
134+
cast(GraphQLEnumType, type_), cast(EnumValueNode, node)
135+
),
133136
),
134137
node,
135138
)
@@ -165,7 +168,9 @@ def is_valid_scalar(self, node: ValueNode) -> None:
165168
bad_enum_value_message(
166169
location_type,
167170
print_ast(node),
168-
enum_type_suggestion(cast(GraphQLEnumType, type_), node),
171+
enum_type_suggestion(
172+
cast(GraphQLEnumType, type_), cast(EnumValueNode, node)
173+
),
169174
)
170175
if is_enum_type(type_)
171176
else bad_value_message(location_type, print_ast(node))
@@ -197,5 +202,4 @@ def is_valid_scalar(self, node: ValueNode) -> None:
197202

198203

199204
def enum_type_suggestion(type_: GraphQLEnumType, node: EnumValueNode) -> List[str]:
200-
all_names = list(type_.values)
201-
return suggestion_list(print_ast(node), all_names)
205+
return suggestion_list(print_ast(node), list(type_.values))

tests/pyutils/test_identity_func.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from graphql.error import INVALID
2+
from graphql.pyutils import identity_func
3+
4+
5+
def describe_identity_func():
6+
def returns_the_first_argument_it_receives():
7+
assert identity_func() is INVALID
8+
assert identity_func(INVALID) is INVALID
9+
assert identity_func(None) is None
10+
obj = object()
11+
assert identity_func(obj) is obj
12+
13+
assert identity_func(INVALID, None) is INVALID
14+
assert identity_func(None, INVALID) is None
15+
16+
assert identity_func(None, INVALID, obj) is None
17+
assert identity_func(INVALID, None, obj) is INVALID
18+
assert identity_func(obj, None, INVALID) is obj

tests/type/test_definition.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from pytest import mark, raises
44

55
from graphql.error import INVALID
6+
from graphql.pyutils import identity_func
67
from graphql.type import (
78
GraphQLArgument,
89
GraphQLEnumValue,
@@ -19,6 +20,7 @@
1920
GraphQLString,
2021
GraphQLUnionType,
2122
)
23+
from graphql.utilities import value_from_ast_untyped
2224

2325
ScalarType = GraphQLScalarType("Scalar", serialize=lambda: None)
2426
ObjectType = GraphQLObjectType("Object", {})
@@ -45,6 +47,12 @@ def accepts_a_scalar_type_defining_parse_value_and_parse_literal():
4547
parse_literal=lambda: None,
4648
)
4749

50+
def provides_default_methods_if_omitted():
51+
scalar = GraphQLScalarType("Foo", lambda: None)
52+
53+
assert scalar.parse_value is identity_func
54+
assert scalar.parse_literal is value_from_ast_untyped
55+
4856
def rejects_a_scalar_type_not_defining_serialize():
4957
with raises(
5058
TypeError, match="missing 1 required positional argument: 'serialize'"

0 commit comments

Comments
 (0)