strawberry-graphql 0.257.0__py3-none-any.whl → 0.257.0.dev1735244504__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- strawberry/__init__.py +0 -2
- strawberry/aiohttp/test/client.py +3 -1
- strawberry/aiohttp/views.py +3 -3
- strawberry/annotation.py +7 -5
- strawberry/asgi/__init__.py +4 -4
- strawberry/channels/handlers/ws_handler.py +3 -3
- strawberry/channels/testing.py +1 -3
- strawberry/cli/__init__.py +5 -7
- strawberry/cli/commands/codegen.py +14 -12
- strawberry/cli/commands/server.py +2 -2
- strawberry/cli/commands/upgrade/_run_codemod.py +3 -2
- strawberry/cli/utils/__init__.py +1 -1
- strawberry/codegen/plugins/python.py +5 -4
- strawberry/codegen/plugins/typescript.py +2 -3
- strawberry/codegen/query_codegen.py +11 -12
- strawberry/codemods/annotated_unions.py +1 -1
- strawberry/codemods/update_imports.py +4 -2
- strawberry/dataloader.py +2 -2
- strawberry/django/__init__.py +2 -2
- strawberry/django/views.py +3 -2
- strawberry/exceptions/__init__.py +2 -4
- strawberry/exceptions/exception.py +1 -1
- strawberry/exceptions/permission_fail_silently_requires_optional.py +1 -2
- strawberry/exceptions/utils/source_finder.py +1 -1
- strawberry/experimental/pydantic/_compat.py +4 -4
- strawberry/experimental/pydantic/conversion.py +5 -4
- strawberry/experimental/pydantic/fields.py +2 -1
- strawberry/experimental/pydantic/object_type.py +2 -6
- strawberry/experimental/pydantic/utils.py +9 -3
- strawberry/ext/mypy_plugin.py +14 -7
- strawberry/extensions/context.py +19 -15
- strawberry/extensions/field_extension.py +54 -53
- strawberry/extensions/query_depth_limiter.py +33 -27
- strawberry/extensions/tracing/datadog.py +1 -1
- strawberry/extensions/tracing/opentelemetry.py +14 -9
- strawberry/fastapi/router.py +3 -2
- strawberry/federation/schema.py +3 -3
- strawberry/flask/views.py +2 -3
- strawberry/http/async_base_view.py +4 -2
- strawberry/http/ides.py +3 -1
- strawberry/http/sync_base_view.py +2 -1
- strawberry/litestar/controller.py +5 -6
- strawberry/permission.py +1 -1
- strawberry/quart/views.py +2 -2
- strawberry/relay/fields.py +3 -28
- strawberry/relay/types.py +1 -1
- strawberry/schema/base.py +2 -0
- strawberry/schema/execute.py +11 -11
- strawberry/schema/name_converter.py +5 -4
- strawberry/schema/schema.py +4 -6
- strawberry/schema/schema_converter.py +19 -24
- strawberry/schema/subscribe.py +4 -4
- strawberry/schema/types/base_scalars.py +2 -4
- strawberry/schema/types/scalar.py +1 -1
- strawberry/schema_codegen/__init__.py +6 -5
- strawberry/subscriptions/protocols/graphql_transport_ws/handlers.py +2 -2
- strawberry/subscriptions/protocols/graphql_ws/handlers.py +3 -0
- strawberry/test/client.py +2 -1
- strawberry/types/arguments.py +2 -2
- strawberry/types/auto.py +3 -3
- strawberry/types/base.py +16 -12
- strawberry/types/field.py +7 -11
- strawberry/types/fields/resolver.py +19 -12
- strawberry/types/union.py +1 -1
- strawberry/types/unset.py +2 -1
- strawberry/utils/debug.py +1 -1
- strawberry/utils/deprecations.py +1 -1
- strawberry/utils/graphql_lexer.py +4 -6
- strawberry/utils/typing.py +2 -1
- {strawberry_graphql-0.257.0.dist-info → strawberry_graphql-0.257.0.dev1735244504.dist-info}/METADATA +2 -2
- {strawberry_graphql-0.257.0.dist-info → strawberry_graphql-0.257.0.dev1735244504.dist-info}/RECORD +74 -75
- {strawberry_graphql-0.257.0.dist-info → strawberry_graphql-0.257.0.dev1735244504.dist-info}/WHEEL +1 -1
- strawberry/types/cast.py +0 -35
- {strawberry_graphql-0.257.0.dist-info → strawberry_graphql-0.257.0.dev1735244504.dist-info}/LICENSE +0 -0
- {strawberry_graphql-0.257.0.dist-info → strawberry_graphql-0.257.0.dev1735244504.dist-info}/entry_points.txt +0 -0
strawberry/schema/base.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from abc import abstractmethod
|
4
|
+
from functools import lru_cache
|
4
5
|
from typing import TYPE_CHECKING, Any, Optional, Union
|
5
6
|
from typing_extensions import Protocol
|
6
7
|
|
@@ -87,6 +88,7 @@ class BaseSchema(Protocol):
|
|
87
88
|
raise NotImplementedError
|
88
89
|
|
89
90
|
@abstractmethod
|
91
|
+
@lru_cache
|
90
92
|
def get_directive_by_name(self, graphql_name: str) -> Optional[StrawberryDirective]:
|
91
93
|
raise NotImplementedError
|
92
94
|
|
strawberry/schema/execute.py
CHANGED
@@ -85,7 +85,7 @@ async def _parse_and_validate_async(
|
|
85
85
|
context: ExecutionContext, extensions_runner: SchemaExtensionsRunner
|
86
86
|
) -> Optional[PreExecutionError]:
|
87
87
|
if not context.query:
|
88
|
-
raise MissingQueryError
|
88
|
+
raise MissingQueryError()
|
89
89
|
|
90
90
|
async with extensions_runner.parsing():
|
91
91
|
try:
|
@@ -96,7 +96,7 @@ async def _parse_and_validate_async(
|
|
96
96
|
context.errors = [error]
|
97
97
|
return PreExecutionError(data=None, errors=[error])
|
98
98
|
|
99
|
-
except Exception as error:
|
99
|
+
except Exception as error:
|
100
100
|
error = GraphQLError(str(error), original_error=error)
|
101
101
|
context.errors = [error]
|
102
102
|
return PreExecutionError(data=None, errors=[error])
|
@@ -189,9 +189,9 @@ async def execute(
|
|
189
189
|
# only return a sanitised version to the client.
|
190
190
|
process_errors(result.errors, execution_context)
|
191
191
|
|
192
|
-
except (MissingQueryError, InvalidOperationTypeError):
|
193
|
-
raise
|
194
|
-
except Exception as exc:
|
192
|
+
except (MissingQueryError, InvalidOperationTypeError) as e:
|
193
|
+
raise e
|
194
|
+
except Exception as exc:
|
195
195
|
return await _handle_execution_result(
|
196
196
|
execution_context,
|
197
197
|
PreExecutionError(data=None, errors=[_coerce_error(exc)]),
|
@@ -219,7 +219,7 @@ def execute_sync(
|
|
219
219
|
# Note: In graphql-core the schema would be validated here but in
|
220
220
|
# Strawberry we are validating it at initialisation time instead
|
221
221
|
if not execution_context.query:
|
222
|
-
raise MissingQueryError
|
222
|
+
raise MissingQueryError()
|
223
223
|
|
224
224
|
with extensions_runner.parsing():
|
225
225
|
try:
|
@@ -238,7 +238,7 @@ def execute_sync(
|
|
238
238
|
)
|
239
239
|
|
240
240
|
if execution_context.operation_type not in allowed_operation_types:
|
241
|
-
raise InvalidOperationTypeError(execution_context.operation_type)
|
241
|
+
raise InvalidOperationTypeError(execution_context.operation_type)
|
242
242
|
|
243
243
|
with extensions_runner.validation():
|
244
244
|
_run_validation(execution_context)
|
@@ -266,7 +266,7 @@ def execute_sync(
|
|
266
266
|
if isawaitable(result):
|
267
267
|
result = cast(Awaitable[GraphQLExecutionResult], result) # type: ignore[redundant-cast]
|
268
268
|
ensure_future(result).cancel()
|
269
|
-
raise RuntimeError(
|
269
|
+
raise RuntimeError(
|
270
270
|
"GraphQL execution failed to complete synchronously."
|
271
271
|
)
|
272
272
|
|
@@ -282,9 +282,9 @@ def execute_sync(
|
|
282
282
|
# extension). That way we can log the original errors but
|
283
283
|
# only return a sanitised version to the client.
|
284
284
|
process_errors(result.errors, execution_context)
|
285
|
-
except (MissingQueryError, InvalidOperationTypeError):
|
286
|
-
raise
|
287
|
-
except Exception as exc:
|
285
|
+
except (MissingQueryError, InvalidOperationTypeError) as e:
|
286
|
+
raise e
|
287
|
+
except Exception as exc:
|
288
288
|
errors = [_coerce_error(exc)]
|
289
289
|
execution_context.errors = errors
|
290
290
|
process_errors(errors, execution_context)
|
@@ -47,17 +47,18 @@ class NameConverter:
|
|
47
47
|
return self.from_directive(type_)
|
48
48
|
if isinstance(type_, EnumDefinition): # TODO: Replace with StrawberryEnum
|
49
49
|
return self.from_enum(type_)
|
50
|
-
|
50
|
+
elif isinstance(type_, StrawberryObjectDefinition):
|
51
51
|
if type_.is_input:
|
52
52
|
return self.from_input_object(type_)
|
53
53
|
if type_.is_interface:
|
54
54
|
return self.from_interface(type_)
|
55
55
|
return self.from_object(type_)
|
56
|
-
|
56
|
+
elif isinstance(type_, StrawberryUnion):
|
57
57
|
return self.from_union(type_)
|
58
|
-
|
58
|
+
elif isinstance(type_, ScalarDefinition): # TODO: Replace with StrawberryScalar
|
59
59
|
return self.from_scalar(type_)
|
60
|
-
|
60
|
+
else:
|
61
|
+
return str(type_)
|
61
62
|
|
62
63
|
def from_argument(self, argument: StrawberryArgument) -> str:
|
63
64
|
return self.get_graphql_name(argument)
|
strawberry/schema/schema.py
CHANGED
@@ -30,7 +30,6 @@ from strawberry.extensions.directives import (
|
|
30
30
|
DirectivesExtensionSync,
|
31
31
|
)
|
32
32
|
from strawberry.extensions.runner import SchemaExtensionsRunner
|
33
|
-
from strawberry.printer import print_schema
|
34
33
|
from strawberry.schema.schema_converter import GraphQLCoreConverter
|
35
34
|
from strawberry.schema.types.scalar import DEFAULT_SCALAR_REGISTRY
|
36
35
|
from strawberry.types import ExecutionContext
|
@@ -41,6 +40,7 @@ from strawberry.types.base import (
|
|
41
40
|
)
|
42
41
|
from strawberry.types.graphql import OperationType
|
43
42
|
|
43
|
+
from ..printer import print_schema
|
44
44
|
from . import compat
|
45
45
|
from .base import BaseSchema
|
46
46
|
from .config import StrawberryConfig
|
@@ -177,11 +177,9 @@ class Schema(BaseSchema):
|
|
177
177
|
self.schema_converter.from_schema_directive(type_)
|
178
178
|
)
|
179
179
|
else:
|
180
|
-
if (
|
181
|
-
|
182
|
-
|
183
|
-
):
|
184
|
-
type_ = StrawberryAnnotation(type_).resolve() # noqa: PLW2901
|
180
|
+
if has_object_definition(type_):
|
181
|
+
if type_.__strawberry_definition__.is_graphql_generic:
|
182
|
+
type_ = StrawberryAnnotation(type_).resolve() # noqa: PLW2901
|
185
183
|
graphql_type = self.schema_converter.from_maybe_optional(type_)
|
186
184
|
if isinstance(graphql_type, GraphQLNonNull):
|
187
185
|
graphql_type = graphql_type.of_type
|
@@ -47,7 +47,6 @@ from strawberry.exceptions import (
|
|
47
47
|
ScalarAlreadyRegisteredError,
|
48
48
|
UnresolvedFieldTypeError,
|
49
49
|
)
|
50
|
-
from strawberry.extensions.field_extension import build_field_extension_resolvers
|
51
50
|
from strawberry.schema.types.scalar import _make_scalar_type
|
52
51
|
from strawberry.types.arguments import StrawberryArgument, convert_arguments
|
53
52
|
from strawberry.types.base import (
|
@@ -58,7 +57,6 @@ from strawberry.types.base import (
|
|
58
57
|
get_object_definition,
|
59
58
|
has_object_definition,
|
60
59
|
)
|
61
|
-
from strawberry.types.cast import get_strawberry_type_cast
|
62
60
|
from strawberry.types.enum import EnumDefinition
|
63
61
|
from strawberry.types.field import UNRESOLVED
|
64
62
|
from strawberry.types.lazy_type import LazyType
|
@@ -68,6 +66,7 @@ from strawberry.types.union import StrawberryUnion
|
|
68
66
|
from strawberry.types.unset import UNSET
|
69
67
|
from strawberry.utils.await_maybe import await_maybe
|
70
68
|
|
69
|
+
from ..extensions.field_extension import build_field_extension_resolvers
|
71
70
|
from . import compat
|
72
71
|
from .types.concrete_type import ConcreteType
|
73
72
|
|
@@ -92,9 +91,7 @@ if TYPE_CHECKING:
|
|
92
91
|
|
93
92
|
|
94
93
|
FieldType = TypeVar(
|
95
|
-
"FieldType",
|
96
|
-
bound=Union[GraphQLField, GraphQLInputField],
|
97
|
-
covariant=True,
|
94
|
+
"FieldType", bound=Union[GraphQLField, GraphQLInputField], covariant=True
|
98
95
|
)
|
99
96
|
|
100
97
|
|
@@ -377,6 +374,8 @@ class GraphQLCoreConverter:
|
|
377
374
|
# self.from_resolver needs to be called before accessing field.type because
|
378
375
|
# in there a field extension might want to change the type during its apply
|
379
376
|
resolver = self.from_resolver(field)
|
377
|
+
# TODO: think more about this
|
378
|
+
field._resolver = resolver # type: ignore
|
380
379
|
field_type = cast(
|
381
380
|
"GraphQLOutputType",
|
382
381
|
self.from_maybe_optional(
|
@@ -620,9 +619,6 @@ class GraphQLCoreConverter:
|
|
620
619
|
)
|
621
620
|
|
622
621
|
def is_type_of(obj: Any, _info: GraphQLResolveInfo) -> bool:
|
623
|
-
if (type_cast := get_strawberry_type_cast(obj)) is not None:
|
624
|
-
return type_cast in possible_types
|
625
|
-
|
626
622
|
if object_type.concrete_of and (
|
627
623
|
has_object_definition(obj)
|
628
624
|
and obj.__strawberry_definition__.origin
|
@@ -762,8 +758,9 @@ class GraphQLCoreConverter:
|
|
762
758
|
if field.is_async:
|
763
759
|
_async_resolver._is_default = not field.base_resolver # type: ignore
|
764
760
|
return _async_resolver
|
765
|
-
|
766
|
-
|
761
|
+
else:
|
762
|
+
_resolver._is_default = not field.base_resolver # type: ignore
|
763
|
+
return _resolver
|
767
764
|
|
768
765
|
def from_scalar(self, scalar: type) -> GraphQLScalarType:
|
769
766
|
scalar_definition: ScalarDefinition
|
@@ -813,9 +810,10 @@ class GraphQLCoreConverter:
|
|
813
810
|
NoneType = type(None)
|
814
811
|
if type_ is None or type_ is NoneType:
|
815
812
|
return self.from_type(type_)
|
816
|
-
|
813
|
+
elif isinstance(type_, StrawberryOptional):
|
817
814
|
return self.from_type(type_.of_type)
|
818
|
-
|
815
|
+
else:
|
816
|
+
return GraphQLNonNull(self.from_type(type_))
|
819
817
|
|
820
818
|
def from_type(self, type_: Union[StrawberryType, type]) -> GraphQLNullableType:
|
821
819
|
if compat.is_graphql_generic(type_):
|
@@ -823,27 +821,27 @@ class GraphQLCoreConverter:
|
|
823
821
|
|
824
822
|
if isinstance(type_, EnumDefinition): # TODO: Replace with StrawberryEnum
|
825
823
|
return self.from_enum(type_)
|
826
|
-
|
824
|
+
elif compat.is_input_type(type_): # TODO: Replace with StrawberryInputObject
|
827
825
|
return self.from_input_object(type_)
|
828
|
-
|
826
|
+
elif isinstance(type_, StrawberryList):
|
829
827
|
return self.from_list(type_)
|
830
|
-
|
828
|
+
elif compat.is_interface_type(type_): # TODO: Replace with StrawberryInterface
|
831
829
|
type_definition: StrawberryObjectDefinition = (
|
832
830
|
type_.__strawberry_definition__ # type: ignore
|
833
831
|
)
|
834
832
|
return self.from_interface(type_definition)
|
835
|
-
|
833
|
+
elif has_object_definition(type_):
|
836
834
|
return self.from_object(type_.__strawberry_definition__)
|
837
|
-
|
835
|
+
elif compat.is_enum(type_): # TODO: Replace with StrawberryEnum
|
838
836
|
enum_definition: EnumDefinition = type_._enum_definition # type: ignore
|
839
837
|
return self.from_enum(enum_definition)
|
840
|
-
|
838
|
+
elif isinstance(type_, StrawberryObjectDefinition):
|
841
839
|
return self.from_object(type_)
|
842
|
-
|
840
|
+
elif isinstance(type_, StrawberryUnion):
|
843
841
|
return self.from_union(type_)
|
844
|
-
|
842
|
+
elif isinstance(type_, LazyType):
|
845
843
|
return self.from_type(type_.resolve_type())
|
846
|
-
|
844
|
+
elif compat.is_scalar(
|
847
845
|
type_, self.scalar_registry
|
848
846
|
): # TODO: Replace with StrawberryScalar
|
849
847
|
return self.from_scalar(type_)
|
@@ -902,9 +900,6 @@ class GraphQLCoreConverter:
|
|
902
900
|
if object_type.interfaces:
|
903
901
|
|
904
902
|
def is_type_of(obj: Any, _info: GraphQLResolveInfo) -> bool:
|
905
|
-
if (type_cast := get_strawberry_type_cast(obj)) is not None:
|
906
|
-
return type_cast is object_type.origin
|
907
|
-
|
908
903
|
if object_type.concrete_of and (
|
909
904
|
has_object_definition(obj)
|
910
905
|
and obj.__strawberry_definition__.origin
|
strawberry/schema/subscribe.py
CHANGED
@@ -27,7 +27,7 @@ if TYPE_CHECKING:
|
|
27
27
|
from graphql.execution.middleware import MiddlewareManager
|
28
28
|
from graphql.type.schema import GraphQLSchema
|
29
29
|
|
30
|
-
from
|
30
|
+
from ..extensions.runner import SchemaExtensionsRunner
|
31
31
|
|
32
32
|
SubscriptionResult: TypeAlias = Union[
|
33
33
|
PreExecutionError, AsyncGenerator[ExecutionResult, None]
|
@@ -80,7 +80,7 @@ async def _subscribe(
|
|
80
80
|
)
|
81
81
|
# graphql-core 3.2 doesn't handle some of the pre-execution errors.
|
82
82
|
# see `test_subscription_immediate_error`
|
83
|
-
except Exception as exc:
|
83
|
+
except Exception as exc:
|
84
84
|
aiter_or_result = OriginalExecutionResult(
|
85
85
|
data=None, errors=[_coerce_error(exc)]
|
86
86
|
)
|
@@ -103,7 +103,7 @@ async def _subscribe(
|
|
103
103
|
process_errors,
|
104
104
|
)
|
105
105
|
# graphql-core doesn't handle exceptions raised while executing.
|
106
|
-
except Exception as exc:
|
106
|
+
except Exception as exc:
|
107
107
|
yield await _handle_execution_result(
|
108
108
|
execution_context,
|
109
109
|
OriginalExecutionResult(data=None, errors=[_coerce_error(exc)]),
|
@@ -111,7 +111,7 @@ async def _subscribe(
|
|
111
111
|
process_errors,
|
112
112
|
)
|
113
113
|
# catch exceptions raised in `on_execute` hook.
|
114
|
-
except Exception as exc:
|
114
|
+
except Exception as exc:
|
115
115
|
origin_result = OriginalExecutionResult(
|
116
116
|
data=None, errors=[_coerce_error(exc)]
|
117
117
|
)
|
@@ -15,9 +15,7 @@ def wrap_parser(parser: Callable, type_: str) -> Callable:
|
|
15
15
|
try:
|
16
16
|
return parser(value)
|
17
17
|
except ValueError as e:
|
18
|
-
raise GraphQLError(
|
19
|
-
f'Value cannot represent a {type_}: "{value}". {e}'
|
20
|
-
)
|
18
|
+
raise GraphQLError(f'Value cannot represent a {type_}: "{value}". {e}')
|
21
19
|
|
22
20
|
return inner
|
23
21
|
|
@@ -26,7 +24,7 @@ def parse_decimal(value: object) -> decimal.Decimal:
|
|
26
24
|
try:
|
27
25
|
return decimal.Decimal(str(value))
|
28
26
|
except decimal.DecimalException:
|
29
|
-
raise GraphQLError(f'Value cannot represent a Decimal: "{value}".')
|
27
|
+
raise GraphQLError(f'Value cannot represent a Decimal: "{value}".')
|
30
28
|
|
31
29
|
|
32
30
|
isoformat = methodcaller("isoformat")
|
@@ -62,7 +62,7 @@ DEFAULT_SCALAR_REGISTRY: dict[object, ScalarDefinition] = {
|
|
62
62
|
datetime.datetime: _get_scalar_definition(base_scalars.DateTime),
|
63
63
|
datetime.time: _get_scalar_definition(base_scalars.Time),
|
64
64
|
decimal.Decimal: _get_scalar_definition(base_scalars.Decimal),
|
65
|
-
# We can't wrap
|
65
|
+
# We can't wrap GLobalID with @scalar because it has custom attributes/methods
|
66
66
|
GlobalID: _get_scalar_definition(
|
67
67
|
scalar(
|
68
68
|
GlobalID,
|
@@ -115,7 +115,7 @@ def _get_field_type(
|
|
115
115
|
|
116
116
|
if isinstance(field_type, NonNullTypeNode):
|
117
117
|
return _get_field_type(field_type.type, was_non_nullable=True)
|
118
|
-
|
118
|
+
elif isinstance(field_type, ListTypeNode):
|
119
119
|
expr = cst.Subscript(
|
120
120
|
value=cst.Name("list"),
|
121
121
|
slice=[
|
@@ -262,13 +262,14 @@ ArgumentValue: TypeAlias = Union[str, bool, list["ArgumentValue"]]
|
|
262
262
|
def _get_argument_value(argument_value: ConstValueNode) -> ArgumentValue:
|
263
263
|
if isinstance(argument_value, StringValueNode):
|
264
264
|
return argument_value.value
|
265
|
-
|
265
|
+
elif isinstance(argument_value, EnumValueDefinitionNode):
|
266
266
|
return argument_value.name.value
|
267
|
-
|
267
|
+
elif isinstance(argument_value, ListValueNode):
|
268
268
|
return [_get_argument_value(arg) for arg in argument_value.values]
|
269
|
-
|
269
|
+
elif isinstance(argument_value, BooleanValueNode):
|
270
270
|
return argument_value.value
|
271
|
-
|
271
|
+
else:
|
272
|
+
raise NotImplementedError(f"Unknown argument value {argument_value}")
|
272
273
|
|
273
274
|
|
274
275
|
def _get_directives(
|
@@ -122,7 +122,7 @@ class BaseGraphQLTransportWSHandler(Generic[Context, RootValue]):
|
|
122
122
|
self.connection_timed_out = True
|
123
123
|
reason = "Connection initialisation timeout"
|
124
124
|
await self.websocket.close(code=4408, reason=reason)
|
125
|
-
except Exception as error:
|
125
|
+
except Exception as error:
|
126
126
|
await self.handle_task_exception(error) # pragma: no cover
|
127
127
|
finally:
|
128
128
|
# do not clear self.connection_init_timeout_task
|
@@ -298,7 +298,7 @@ class BaseGraphQLTransportWSHandler(Generic[Context, RootValue]):
|
|
298
298
|
{"id": operation.id, "type": "complete"}
|
299
299
|
)
|
300
300
|
|
301
|
-
except BaseException: # pragma: no cover
|
301
|
+
except BaseException as e: # pragma: no cover
|
302
302
|
self.operations.pop(operation.id, None)
|
303
303
|
raise
|
304
304
|
finally:
|
strawberry/test/client.py
CHANGED
@@ -188,7 +188,8 @@ class BaseGraphQLTestClient(ABC):
|
|
188
188
|
# Variables can be mixed files and other data, we don't want to map non-files
|
189
189
|
# vars so we need to remove them, we can't remove them before
|
190
190
|
# because they can be part of a list of files or folder
|
191
|
-
|
191
|
+
map_without_vars = {k: v for k, v in map.items() if k in files}
|
192
|
+
return map_without_vars
|
192
193
|
|
193
194
|
def _decode(self, response: Any, type: Literal["multipart", "json"]) -> Any:
|
194
195
|
if type == "multipart":
|
strawberry/types/arguments.py
CHANGED
@@ -23,8 +23,8 @@ from strawberry.types.base import (
|
|
23
23
|
)
|
24
24
|
from strawberry.types.enum import EnumDefinition
|
25
25
|
from strawberry.types.lazy_type import LazyType, StrawberryLazyReference
|
26
|
-
from strawberry.types.unset import UNSET as _deprecated_UNSET
|
27
|
-
from strawberry.types.unset import _deprecated_is_unset # noqa:
|
26
|
+
from strawberry.types.unset import UNSET as _deprecated_UNSET
|
27
|
+
from strawberry.types.unset import _deprecated_is_unset # noqa # type: ignore
|
28
28
|
|
29
29
|
if TYPE_CHECKING:
|
30
30
|
from strawberry.schema.config import StrawberryConfig
|
strawberry/types/auto.py
CHANGED
@@ -23,8 +23,8 @@ class StrawberryAutoMeta(type):
|
|
23
23
|
|
24
24
|
"""
|
25
25
|
|
26
|
-
def __init__(
|
27
|
-
|
26
|
+
def __init__(self, *args: str, **kwargs: Any) -> None:
|
27
|
+
self._instance: Optional[StrawberryAuto] = None
|
28
28
|
super().__init__(*args, **kwargs)
|
29
29
|
|
30
30
|
def __call__(cls, *args: str, **kwargs: Any) -> Any:
|
@@ -34,7 +34,7 @@ class StrawberryAutoMeta(type):
|
|
34
34
|
return cls._instance
|
35
35
|
|
36
36
|
def __instancecheck__(
|
37
|
-
|
37
|
+
self,
|
38
38
|
instance: Union[StrawberryAuto, StrawberryAnnotation, StrawberryType, type],
|
39
39
|
) -> bool:
|
40
40
|
if isinstance(instance, StrawberryAnnotation):
|
strawberry/types/base.py
CHANGED
@@ -54,12 +54,12 @@ class StrawberryType(ABC):
|
|
54
54
|
str, Union[StrawberryType, type[WithStrawberryObjectDefinition]]
|
55
55
|
],
|
56
56
|
) -> Union[StrawberryType, type[WithStrawberryObjectDefinition]]:
|
57
|
-
raise NotImplementedError
|
57
|
+
raise NotImplementedError()
|
58
58
|
|
59
59
|
@property
|
60
60
|
@abstractmethod
|
61
61
|
def is_graphql_generic(self) -> bool:
|
62
|
-
raise NotImplementedError
|
62
|
+
raise NotImplementedError()
|
63
63
|
|
64
64
|
def has_generic(self, type_var: TypeVar) -> bool:
|
65
65
|
return False
|
@@ -70,15 +70,17 @@ class StrawberryType(ABC):
|
|
70
70
|
if isinstance(other, StrawberryType):
|
71
71
|
return self is other
|
72
72
|
|
73
|
-
|
73
|
+
elif isinstance(other, StrawberryAnnotation):
|
74
74
|
return self == other.resolve()
|
75
75
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
else:
|
77
|
+
# This could be simplified if StrawberryAnnotation.resolve() always returned
|
78
|
+
# a StrawberryType
|
79
|
+
resolved = StrawberryAnnotation(other).resolve()
|
80
|
+
if isinstance(resolved, StrawberryType):
|
81
|
+
return self == resolved
|
82
|
+
else:
|
83
|
+
return NotImplemented
|
82
84
|
|
83
85
|
def __hash__(self) -> int:
|
84
86
|
# TODO: Is this a bad idea? __eq__ objects are supposed to have the same hash
|
@@ -98,7 +100,8 @@ class StrawberryContainer(StrawberryType):
|
|
98
100
|
if isinstance(other, StrawberryType):
|
99
101
|
if isinstance(other, StrawberryContainer):
|
100
102
|
return self.of_type == other.of_type
|
101
|
-
|
103
|
+
else:
|
104
|
+
return False
|
102
105
|
|
103
106
|
return super().__eq__(other)
|
104
107
|
|
@@ -109,10 +112,11 @@ class StrawberryContainer(StrawberryType):
|
|
109
112
|
|
110
113
|
return list(parameters) if parameters else []
|
111
114
|
|
112
|
-
|
115
|
+
elif isinstance(self.of_type, StrawberryType):
|
113
116
|
return self.of_type.type_params
|
114
117
|
|
115
|
-
|
118
|
+
else:
|
119
|
+
return []
|
116
120
|
|
117
121
|
def copy_with(
|
118
122
|
self,
|
strawberry/types/field.py
CHANGED
@@ -191,21 +191,17 @@ class StrawberryField(dataclasses.Field):
|
|
191
191
|
for argument in resolver.arguments:
|
192
192
|
if isinstance(argument.type_annotation.annotation, str):
|
193
193
|
continue
|
194
|
-
|
195
|
-
if isinstance(argument.type, StrawberryUnion):
|
196
|
-
raise InvalidArgumentTypeError(
|
197
|
-
resolver,
|
198
|
-
argument,
|
199
|
-
)
|
200
|
-
|
201
|
-
if (
|
202
|
-
has_object_definition(argument.type)
|
203
|
-
and argument.type.__strawberry_definition__.is_interface
|
204
|
-
):
|
194
|
+
elif isinstance(argument.type, StrawberryUnion):
|
205
195
|
raise InvalidArgumentTypeError(
|
206
196
|
resolver,
|
207
197
|
argument,
|
208
198
|
)
|
199
|
+
elif has_object_definition(argument.type):
|
200
|
+
if argument.type.__strawberry_definition__.is_interface:
|
201
|
+
raise InvalidArgumentTypeError(
|
202
|
+
resolver,
|
203
|
+
argument,
|
204
|
+
)
|
209
205
|
|
210
206
|
self.base_resolver = resolver
|
211
207
|
|
@@ -91,7 +91,8 @@ class ReservedNameBoundParameter(NamedTuple):
|
|
91
91
|
if parameters: # Add compatibility for resolvers with no arguments
|
92
92
|
first_parameter = parameters[0]
|
93
93
|
return first_parameter if first_parameter.name == self.name else None
|
94
|
-
|
94
|
+
else:
|
95
|
+
return None
|
95
96
|
|
96
97
|
|
97
98
|
class ReservedType(NamedTuple):
|
@@ -144,19 +145,21 @@ class ReservedType(NamedTuple):
|
|
144
145
|
)
|
145
146
|
warnings.warn(warning, stacklevel=3)
|
146
147
|
return reserved_name
|
147
|
-
|
148
|
+
else:
|
149
|
+
return None
|
148
150
|
|
149
151
|
def is_reserved_type(self, other: builtins.type) -> bool:
|
150
152
|
origin = cast(type, get_origin(other)) or other
|
151
153
|
if origin is Annotated:
|
152
154
|
# Handle annotated arguments such as Private[str] and DirectiveValue[str]
|
153
155
|
return type_has_annotation(other, self.type)
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
156
|
+
else:
|
157
|
+
# Handle both concrete and generic types (i.e Info, and Info)
|
158
|
+
return (
|
159
|
+
issubclass(origin, self.type)
|
160
|
+
if isinstance(origin, type)
|
161
|
+
else origin is self.type
|
162
|
+
)
|
160
163
|
|
161
164
|
|
162
165
|
SELF_PARAMSPEC = ReservedNameBoundParameter("self")
|
@@ -306,20 +309,24 @@ class StrawberryResolver(Generic[T]):
|
|
306
309
|
reserved_names = {p.name for p in reserved_parameters.values() if p is not None}
|
307
310
|
|
308
311
|
annotations = self._unbound_wrapped_func.__annotations__
|
309
|
-
|
312
|
+
annotations = {
|
310
313
|
name: annotation
|
311
314
|
for name, annotation in annotations.items()
|
312
315
|
if name not in reserved_names
|
313
316
|
}
|
314
317
|
|
318
|
+
return annotations
|
319
|
+
|
315
320
|
@cached_property
|
316
321
|
def type_annotation(self) -> Optional[StrawberryAnnotation]:
|
317
322
|
return_annotation = self.signature.return_annotation
|
318
323
|
if return_annotation is inspect.Signature.empty:
|
319
324
|
return None
|
320
|
-
|
321
|
-
|
322
|
-
|
325
|
+
else:
|
326
|
+
type_annotation = StrawberryAnnotation(
|
327
|
+
annotation=return_annotation, namespace=self._namespace
|
328
|
+
)
|
329
|
+
return type_annotation
|
323
330
|
|
324
331
|
@property
|
325
332
|
def type(self) -> Optional[Union[StrawberryType, type]]:
|
strawberry/types/union.py
CHANGED
@@ -54,7 +54,7 @@ class StrawberryUnion(StrawberryType):
|
|
54
54
|
def __init__(
|
55
55
|
self,
|
56
56
|
name: Optional[str] = None,
|
57
|
-
type_annotations: tuple[StrawberryAnnotation, ...] = (),
|
57
|
+
type_annotations: tuple[StrawberryAnnotation, ...] = tuple(),
|
58
58
|
description: Optional[str] = None,
|
59
59
|
directives: Iterable[object] = (),
|
60
60
|
) -> None:
|
strawberry/types/unset.py
CHANGED
strawberry/utils/debug.py
CHANGED
@@ -30,7 +30,7 @@ def pretty_print_graphql_operation(
|
|
30
30
|
if operation_name == "IntrospectionQuery":
|
31
31
|
return
|
32
32
|
|
33
|
-
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
33
|
+
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
34
34
|
|
35
35
|
print(f"[{now}]: {operation_name or 'No operation name'}") # noqa: T201
|
36
36
|
print(highlight(query, GraphQLLexer(), Terminal256Formatter())) # noqa: T201
|
strawberry/utils/deprecations.py
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import Any, ClassVar
|
2
|
-
|
3
1
|
from pygments import token
|
4
2
|
from pygments.lexer import RegexLexer
|
5
3
|
|
@@ -8,11 +6,11 @@ class GraphQLLexer(RegexLexer):
|
|
8
6
|
"""GraphQL Lexer for Pygments, used by the debug server."""
|
9
7
|
|
10
8
|
name = "GraphQL"
|
11
|
-
aliases
|
12
|
-
filenames
|
13
|
-
mimetypes
|
9
|
+
aliases = ["graphql", "gql"]
|
10
|
+
filenames = ["*.graphql", "*.gql"]
|
11
|
+
mimetypes = ["application/graphql"]
|
14
12
|
|
15
|
-
tokens
|
13
|
+
tokens = {
|
16
14
|
"root": [
|
17
15
|
(r"#.*", token.Comment.Singline),
|
18
16
|
(r"\.\.\.", token.Operator),
|