strawberry-graphql 0.254.1__py3-none-any.whl → 0.256.0__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 +9 -9
- strawberry/aiohttp/test/client.py +10 -8
- strawberry/aiohttp/views.py +5 -7
- strawberry/annotation.py +13 -16
- strawberry/asgi/__init__.py +3 -6
- strawberry/asgi/test/client.py +9 -8
- strawberry/chalice/views.py +4 -2
- strawberry/channels/__init__.py +1 -1
- strawberry/channels/handlers/base.py +3 -7
- strawberry/channels/handlers/http_handler.py +5 -6
- strawberry/channels/handlers/ws_handler.py +3 -4
- strawberry/channels/testing.py +5 -9
- strawberry/cli/commands/codegen.py +9 -9
- strawberry/cli/commands/upgrade/__init__.py +2 -3
- strawberry/cli/commands/upgrade/_run_codemod.py +7 -5
- strawberry/codegen/exceptions.py +2 -2
- strawberry/codegen/plugins/print_operation.py +6 -6
- strawberry/codegen/plugins/python.py +6 -6
- strawberry/codegen/plugins/typescript.py +3 -3
- strawberry/codegen/query_codegen.py +29 -34
- strawberry/codegen/types.py +35 -34
- strawberry/codemods/annotated_unions.py +5 -2
- strawberry/dataloader.py +13 -20
- strawberry/directive.py +12 -5
- strawberry/django/test/client.py +4 -4
- strawberry/django/views.py +4 -5
- strawberry/exceptions/__init__.py +24 -24
- strawberry/exceptions/conflicting_arguments.py +2 -2
- strawberry/exceptions/duplicated_type_name.py +3 -3
- strawberry/exceptions/handler.py +7 -7
- strawberry/exceptions/invalid_union_type.py +2 -2
- strawberry/exceptions/missing_arguments_annotations.py +2 -2
- strawberry/exceptions/missing_field_annotation.py +2 -2
- strawberry/exceptions/object_is_not_an_enum.py +2 -2
- strawberry/exceptions/private_strawberry_field.py +2 -2
- strawberry/exceptions/syntax.py +4 -4
- strawberry/exceptions/utils/source_finder.py +7 -6
- strawberry/experimental/pydantic/__init__.py +3 -3
- strawberry/experimental/pydantic/_compat.py +14 -14
- strawberry/experimental/pydantic/conversion.py +2 -2
- strawberry/experimental/pydantic/conversion_types.py +3 -3
- strawberry/experimental/pydantic/error_type.py +18 -16
- strawberry/experimental/pydantic/exceptions.py +5 -5
- strawberry/experimental/pydantic/fields.py +2 -13
- strawberry/experimental/pydantic/object_type.py +20 -22
- strawberry/experimental/pydantic/utils.py +6 -10
- strawberry/ext/dataclasses/dataclasses.py +3 -3
- strawberry/ext/mypy_plugin.py +6 -9
- strawberry/extensions/__init__.py +7 -8
- strawberry/extensions/add_validation_rules.py +5 -3
- strawberry/extensions/base_extension.py +4 -4
- strawberry/extensions/context.py +15 -14
- strawberry/extensions/directives.py +2 -2
- strawberry/extensions/disable_validation.py +1 -1
- strawberry/extensions/field_extension.py +2 -1
- strawberry/extensions/mask_errors.py +3 -2
- strawberry/extensions/max_aliases.py +2 -2
- strawberry/extensions/max_tokens.py +1 -1
- strawberry/extensions/parser_cache.py +2 -1
- strawberry/extensions/pyinstrument.py +4 -1
- strawberry/extensions/query_depth_limiter.py +13 -13
- strawberry/extensions/runner.py +7 -7
- strawberry/extensions/tracing/apollo.py +11 -9
- strawberry/extensions/tracing/datadog.py +3 -1
- strawberry/extensions/tracing/opentelemetry.py +7 -10
- strawberry/extensions/utils.py +3 -3
- strawberry/extensions/validation_cache.py +2 -1
- strawberry/fastapi/context.py +3 -3
- strawberry/fastapi/router.py +9 -14
- strawberry/federation/__init__.py +4 -4
- strawberry/federation/argument.py +2 -1
- strawberry/federation/enum.py +8 -8
- strawberry/federation/field.py +25 -28
- strawberry/federation/object_type.py +24 -26
- strawberry/federation/scalar.py +7 -8
- strawberry/federation/schema.py +30 -36
- strawberry/federation/schema_directive.py +5 -5
- strawberry/federation/schema_directives.py +14 -14
- strawberry/federation/union.py +3 -2
- strawberry/field_extensions/input_mutation.py +1 -2
- strawberry/file_uploads/utils.py +4 -3
- strawberry/flask/views.py +3 -2
- strawberry/http/__init__.py +6 -6
- strawberry/http/async_base_view.py +9 -14
- strawberry/http/base.py +5 -4
- strawberry/http/ides.py +1 -1
- strawberry/http/parse_content_type.py +1 -2
- strawberry/http/sync_base_view.py +3 -5
- strawberry/http/temporal_response.py +1 -2
- strawberry/http/types.py +3 -2
- strawberry/litestar/controller.py +8 -14
- strawberry/parent.py +1 -2
- strawberry/permission.py +6 -8
- strawberry/printer/ast_from_value.py +2 -1
- strawberry/printer/printer.py +50 -30
- strawberry/quart/views.py +3 -3
- strawberry/relay/exceptions.py +4 -4
- strawberry/relay/fields.py +43 -63
- strawberry/relay/types.py +29 -27
- strawberry/relay/utils.py +4 -4
- strawberry/sanic/utils.py +4 -4
- strawberry/sanic/views.py +5 -7
- strawberry/scalars.py +2 -2
- strawberry/schema/base.py +16 -11
- strawberry/schema/compat.py +4 -4
- strawberry/schema/execute.py +6 -10
- strawberry/schema/name_converter.py +3 -3
- strawberry/schema/schema.py +37 -25
- strawberry/schema/schema_converter.py +22 -24
- strawberry/schema/subscribe.py +5 -4
- strawberry/schema/types/base_scalars.py +1 -1
- strawberry/schema/types/concrete_type.py +2 -2
- strawberry/schema/types/scalar.py +3 -4
- strawberry/schema_codegen/__init__.py +4 -4
- strawberry/schema_directive.py +8 -8
- strawberry/subscriptions/protocols/graphql_transport_ws/handlers.py +8 -9
- strawberry/subscriptions/protocols/graphql_transport_ws/types.py +16 -16
- strawberry/subscriptions/protocols/graphql_ws/handlers.py +6 -5
- strawberry/subscriptions/protocols/graphql_ws/types.py +13 -13
- strawberry/test/__init__.py +1 -1
- strawberry/test/client.py +21 -19
- strawberry/tools/create_type.py +4 -3
- strawberry/tools/merge_types.py +1 -2
- strawberry/types/__init__.py +1 -1
- strawberry/types/arguments.py +10 -12
- strawberry/types/auto.py +2 -2
- strawberry/types/base.py +17 -21
- strawberry/types/enum.py +3 -5
- strawberry/types/execution.py +8 -12
- strawberry/types/field.py +26 -31
- strawberry/types/fields/resolver.py +15 -17
- strawberry/types/graphql.py +2 -2
- strawberry/types/info.py +5 -9
- strawberry/types/lazy_type.py +3 -5
- strawberry/types/mutation.py +25 -28
- strawberry/types/nodes.py +11 -9
- strawberry/types/object_type.py +14 -16
- strawberry/types/private.py +1 -2
- strawberry/types/scalar.py +2 -2
- strawberry/types/type_resolver.py +5 -5
- strawberry/types/union.py +8 -11
- strawberry/types/unset.py +3 -3
- strawberry/utils/aio.py +3 -8
- strawberry/utils/await_maybe.py +3 -2
- strawberry/utils/debug.py +2 -2
- strawberry/utils/deprecations.py +2 -2
- strawberry/utils/inspect.py +3 -5
- strawberry/utils/str_converters.py +1 -1
- strawberry/utils/typing.py +38 -67
- {strawberry_graphql-0.254.1.dist-info → strawberry_graphql-0.256.0.dist-info}/METADATA +3 -6
- strawberry_graphql-0.256.0.dist-info/RECORD +236 -0
- strawberry_graphql-0.254.1.dist-info/RECORD +0 -236
- {strawberry_graphql-0.254.1.dist-info → strawberry_graphql-0.256.0.dist-info}/LICENSE +0 -0
- {strawberry_graphql-0.254.1.dist-info → strawberry_graphql-0.256.0.dist-info}/WHEEL +0 -0
- {strawberry_graphql-0.254.1.dist-info → strawberry_graphql-0.256.0.dist-info}/entry_points.txt +0 -0
strawberry/http/ides.py
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
from email.message import Message
|
2
|
-
from typing import Dict, Tuple
|
3
2
|
|
4
3
|
|
5
|
-
def parse_content_type(content_type: str) ->
|
4
|
+
def parse_content_type(content_type: str) -> tuple[str, dict[str, str]]:
|
6
5
|
"""Parse a content type header into a mime-type and a dictionary of parameters."""
|
7
6
|
email = Message()
|
8
7
|
email["content-type"] = content_type
|
@@ -1,12 +1,10 @@
|
|
1
1
|
import abc
|
2
2
|
import json
|
3
|
+
from collections.abc import Mapping
|
3
4
|
from typing import (
|
4
5
|
Any,
|
5
6
|
Callable,
|
6
|
-
Dict,
|
7
7
|
Generic,
|
8
|
-
List,
|
9
|
-
Mapping,
|
10
8
|
Optional,
|
11
9
|
Union,
|
12
10
|
)
|
@@ -126,7 +124,7 @@ class SyncBaseHTTPView(
|
|
126
124
|
allowed_operation_types=allowed_operation_types,
|
127
125
|
)
|
128
126
|
|
129
|
-
def parse_multipart(self, request: SyncHTTPRequestAdapter) ->
|
127
|
+
def parse_multipart(self, request: SyncHTTPRequestAdapter) -> dict[str, str]:
|
130
128
|
operations = self.parse_json(request.post_data.get("operations", "{}"))
|
131
129
|
files_map = self.parse_json(request.post_data.get("map", "{}"))
|
132
130
|
|
@@ -159,7 +157,7 @@ class SyncBaseHTTPView(
|
|
159
157
|
)
|
160
158
|
|
161
159
|
def _handle_errors(
|
162
|
-
self, errors:
|
160
|
+
self, errors: list[GraphQLError], response_data: GraphQLHTTPResponse
|
163
161
|
) -> None:
|
164
162
|
"""Hook to allow custom handling of errors, used by the Sentry Integration."""
|
165
163
|
|
@@ -1,11 +1,10 @@
|
|
1
1
|
from dataclasses import dataclass, field
|
2
|
-
from typing import Dict
|
3
2
|
|
4
3
|
|
5
4
|
@dataclass
|
6
5
|
class TemporalResponse:
|
7
6
|
status_code: int = 200
|
8
|
-
headers:
|
7
|
+
headers: dict[str, str] = field(default_factory=dict)
|
9
8
|
|
10
9
|
|
11
10
|
__all__ = ["TemporalResponse"]
|
strawberry/http/types.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
from
|
1
|
+
from collections.abc import Mapping
|
2
|
+
from typing import Any, Optional
|
2
3
|
from typing_extensions import Literal, TypedDict
|
3
4
|
|
4
5
|
HTTPMethod = Literal[
|
@@ -13,4 +14,4 @@ class FormData(TypedDict):
|
|
13
14
|
form: Mapping[str, Any]
|
14
15
|
|
15
16
|
|
16
|
-
__all__ = ["
|
17
|
+
__all__ = ["FormData", "HTTPMethod", "QueryParams"]
|
@@ -8,14 +8,8 @@ from datetime import timedelta
|
|
8
8
|
from typing import (
|
9
9
|
TYPE_CHECKING,
|
10
10
|
Any,
|
11
|
-
AsyncGenerator,
|
12
|
-
AsyncIterator,
|
13
11
|
Callable,
|
14
|
-
Dict,
|
15
|
-
FrozenSet,
|
16
12
|
Optional,
|
17
|
-
Tuple,
|
18
|
-
Type,
|
19
13
|
TypedDict,
|
20
14
|
Union,
|
21
15
|
cast,
|
@@ -60,7 +54,7 @@ from strawberry.http.typevars import Context, RootValue
|
|
60
54
|
from strawberry.subscriptions import GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL
|
61
55
|
|
62
56
|
if TYPE_CHECKING:
|
63
|
-
from collections.abc import Mapping
|
57
|
+
from collections.abc import AsyncGenerator, AsyncIterator, Mapping
|
64
58
|
|
65
59
|
from litestar.types import AnyCallable, Dependencies
|
66
60
|
from strawberry.http import GraphQLHTTPResponse
|
@@ -97,7 +91,7 @@ class WebSocketContextDict(TypedDict):
|
|
97
91
|
|
98
92
|
|
99
93
|
MergedContext = Union[
|
100
|
-
BaseContext, WebSocketContextDict, HTTPContextDict,
|
94
|
+
BaseContext, WebSocketContextDict, HTTPContextDict, dict[str, Any]
|
101
95
|
]
|
102
96
|
|
103
97
|
|
@@ -254,11 +248,11 @@ class GraphQLController(
|
|
254
248
|
websocket_adapter_class = LitestarWebSocketAdapter
|
255
249
|
|
256
250
|
allow_queries_via_get: bool = True
|
257
|
-
graphiql_allowed_accept:
|
251
|
+
graphiql_allowed_accept: frozenset[str] = frozenset({"text/html", "*/*"})
|
258
252
|
graphql_ide: Optional[GraphQL_IDE] = "graphiql"
|
259
253
|
debug: bool = False
|
260
254
|
connection_init_wait_timeout: timedelta = timedelta(minutes=1)
|
261
|
-
protocols:
|
255
|
+
protocols: tuple[str, ...] = (
|
262
256
|
GRAPHQL_TRANSPORT_WS_PROTOCOL,
|
263
257
|
GRAPHQL_WS_PROTOCOL,
|
264
258
|
)
|
@@ -329,7 +323,7 @@ class GraphQLController(
|
|
329
323
|
request: Request,
|
330
324
|
stream: Callable[[], AsyncIterator[str]],
|
331
325
|
sub_response: Response,
|
332
|
-
headers:
|
326
|
+
headers: dict[str, str],
|
333
327
|
) -> Response:
|
334
328
|
return Stream(
|
335
329
|
stream(),
|
@@ -416,13 +410,13 @@ def make_graphql_controller(
|
|
416
410
|
root_value_getter: Optional[AnyCallable] = None,
|
417
411
|
# TODO: context typevar
|
418
412
|
context_getter: Optional[AnyCallable] = None,
|
419
|
-
subscription_protocols:
|
413
|
+
subscription_protocols: tuple[str, ...] = (
|
420
414
|
GRAPHQL_TRANSPORT_WS_PROTOCOL,
|
421
415
|
GRAPHQL_WS_PROTOCOL,
|
422
416
|
),
|
423
417
|
connection_init_wait_timeout: timedelta = timedelta(minutes=1),
|
424
418
|
multipart_uploads_enabled: bool = False,
|
425
|
-
) ->
|
419
|
+
) -> type[GraphQLController]: # sourcery skip: move-assign
|
426
420
|
if context_getter is None:
|
427
421
|
custom_context_getter_ = _none_custom_context_getter
|
428
422
|
else:
|
@@ -474,6 +468,6 @@ def make_graphql_controller(
|
|
474
468
|
|
475
469
|
|
476
470
|
__all__ = [
|
477
|
-
"make_graphql_controller",
|
478
471
|
"GraphQLController",
|
472
|
+
"make_graphql_controller",
|
479
473
|
]
|
strawberry/parent.py
CHANGED
strawberry/permission.py
CHANGED
@@ -7,11 +7,7 @@ from inspect import iscoroutinefunction
|
|
7
7
|
from typing import (
|
8
8
|
TYPE_CHECKING,
|
9
9
|
Any,
|
10
|
-
Awaitable,
|
11
|
-
Dict,
|
12
|
-
List,
|
13
10
|
Optional,
|
14
|
-
Type,
|
15
11
|
Union,
|
16
12
|
)
|
17
13
|
|
@@ -25,6 +21,8 @@ from strawberry.types.base import StrawberryList, StrawberryOptional
|
|
25
21
|
from strawberry.utils.await_maybe import await_maybe
|
26
22
|
|
27
23
|
if TYPE_CHECKING:
|
24
|
+
from collections.abc import Awaitable
|
25
|
+
|
28
26
|
from graphql import GraphQLError, GraphQLErrorExtensions
|
29
27
|
|
30
28
|
from strawberry.extensions.field_extension import (
|
@@ -56,7 +54,7 @@ class BasePermission(abc.ABC):
|
|
56
54
|
|
57
55
|
error_extensions: Optional[GraphQLErrorExtensions] = None
|
58
56
|
|
59
|
-
error_class:
|
57
|
+
error_class: type[GraphQLError] = StrawberryGraphQLError
|
60
58
|
|
61
59
|
_schema_directive: Optional[object] = None
|
62
60
|
|
@@ -138,7 +136,7 @@ class PermissionExtension(FieldExtension):
|
|
138
136
|
|
139
137
|
def __init__(
|
140
138
|
self,
|
141
|
-
permissions:
|
139
|
+
permissions: list[BasePermission],
|
142
140
|
use_directives: bool = True,
|
143
141
|
fail_silently: bool = False,
|
144
142
|
) -> None:
|
@@ -189,7 +187,7 @@ class PermissionExtension(FieldExtension):
|
|
189
187
|
next_: SyncExtensionResolver,
|
190
188
|
source: Any,
|
191
189
|
info: Info,
|
192
|
-
**kwargs:
|
190
|
+
**kwargs: dict[str, Any],
|
193
191
|
) -> Any:
|
194
192
|
"""Checks if the permission should be accepted and raises an exception if not."""
|
195
193
|
for permission in self.permissions:
|
@@ -202,7 +200,7 @@ class PermissionExtension(FieldExtension):
|
|
202
200
|
next_: AsyncExtensionResolver,
|
203
201
|
source: Any,
|
204
202
|
info: Info,
|
205
|
-
**kwargs:
|
203
|
+
**kwargs: dict[str, Any],
|
206
204
|
) -> Any:
|
207
205
|
for permission in self.permissions:
|
208
206
|
has_permission = await await_maybe(
|
@@ -1,8 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import re
|
4
|
+
from collections.abc import Mapping
|
4
5
|
from math import isfinite
|
5
|
-
from typing import TYPE_CHECKING, Any,
|
6
|
+
from typing import TYPE_CHECKING, Any, Optional, cast
|
6
7
|
|
7
8
|
from graphql.language import (
|
8
9
|
BooleanValueNode,
|
strawberry/printer/printer.py
CHANGED
@@ -5,19 +5,14 @@ from itertools import chain
|
|
5
5
|
from typing import (
|
6
6
|
TYPE_CHECKING,
|
7
7
|
Any,
|
8
|
-
Dict,
|
9
|
-
List,
|
10
8
|
Optional,
|
11
|
-
Set,
|
12
|
-
Tuple,
|
13
|
-
Type,
|
14
9
|
TypeVar,
|
15
10
|
Union,
|
16
11
|
cast,
|
17
12
|
overload,
|
18
13
|
)
|
19
14
|
|
20
|
-
from graphql import is_union_type
|
15
|
+
from graphql import GraphQLObjectType, GraphQLSchema, is_union_type
|
21
16
|
from graphql.language.printer import print_ast
|
22
17
|
from graphql.type import (
|
23
18
|
is_enum_type,
|
@@ -38,7 +33,11 @@ from graphql.utilities.print_schema import (
|
|
38
33
|
from graphql.utilities.print_schema import print_type as original_print_type
|
39
34
|
|
40
35
|
from strawberry.schema_directive import Location, StrawberrySchemaDirective
|
41
|
-
from strawberry.types.base import
|
36
|
+
from strawberry.types.base import (
|
37
|
+
StrawberryContainer,
|
38
|
+
StrawberryObjectDefinition,
|
39
|
+
has_object_definition,
|
40
|
+
)
|
42
41
|
from strawberry.types.enum import EnumDefinition
|
43
42
|
from strawberry.types.scalar import ScalarWrapper
|
44
43
|
from strawberry.types.unset import UNSET
|
@@ -64,18 +63,18 @@ _T = TypeVar("_T")
|
|
64
63
|
|
65
64
|
@dataclasses.dataclass
|
66
65
|
class PrintExtras:
|
67
|
-
directives:
|
68
|
-
types:
|
66
|
+
directives: set[str] = dataclasses.field(default_factory=set)
|
67
|
+
types: set[type] = dataclasses.field(default_factory=set)
|
69
68
|
|
70
69
|
|
71
70
|
@overload
|
72
|
-
def _serialize_dataclasses(value:
|
71
|
+
def _serialize_dataclasses(value: dict[_T, object]) -> dict[_T, object]: ...
|
73
72
|
|
74
73
|
|
75
74
|
@overload
|
76
75
|
def _serialize_dataclasses(
|
77
|
-
value: Union[
|
78
|
-
) ->
|
76
|
+
value: Union[list[object], tuple[object]],
|
77
|
+
) -> list[object]: ...
|
79
78
|
|
80
79
|
|
81
80
|
@overload
|
@@ -94,7 +93,7 @@ def _serialize_dataclasses(value):
|
|
94
93
|
|
95
94
|
|
96
95
|
def print_schema_directive_params(
|
97
|
-
directive: GraphQLDirective, values:
|
96
|
+
directive: GraphQLDirective, values: dict[str, Any]
|
98
97
|
) -> str:
|
99
98
|
params = []
|
100
99
|
for name, arg in directive.args.items():
|
@@ -189,7 +188,7 @@ def print_argument_directives(
|
|
189
188
|
|
190
189
|
|
191
190
|
def print_args(
|
192
|
-
args:
|
191
|
+
args: dict[str, GraphQLArgument],
|
193
192
|
indentation: str = "",
|
194
193
|
*,
|
195
194
|
schema: BaseSchema,
|
@@ -225,7 +224,12 @@ def print_args(
|
|
225
224
|
)
|
226
225
|
|
227
226
|
|
228
|
-
def print_fields(
|
227
|
+
def print_fields(
|
228
|
+
type_: GraphQLObjectType,
|
229
|
+
schema: BaseSchema,
|
230
|
+
*,
|
231
|
+
extras: PrintExtras,
|
232
|
+
) -> str:
|
229
233
|
from strawberry.schema.schema_converter import GraphQLCoreConverter
|
230
234
|
|
231
235
|
fields = []
|
@@ -320,11 +324,13 @@ def print_enum(
|
|
320
324
|
)
|
321
325
|
|
322
326
|
|
323
|
-
def print_extends(type_:
|
327
|
+
def print_extends(type_: GraphQLObjectType, schema: BaseSchema) -> str:
|
324
328
|
from strawberry.schema.schema_converter import GraphQLCoreConverter
|
325
329
|
|
326
|
-
strawberry_type =
|
327
|
-
|
330
|
+
strawberry_type = cast(
|
331
|
+
Optional[StrawberryObjectDefinition],
|
332
|
+
type_.extensions
|
333
|
+
and type_.extensions.get(GraphQLCoreConverter.DEFINITION_BACKREF),
|
328
334
|
)
|
329
335
|
|
330
336
|
if strawberry_type and strawberry_type.extend:
|
@@ -334,12 +340,14 @@ def print_extends(type_: Type, schema: BaseSchema) -> str:
|
|
334
340
|
|
335
341
|
|
336
342
|
def print_type_directives(
|
337
|
-
type_:
|
343
|
+
type_: GraphQLObjectType, schema: BaseSchema, *, extras: PrintExtras
|
338
344
|
) -> str:
|
339
345
|
from strawberry.schema.schema_converter import GraphQLCoreConverter
|
340
346
|
|
341
|
-
strawberry_type =
|
342
|
-
|
347
|
+
strawberry_type = cast(
|
348
|
+
Optional[StrawberryObjectDefinition],
|
349
|
+
type_.extensions
|
350
|
+
and type_.extensions.get(GraphQLCoreConverter.DEFINITION_BACKREF),
|
343
351
|
)
|
344
352
|
|
345
353
|
if not strawberry_type:
|
@@ -354,7 +362,7 @@ def print_type_directives(
|
|
354
362
|
for directive in strawberry_type.directives or []
|
355
363
|
if any(
|
356
364
|
location in allowed_locations
|
357
|
-
for location in directive.__strawberry_directive__.locations
|
365
|
+
for location in directive.__strawberry_directive__.locations # type: ignore[attr-defined]
|
358
366
|
)
|
359
367
|
)
|
360
368
|
|
@@ -550,21 +558,33 @@ def is_builtin_directive(directive: GraphQLDirective) -> bool:
|
|
550
558
|
|
551
559
|
|
552
560
|
def print_schema(schema: BaseSchema) -> str:
|
553
|
-
graphql_core_schema =
|
561
|
+
graphql_core_schema = cast(
|
562
|
+
GraphQLSchema,
|
563
|
+
schema._schema, # type: ignore
|
564
|
+
)
|
554
565
|
extras = PrintExtras()
|
555
566
|
|
556
|
-
|
557
|
-
|
558
|
-
|
567
|
+
filtered_directives = [
|
568
|
+
directive
|
569
|
+
for directive in graphql_core_schema.directives
|
570
|
+
if not is_builtin_directive(directive)
|
571
|
+
]
|
572
|
+
|
559
573
|
type_map = graphql_core_schema.type_map
|
560
|
-
types =
|
574
|
+
types = [
|
575
|
+
type_
|
576
|
+
for type_name in sorted(type_map)
|
577
|
+
if is_defined_type(type_ := type_map[type_name])
|
578
|
+
]
|
561
579
|
|
562
580
|
types_printed = [_print_type(type_, schema, extras=extras) for type_ in types]
|
563
581
|
schema_definition = print_schema_definition(schema, extras=extras)
|
564
582
|
|
565
|
-
directives =
|
566
|
-
|
567
|
-
|
583
|
+
directives = [
|
584
|
+
printed_directive
|
585
|
+
for directive in filtered_directives
|
586
|
+
if (printed_directive := print_directive(directive, schema=schema)) is not None
|
587
|
+
]
|
568
588
|
|
569
589
|
def _name_getter(type_: Any) -> str:
|
570
590
|
if hasattr(type_, "name"):
|
strawberry/quart/views.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import warnings
|
2
|
-
from collections.abc import Mapping
|
3
|
-
from typing import TYPE_CHECKING,
|
2
|
+
from collections.abc import AsyncGenerator, Mapping
|
3
|
+
from typing import TYPE_CHECKING, Callable, Optional, cast
|
4
4
|
from typing_extensions import TypeGuard
|
5
5
|
|
6
6
|
from quart import Request, Response, request
|
@@ -111,7 +111,7 @@ class GraphQLView(
|
|
111
111
|
request: Request,
|
112
112
|
stream: Callable[[], AsyncGenerator[str, None]],
|
113
113
|
sub_response: Response,
|
114
|
-
headers:
|
114
|
+
headers: dict[str, str],
|
115
115
|
) -> Response:
|
116
116
|
return (
|
117
117
|
stream(),
|
strawberry/relay/exceptions.py
CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
from collections.abc import Callable
|
4
4
|
from functools import cached_property
|
5
|
-
from typing import TYPE_CHECKING, Optional,
|
5
|
+
from typing import TYPE_CHECKING, Optional, cast
|
6
6
|
|
7
7
|
from strawberry.exceptions.exception import StrawberryException
|
8
8
|
from strawberry.exceptions.utils.source_finder import SourceFinder
|
@@ -13,7 +13,7 @@ if TYPE_CHECKING:
|
|
13
13
|
|
14
14
|
|
15
15
|
class NodeIDAnnotationError(StrawberryException):
|
16
|
-
def __init__(self, message: str, cls:
|
16
|
+
def __init__(self, message: str, cls: type) -> None:
|
17
17
|
self.cls = cls
|
18
18
|
|
19
19
|
self.message = message
|
@@ -41,7 +41,7 @@ class NodeIDAnnotationError(StrawberryException):
|
|
41
41
|
|
42
42
|
|
43
43
|
class RelayWrongAnnotationError(StrawberryException):
|
44
|
-
def __init__(self, field_name: str, cls:
|
44
|
+
def __init__(self, field_name: str, cls: type) -> None:
|
45
45
|
self.cls = cls
|
46
46
|
self.field_name = field_name
|
47
47
|
|
@@ -85,7 +85,7 @@ class RelayWrongResolverAnnotationError(StrawberryException):
|
|
85
85
|
)
|
86
86
|
self.suggestion = (
|
87
87
|
"To fix this error you can annootate your resolver to return "
|
88
|
-
"one of the following options: `
|
88
|
+
"one of the following options: `list[<NodeType>]`, "
|
89
89
|
"`Iterator[<NodeType>]`, `Iterable[<NodeType>]`, "
|
90
90
|
"`AsyncIterator[<NodeType>]`, `AsyncIterable[<NodeType>]`, "
|
91
91
|
"`Generator[<NodeType>, Any, Any]` and "
|
strawberry/relay/fields.py
CHANGED
@@ -4,29 +4,26 @@ import asyncio
|
|
4
4
|
import dataclasses
|
5
5
|
import inspect
|
6
6
|
from collections import defaultdict
|
7
|
-
from collections.abc import
|
8
|
-
|
9
|
-
TYPE_CHECKING,
|
10
|
-
Any,
|
7
|
+
from collections.abc import (
|
8
|
+
AsyncIterable,
|
11
9
|
AsyncIterator,
|
12
10
|
Awaitable,
|
13
|
-
Callable,
|
14
|
-
DefaultDict,
|
15
|
-
Dict,
|
16
|
-
ForwardRef,
|
17
11
|
Iterable,
|
18
12
|
Iterator,
|
19
|
-
List,
|
20
13
|
Mapping,
|
21
|
-
Optional,
|
22
14
|
Sequence,
|
23
|
-
|
24
|
-
|
15
|
+
)
|
16
|
+
from typing import (
|
17
|
+
TYPE_CHECKING,
|
18
|
+
Annotated,
|
19
|
+
Any,
|
20
|
+
Callable,
|
21
|
+
ForwardRef,
|
22
|
+
Optional,
|
25
23
|
Union,
|
26
24
|
cast,
|
27
|
-
overload,
|
28
25
|
)
|
29
|
-
from typing_extensions import
|
26
|
+
from typing_extensions import get_args, get_origin
|
30
27
|
|
31
28
|
from strawberry.annotation import StrawberryAnnotation
|
32
29
|
from strawberry.extensions.field_extension import (
|
@@ -44,9 +41,9 @@ from strawberry.types.field import _RESOLVER_TYPE, StrawberryField, field
|
|
44
41
|
from strawberry.types.fields.resolver import StrawberryResolver
|
45
42
|
from strawberry.types.lazy_type import LazyType
|
46
43
|
from strawberry.utils.aio import asyncgen_to_list
|
47
|
-
from strawberry.utils.typing import eval_type, is_generic_alias
|
44
|
+
from strawberry.utils.typing import eval_type, is_generic_alias, is_optional, is_union
|
48
45
|
|
49
|
-
from .types import Connection, GlobalID, Node
|
46
|
+
from .types import Connection, GlobalID, Node
|
50
47
|
|
51
48
|
if TYPE_CHECKING:
|
52
49
|
from typing_extensions import Literal
|
@@ -101,7 +98,7 @@ class NodeExtension(FieldExtension):
|
|
101
98
|
|
102
99
|
def get_node_list_resolver(
|
103
100
|
self, field: StrawberryField
|
104
|
-
) -> Callable[[Info,
|
101
|
+
) -> Callable[[Info, list[GlobalID]], Union[list[Node], Awaitable[list[Node]]]]:
|
105
102
|
type_ = field.type
|
106
103
|
assert isinstance(type_, StrawberryList)
|
107
104
|
is_optional = isinstance(type_.of_type, StrawberryOptional)
|
@@ -109,14 +106,14 @@ class NodeExtension(FieldExtension):
|
|
109
106
|
def resolver(
|
110
107
|
info: Info,
|
111
108
|
ids: Annotated[
|
112
|
-
|
109
|
+
list[GlobalID], argument(description="The IDs of the objects.")
|
113
110
|
],
|
114
|
-
) -> Union[
|
115
|
-
nodes_map:
|
111
|
+
) -> Union[list[Node], Awaitable[list[Node]]]:
|
112
|
+
nodes_map: defaultdict[type[Node], list[str]] = defaultdict(list)
|
116
113
|
# Store the index of the node in the list of nodes of the same type
|
117
114
|
# so that we can return them in the same order while also supporting
|
118
115
|
# different types
|
119
|
-
index_map:
|
116
|
+
index_map: dict[GlobalID, tuple[type[Node], int]] = {}
|
120
117
|
for gid in ids:
|
121
118
|
node_t = gid.resolve_type(info)
|
122
119
|
nodes_map[node_t].append(gid.node_id)
|
@@ -144,7 +141,7 @@ class NodeExtension(FieldExtension):
|
|
144
141
|
|
145
142
|
if awaitable_nodes or asyncgen_nodes:
|
146
143
|
|
147
|
-
async def resolve(resolved: Any = resolved_nodes) ->
|
144
|
+
async def resolve(resolved: Any = resolved_nodes) -> list[Node]:
|
148
145
|
resolved.update(
|
149
146
|
zip(
|
150
147
|
[
|
@@ -183,7 +180,7 @@ class NodeExtension(FieldExtension):
|
|
183
180
|
|
184
181
|
|
185
182
|
class ConnectionExtension(FieldExtension):
|
186
|
-
connection_type:
|
183
|
+
connection_type: type[Connection[Node]]
|
187
184
|
|
188
185
|
def apply(self, field: StrawberryField) -> None:
|
189
186
|
field.arguments = [
|
@@ -233,7 +230,11 @@ class ConnectionExtension(FieldExtension):
|
|
233
230
|
f_type = f_type.resolve_type()
|
234
231
|
field.type = f_type
|
235
232
|
|
233
|
+
if isinstance(f_type, StrawberryOptional):
|
234
|
+
f_type = f_type.of_type
|
235
|
+
|
236
236
|
type_origin = get_origin(f_type) if is_generic_alias(f_type) else f_type
|
237
|
+
|
237
238
|
if not isinstance(type_origin, type) or not issubclass(type_origin, Connection):
|
238
239
|
raise RelayWrongAnnotationError(field.name, cast(type, field.origin))
|
239
240
|
|
@@ -253,13 +254,19 @@ class ConnectionExtension(FieldExtension):
|
|
253
254
|
None,
|
254
255
|
)
|
255
256
|
|
257
|
+
if is_union(resolver_type):
|
258
|
+
assert is_optional(resolver_type)
|
259
|
+
|
260
|
+
resolver_type = get_args(resolver_type)[0]
|
261
|
+
|
256
262
|
origin = get_origin(resolver_type)
|
263
|
+
|
257
264
|
if origin is None or not issubclass(
|
258
265
|
origin, (Iterator, Iterable, AsyncIterator, AsyncIterable)
|
259
266
|
):
|
260
267
|
raise RelayWrongResolverAnnotationError(field.name, field.base_resolver)
|
261
268
|
|
262
|
-
self.connection_type = cast(
|
269
|
+
self.connection_type = cast(type[Connection[Node]], f_type)
|
263
270
|
|
264
271
|
def resolve(
|
265
272
|
self,
|
@@ -327,59 +334,32 @@ else:
|
|
327
334
|
return field(*args, **kwargs)
|
328
335
|
|
329
336
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
description: Optional[str] = None,
|
338
|
-
init: Literal[True] = True,
|
339
|
-
permission_classes: Optional[List[Type[BasePermission]]] = None,
|
340
|
-
deprecation_reason: Optional[str] = None,
|
341
|
-
default: Any = dataclasses.MISSING,
|
342
|
-
default_factory: Union[Callable[..., object], object] = dataclasses.MISSING,
|
343
|
-
metadata: Optional[Mapping[Any, Any]] = None,
|
344
|
-
directives: Optional[Sequence[object]] = (),
|
345
|
-
extensions: List[FieldExtension] = (), # type: ignore
|
346
|
-
) -> Any: ...
|
347
|
-
|
348
|
-
|
349
|
-
@overload
|
350
|
-
def connection(
|
351
|
-
graphql_type: Optional[Type[Connection[NodeType]]] = None,
|
352
|
-
*,
|
353
|
-
name: Optional[str] = None,
|
354
|
-
is_subscription: bool = False,
|
355
|
-
description: Optional[str] = None,
|
356
|
-
permission_classes: Optional[List[Type[BasePermission]]] = None,
|
357
|
-
deprecation_reason: Optional[str] = None,
|
358
|
-
default: Any = dataclasses.MISSING,
|
359
|
-
default_factory: Union[Callable[..., object], object] = dataclasses.MISSING,
|
360
|
-
metadata: Optional[Mapping[Any, Any]] = None,
|
361
|
-
directives: Optional[Sequence[object]] = (),
|
362
|
-
extensions: List[FieldExtension] = (), # type: ignore
|
363
|
-
) -> StrawberryField: ...
|
337
|
+
# we used to have `Type[Connection[NodeType]]` here, but that when we added
|
338
|
+
# support for making the Connection type optional, we had to change it to
|
339
|
+
# `Any` because otherwise it wouldn't be type check since `Optional[Connection[Something]]`
|
340
|
+
# is not a `Type`, but a special form, see https://discuss.python.org/t/is-annotated-compatible-with-type-t/43898/46
|
341
|
+
# for more information, and also https://peps.python.org/pep-0747/, which is currently
|
342
|
+
# in draft status (and no type checker supports it yet)
|
343
|
+
ConnectionGraphQLType = Any
|
364
344
|
|
365
345
|
|
366
346
|
def connection(
|
367
|
-
graphql_type: Optional[
|
347
|
+
graphql_type: Optional[ConnectionGraphQLType] = None,
|
368
348
|
*,
|
369
349
|
resolver: Optional[_RESOLVER_TYPE[Any]] = None,
|
370
350
|
name: Optional[str] = None,
|
371
351
|
is_subscription: bool = False,
|
372
352
|
description: Optional[str] = None,
|
373
|
-
permission_classes: Optional[
|
353
|
+
permission_classes: Optional[list[type[BasePermission]]] = None,
|
374
354
|
deprecation_reason: Optional[str] = None,
|
375
355
|
default: Any = dataclasses.MISSING,
|
376
356
|
default_factory: Union[Callable[..., object], object] = dataclasses.MISSING,
|
377
357
|
metadata: Optional[Mapping[Any, Any]] = None,
|
378
358
|
directives: Optional[Sequence[object]] = (),
|
379
|
-
extensions:
|
359
|
+
extensions: list[FieldExtension] = (), # type: ignore
|
380
360
|
# This init parameter is used by pyright to determine whether this field
|
381
361
|
# is added in the constructor or not. It is not used to change
|
382
|
-
# any
|
362
|
+
# any behaviour at the moment.
|
383
363
|
init: Literal[True, False, None] = None,
|
384
364
|
) -> Any:
|
385
365
|
"""Annotate a property or a method to create a relay connection field.
|
@@ -478,4 +458,4 @@ def connection(
|
|
478
458
|
return f
|
479
459
|
|
480
460
|
|
481
|
-
__all__ = ["
|
461
|
+
__all__ = ["connection", "node"]
|