strawberry-graphql 0.275.7__py3-none-any.whl → 0.284.3__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.
Potentially problematic release.
This version of strawberry-graphql might be problematic. Click here for more details.
- strawberry/__init__.py +2 -0
- strawberry/aiohttp/test/client.py +8 -15
- strawberry/aiohttp/views.py +15 -64
- strawberry/annotation.py +70 -25
- strawberry/asgi/__init__.py +22 -56
- strawberry/asgi/test/client.py +6 -6
- strawberry/chalice/views.py +13 -79
- strawberry/channels/handlers/base.py +7 -8
- strawberry/channels/handlers/http_handler.py +50 -32
- strawberry/channels/handlers/ws_handler.py +12 -14
- strawberry/channels/router.py +3 -4
- strawberry/channels/testing.py +7 -9
- strawberry/cli/__init__.py +7 -6
- strawberry/cli/commands/codegen.py +7 -7
- strawberry/cli/commands/dev.py +72 -0
- strawberry/cli/commands/schema_codegen.py +1 -2
- strawberry/cli/commands/server.py +3 -44
- strawberry/cli/commands/upgrade/__init__.py +3 -3
- strawberry/cli/commands/upgrade/_run_codemod.py +2 -2
- strawberry/cli/constants.py +1 -2
- strawberry/cli/{debug_server.py → dev_server.py} +3 -7
- strawberry/codegen/plugins/print_operation.py +2 -2
- strawberry/codegen/plugins/python.py +2 -2
- strawberry/codegen/query_codegen.py +20 -30
- strawberry/codegen/types.py +32 -32
- strawberry/codemods/__init__.py +9 -0
- strawberry/codemods/annotated_unions.py +2 -2
- strawberry/codemods/maybe_optional.py +118 -0
- strawberry/dataloader.py +28 -24
- strawberry/directive.py +6 -7
- strawberry/django/test/client.py +3 -3
- strawberry/django/views.py +21 -91
- strawberry/exceptions/__init__.py +4 -4
- strawberry/exceptions/conflicting_arguments.py +2 -2
- strawberry/exceptions/duplicated_type_name.py +4 -4
- strawberry/exceptions/exception.py +3 -3
- strawberry/exceptions/handler.py +8 -7
- strawberry/exceptions/invalid_argument_type.py +2 -2
- strawberry/exceptions/invalid_superclass_interface.py +2 -2
- strawberry/exceptions/invalid_union_type.py +4 -4
- strawberry/exceptions/missing_arguments_annotations.py +2 -2
- strawberry/exceptions/missing_dependencies.py +2 -4
- strawberry/exceptions/missing_field_annotation.py +2 -2
- strawberry/exceptions/missing_return_annotation.py +2 -2
- strawberry/exceptions/object_is_not_a_class.py +2 -2
- strawberry/exceptions/object_is_not_an_enum.py +2 -2
- strawberry/exceptions/permission_fail_silently_requires_optional.py +2 -2
- strawberry/exceptions/private_strawberry_field.py +2 -2
- strawberry/exceptions/scalar_already_registered.py +2 -2
- strawberry/exceptions/syntax.py +3 -3
- strawberry/exceptions/unresolved_field_type.py +2 -2
- strawberry/exceptions/utils/source_finder.py +25 -25
- strawberry/experimental/pydantic/_compat.py +8 -7
- strawberry/experimental/pydantic/conversion.py +2 -2
- strawberry/experimental/pydantic/conversion_types.py +2 -2
- strawberry/experimental/pydantic/error_type.py +10 -12
- strawberry/experimental/pydantic/fields.py +9 -15
- strawberry/experimental/pydantic/object_type.py +17 -25
- strawberry/experimental/pydantic/utils.py +1 -2
- strawberry/ext/mypy_plugin.py +12 -14
- strawberry/extensions/base_extension.py +2 -1
- strawberry/extensions/context.py +13 -18
- strawberry/extensions/directives.py +9 -3
- strawberry/extensions/field_extension.py +4 -4
- strawberry/extensions/mask_errors.py +24 -13
- strawberry/extensions/max_aliases.py +1 -3
- strawberry/extensions/parser_cache.py +1 -2
- strawberry/extensions/query_depth_limiter.py +18 -14
- strawberry/extensions/runner.py +2 -2
- strawberry/extensions/tracing/apollo.py +3 -3
- strawberry/extensions/tracing/datadog.py +3 -3
- strawberry/extensions/tracing/opentelemetry.py +6 -8
- strawberry/extensions/tracing/utils.py +3 -1
- strawberry/extensions/utils.py +2 -2
- strawberry/extensions/validation_cache.py +2 -3
- strawberry/fastapi/context.py +6 -6
- strawberry/fastapi/router.py +43 -42
- strawberry/federation/argument.py +4 -5
- strawberry/federation/enum.py +18 -21
- strawberry/federation/field.py +94 -97
- strawberry/federation/object_type.py +56 -58
- strawberry/federation/scalar.py +27 -35
- strawberry/federation/schema.py +15 -16
- strawberry/federation/schema_directive.py +7 -6
- strawberry/federation/schema_directives.py +11 -11
- strawberry/federation/union.py +4 -4
- strawberry/flask/views.py +16 -85
- strawberry/http/__init__.py +30 -20
- strawberry/http/async_base_view.py +208 -89
- strawberry/http/base.py +28 -11
- strawberry/http/exceptions.py +5 -7
- strawberry/http/ides.py +2 -3
- strawberry/http/sync_base_view.py +115 -69
- strawberry/http/types.py +3 -3
- strawberry/litestar/controller.py +43 -77
- strawberry/permission.py +4 -6
- strawberry/printer/ast_from_value.py +3 -5
- strawberry/printer/printer.py +18 -15
- strawberry/quart/views.py +16 -48
- strawberry/relay/exceptions.py +4 -4
- strawberry/relay/fields.py +33 -32
- strawberry/relay/types.py +32 -35
- strawberry/relay/utils.py +11 -23
- strawberry/resolvers.py +2 -1
- strawberry/sanic/context.py +1 -0
- strawberry/sanic/utils.py +3 -3
- strawberry/sanic/views.py +15 -54
- strawberry/scalars.py +2 -2
- strawberry/schema/_graphql_core.py +55 -0
- strawberry/schema/base.py +32 -33
- strawberry/schema/compat.py +9 -9
- strawberry/schema/config.py +10 -1
- strawberry/schema/exceptions.py +1 -3
- strawberry/schema/name_converter.py +9 -8
- strawberry/schema/schema.py +133 -100
- strawberry/schema/schema_converter.py +96 -58
- strawberry/schema/types/base_scalars.py +1 -1
- strawberry/schema/types/concrete_type.py +5 -5
- strawberry/schema/validation_rules/maybe_null.py +136 -0
- strawberry/schema_codegen/__init__.py +3 -3
- strawberry/schema_directive.py +7 -6
- strawberry/static/graphiql.html +5 -5
- strawberry/streamable.py +35 -0
- strawberry/subscriptions/protocols/graphql_transport_ws/handlers.py +5 -16
- strawberry/subscriptions/protocols/graphql_transport_ws/types.py +20 -20
- strawberry/subscriptions/protocols/graphql_ws/handlers.py +5 -12
- strawberry/subscriptions/protocols/graphql_ws/types.py +14 -14
- strawberry/test/client.py +18 -18
- strawberry/tools/create_type.py +2 -3
- strawberry/types/arguments.py +41 -28
- strawberry/types/auto.py +3 -4
- strawberry/types/base.py +25 -27
- strawberry/types/enum.py +22 -25
- strawberry/types/execution.py +21 -16
- strawberry/types/field.py +109 -130
- strawberry/types/fields/resolver.py +19 -21
- strawberry/types/info.py +5 -11
- strawberry/types/lazy_type.py +2 -3
- strawberry/types/maybe.py +12 -3
- strawberry/types/mutation.py +115 -118
- strawberry/types/nodes.py +2 -2
- strawberry/types/object_type.py +43 -63
- strawberry/types/scalar.py +37 -43
- strawberry/types/union.py +12 -14
- strawberry/utils/aio.py +12 -9
- strawberry/utils/await_maybe.py +3 -3
- strawberry/utils/deprecations.py +2 -2
- strawberry/utils/importer.py +1 -2
- strawberry/utils/inspect.py +4 -6
- strawberry/utils/logging.py +2 -2
- strawberry/utils/operation.py +4 -4
- strawberry/utils/typing.py +18 -83
- {strawberry_graphql-0.275.7.dist-info → strawberry_graphql-0.284.3.dist-info}/METADATA +14 -8
- strawberry_graphql-0.284.3.dist-info/RECORD +243 -0
- {strawberry_graphql-0.275.7.dist-info → strawberry_graphql-0.284.3.dist-info}/WHEEL +1 -1
- strawberry/utils/dataclasses.py +0 -37
- strawberry/utils/debug.py +0 -46
- strawberry/utils/graphql_lexer.py +0 -35
- strawberry_graphql-0.275.7.dist-info/RECORD +0 -241
- {strawberry_graphql-0.275.7.dist-info → strawberry_graphql-0.284.3.dist-info}/entry_points.txt +0 -0
- {strawberry_graphql-0.275.7.dist-info → strawberry_graphql-0.284.3.dist-info/licenses}/LICENSE +0 -0
|
@@ -6,7 +6,6 @@ import warnings
|
|
|
6
6
|
from typing import (
|
|
7
7
|
TYPE_CHECKING,
|
|
8
8
|
Any,
|
|
9
|
-
Callable,
|
|
10
9
|
Optional,
|
|
11
10
|
cast,
|
|
12
11
|
)
|
|
@@ -36,7 +35,7 @@ from strawberry.types.type_resolver import _get_fields
|
|
|
36
35
|
|
|
37
36
|
if TYPE_CHECKING:
|
|
38
37
|
import builtins
|
|
39
|
-
from collections.abc import Sequence
|
|
38
|
+
from collections.abc import Callable, Sequence
|
|
40
39
|
|
|
41
40
|
from graphql import GraphQLResolveInfo
|
|
42
41
|
|
|
@@ -50,7 +49,7 @@ def get_type_for_field(field: CompatModelField, is_input: bool, compat: Pydantic
|
|
|
50
49
|
# only pydantic v1 has this Optional logic
|
|
51
50
|
should_add_optional: bool = field.allow_none
|
|
52
51
|
if should_add_optional:
|
|
53
|
-
return Optional[replaced_type]
|
|
52
|
+
return Optional[replaced_type] # noqa: UP045
|
|
54
53
|
|
|
55
54
|
return replaced_type
|
|
56
55
|
|
|
@@ -116,20 +115,20 @@ if TYPE_CHECKING:
|
|
|
116
115
|
)
|
|
117
116
|
|
|
118
117
|
|
|
119
|
-
def type(
|
|
118
|
+
def type(
|
|
120
119
|
model: builtins.type[PydanticModel],
|
|
121
120
|
*,
|
|
122
|
-
fields:
|
|
123
|
-
name:
|
|
121
|
+
fields: list[str] | None = None,
|
|
122
|
+
name: str | None = None,
|
|
124
123
|
is_input: bool = False,
|
|
125
124
|
is_interface: bool = False,
|
|
126
|
-
description:
|
|
127
|
-
directives:
|
|
125
|
+
description: str | None = None,
|
|
126
|
+
directives: Sequence[object] | None = (),
|
|
128
127
|
all_fields: bool = False,
|
|
129
128
|
include_computed: bool = False,
|
|
130
129
|
use_pydantic_alias: bool = True,
|
|
131
130
|
) -> Callable[..., builtins.type[StrawberryTypeFromPydantic[PydanticModel]]]:
|
|
132
|
-
def wrap(cls: Any) -> builtins.type[StrawberryTypeFromPydantic[PydanticModel]]:
|
|
131
|
+
def wrap(cls: Any) -> builtins.type[StrawberryTypeFromPydantic[PydanticModel]]:
|
|
133
132
|
compat = PydanticCompat.from_model(model)
|
|
134
133
|
model_fields = compat.get_model_fields(model, include_computed=include_computed)
|
|
135
134
|
original_fields_set = set(fields) if fields else set()
|
|
@@ -247,8 +246,6 @@ def type( # noqa: PLR0915
|
|
|
247
246
|
# https://github.com/python/cpython/issues/89961
|
|
248
247
|
if sys.version_info >= (3, 10, 1):
|
|
249
248
|
kwargs["kw_only"] = dataclasses.MISSING
|
|
250
|
-
else:
|
|
251
|
-
kwargs["init"] = False
|
|
252
249
|
|
|
253
250
|
cls = dataclasses.make_dataclass(
|
|
254
251
|
cls.__name__,
|
|
@@ -258,11 +255,6 @@ def type( # noqa: PLR0915
|
|
|
258
255
|
**kwargs, # type: ignore
|
|
259
256
|
)
|
|
260
257
|
|
|
261
|
-
if sys.version_info < (3, 10, 1):
|
|
262
|
-
from strawberry.utils.dataclasses import add_custom_init_fn
|
|
263
|
-
|
|
264
|
-
add_custom_init_fn(cls)
|
|
265
|
-
|
|
266
258
|
_process_type(
|
|
267
259
|
cls,
|
|
268
260
|
name=name,
|
|
@@ -279,7 +271,7 @@ def type( # noqa: PLR0915
|
|
|
279
271
|
cls._pydantic_type = model
|
|
280
272
|
|
|
281
273
|
def from_pydantic_default(
|
|
282
|
-
instance: PydanticModel, extra:
|
|
274
|
+
instance: PydanticModel, extra: dict[str, Any] | None = None
|
|
283
275
|
) -> StrawberryTypeFromPydantic[PydanticModel]:
|
|
284
276
|
ret = convert_pydantic_model_to_strawberry_class(
|
|
285
277
|
cls=cls, model_instance=instance, extra=extra
|
|
@@ -310,11 +302,11 @@ def type( # noqa: PLR0915
|
|
|
310
302
|
def input(
|
|
311
303
|
model: builtins.type[PydanticModel],
|
|
312
304
|
*,
|
|
313
|
-
fields:
|
|
314
|
-
name:
|
|
305
|
+
fields: list[str] | None = None,
|
|
306
|
+
name: str | None = None,
|
|
315
307
|
is_interface: bool = False,
|
|
316
|
-
description:
|
|
317
|
-
directives:
|
|
308
|
+
description: str | None = None,
|
|
309
|
+
directives: Sequence[object] | None = (),
|
|
318
310
|
all_fields: bool = False,
|
|
319
311
|
use_pydantic_alias: bool = True,
|
|
320
312
|
) -> Callable[..., builtins.type[StrawberryTypeFromPydantic[PydanticModel]]]:
|
|
@@ -340,11 +332,11 @@ def input(
|
|
|
340
332
|
def interface(
|
|
341
333
|
model: builtins.type[PydanticModel],
|
|
342
334
|
*,
|
|
343
|
-
fields:
|
|
344
|
-
name:
|
|
335
|
+
fields: list[str] | None = None,
|
|
336
|
+
name: str | None = None,
|
|
345
337
|
is_input: bool = False,
|
|
346
|
-
description:
|
|
347
|
-
directives:
|
|
338
|
+
description: str | None = None,
|
|
339
|
+
directives: Sequence[object] | None = (),
|
|
348
340
|
all_fields: bool = False,
|
|
349
341
|
use_pydantic_alias: bool = True,
|
|
350
342
|
) -> Callable[..., builtins.type[StrawberryTypeFromPydantic[PydanticModel]]]:
|
|
@@ -5,7 +5,6 @@ from typing import (
|
|
|
5
5
|
TYPE_CHECKING,
|
|
6
6
|
Any,
|
|
7
7
|
NamedTuple,
|
|
8
|
-
Union,
|
|
9
8
|
cast,
|
|
10
9
|
)
|
|
11
10
|
|
|
@@ -69,7 +68,7 @@ class DataclassCreationFields(NamedTuple):
|
|
|
69
68
|
def get_default_factory_for_field(
|
|
70
69
|
field: CompatModelField,
|
|
71
70
|
compat: PydanticCompat,
|
|
72
|
-
) ->
|
|
71
|
+
) -> NoArgAnyCallable | dataclasses._MISSING_TYPE:
|
|
73
72
|
"""Gets the default factory for a pydantic field.
|
|
74
73
|
|
|
75
74
|
Handles mutable defaults when making the dataclass by
|
strawberry/ext/mypy_plugin.py
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
import typing
|
|
5
4
|
import warnings
|
|
6
5
|
from decimal import Decimal
|
|
7
6
|
from typing import (
|
|
8
7
|
TYPE_CHECKING,
|
|
9
8
|
Any,
|
|
10
|
-
Callable,
|
|
11
|
-
Optional,
|
|
12
|
-
Union,
|
|
13
9
|
cast,
|
|
14
10
|
)
|
|
15
11
|
|
|
@@ -57,7 +53,7 @@ try:
|
|
|
57
53
|
except ImportError:
|
|
58
54
|
TypeVarDef = TypeVarType
|
|
59
55
|
|
|
60
|
-
PYDANTIC_VERSION:
|
|
56
|
+
PYDANTIC_VERSION: tuple[int, ...] | None = None
|
|
61
57
|
|
|
62
58
|
# To be compatible with user who don't use pydantic
|
|
63
59
|
try:
|
|
@@ -74,6 +70,8 @@ except ImportError:
|
|
|
74
70
|
|
|
75
71
|
|
|
76
72
|
if TYPE_CHECKING:
|
|
73
|
+
from collections.abc import Callable
|
|
74
|
+
|
|
77
75
|
from mypy.nodes import ClassDef, Expression
|
|
78
76
|
from mypy.plugins import ( # type: ignore
|
|
79
77
|
AnalyzeTypeContext,
|
|
@@ -241,7 +239,7 @@ def enum_hook(ctx: DynamicClassDefContext) -> None:
|
|
|
241
239
|
)
|
|
242
240
|
return
|
|
243
241
|
|
|
244
|
-
enum_type:
|
|
242
|
+
enum_type: Type | None
|
|
245
243
|
|
|
246
244
|
try:
|
|
247
245
|
enum_type = _get_type_for_expr(first_argument, ctx.api)
|
|
@@ -289,7 +287,7 @@ def scalar_hook(ctx: DynamicClassDefContext) -> None:
|
|
|
289
287
|
)
|
|
290
288
|
return
|
|
291
289
|
|
|
292
|
-
scalar_type:
|
|
290
|
+
scalar_type: Type | None
|
|
293
291
|
|
|
294
292
|
# TODO: add proper support for NewType
|
|
295
293
|
|
|
@@ -314,12 +312,12 @@ def scalar_hook(ctx: DynamicClassDefContext) -> None:
|
|
|
314
312
|
|
|
315
313
|
|
|
316
314
|
def add_static_method_to_class(
|
|
317
|
-
api:
|
|
315
|
+
api: SemanticAnalyzerPluginInterface | CheckerPluginInterface,
|
|
318
316
|
cls: ClassDef,
|
|
319
317
|
name: str,
|
|
320
318
|
args: list[Argument],
|
|
321
319
|
return_type: Type,
|
|
322
|
-
tvar_def:
|
|
320
|
+
tvar_def: TypeVarType | None = None,
|
|
323
321
|
) -> None:
|
|
324
322
|
"""Adds a static method.
|
|
325
323
|
|
|
@@ -355,7 +353,7 @@ def add_static_method_to_class(
|
|
|
355
353
|
arg_types, arg_kinds, arg_names, return_type, function_type
|
|
356
354
|
)
|
|
357
355
|
if tvar_def:
|
|
358
|
-
signature.variables = [tvar_def]
|
|
356
|
+
signature.variables = [tvar_def] # type: ignore[assignment]
|
|
359
357
|
|
|
360
358
|
func = FuncDef(name, args, Block([PassStmt()]))
|
|
361
359
|
|
|
@@ -527,7 +525,7 @@ def strawberry_pydantic_class_callback(ctx: ClassDefContext) -> None:
|
|
|
527
525
|
class StrawberryPlugin(Plugin):
|
|
528
526
|
def get_dynamic_class_hook(
|
|
529
527
|
self, fullname: str
|
|
530
|
-
) ->
|
|
528
|
+
) -> Callable[[DynamicClassDefContext], None] | None:
|
|
531
529
|
# TODO: investigate why we need this instead of `strawberry.union.union` on CI
|
|
532
530
|
# we have the same issue in the other hooks
|
|
533
531
|
if self._is_strawberry_union(fullname):
|
|
@@ -544,7 +542,7 @@ class StrawberryPlugin(Plugin):
|
|
|
544
542
|
|
|
545
543
|
return None
|
|
546
544
|
|
|
547
|
-
def get_type_analyze_hook(self, fullname: str) ->
|
|
545
|
+
def get_type_analyze_hook(self, fullname: str) -> Callable[..., Type] | None:
|
|
548
546
|
if self._is_strawberry_lazy_type(fullname):
|
|
549
547
|
return lazy_type_analyze_callback
|
|
550
548
|
|
|
@@ -552,7 +550,7 @@ class StrawberryPlugin(Plugin):
|
|
|
552
550
|
|
|
553
551
|
def get_class_decorator_hook(
|
|
554
552
|
self, fullname: str
|
|
555
|
-
) ->
|
|
553
|
+
) -> Callable[[ClassDefContext], None] | None:
|
|
556
554
|
if self._is_strawberry_pydantic_decorator(fullname):
|
|
557
555
|
return strawberry_pydantic_class_callback
|
|
558
556
|
|
|
@@ -613,7 +611,7 @@ class StrawberryPlugin(Plugin):
|
|
|
613
611
|
)
|
|
614
612
|
|
|
615
613
|
|
|
616
|
-
def plugin(version: str) ->
|
|
614
|
+
def plugin(version: str) -> type[StrawberryPlugin]:
|
|
617
615
|
match = VERSION_RE.match(version)
|
|
618
616
|
if match:
|
|
619
617
|
MypyVersion.VERSION = Decimal(".".join(match.groups()))
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Callable
|
|
3
4
|
from enum import Enum
|
|
4
|
-
from typing import TYPE_CHECKING, Any
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
5
6
|
|
|
6
7
|
from strawberry.utils.await_maybe import AsyncIteratorOrIterator, AwaitableOrValue
|
|
7
8
|
|
strawberry/extensions/context.py
CHANGED
|
@@ -8,17 +8,14 @@ from asyncio import iscoroutinefunction
|
|
|
8
8
|
from typing import (
|
|
9
9
|
TYPE_CHECKING,
|
|
10
10
|
Any,
|
|
11
|
-
Callable,
|
|
12
11
|
NamedTuple,
|
|
13
|
-
Optional,
|
|
14
|
-
Union,
|
|
15
12
|
)
|
|
16
13
|
|
|
17
14
|
from strawberry.extensions import SchemaExtension
|
|
18
15
|
from strawberry.utils.await_maybe import AwaitableOrValue, await_maybe
|
|
19
16
|
|
|
20
17
|
if TYPE_CHECKING:
|
|
21
|
-
from collections.abc import AsyncIterator, Iterator
|
|
18
|
+
from collections.abc import AsyncIterator, Callable, Iterator
|
|
22
19
|
from types import TracebackType
|
|
23
20
|
|
|
24
21
|
from strawberry.extensions.base_extension import Hook
|
|
@@ -28,10 +25,8 @@ class WrappedHook(NamedTuple):
|
|
|
28
25
|
extension: SchemaExtension
|
|
29
26
|
hook: Callable[
|
|
30
27
|
...,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
contextlib.AbstractContextManager[None],
|
|
34
|
-
],
|
|
28
|
+
contextlib.AbstractAsyncContextManager[None]
|
|
29
|
+
| contextlib.AbstractContextManager[None],
|
|
35
30
|
]
|
|
36
31
|
is_async: bool
|
|
37
32
|
|
|
@@ -65,12 +60,12 @@ class ExtensionContextManagerBase:
|
|
|
65
60
|
if hook:
|
|
66
61
|
self.hooks.append(hook)
|
|
67
62
|
|
|
68
|
-
def get_hook(self, extension: SchemaExtension) ->
|
|
63
|
+
def get_hook(self, extension: SchemaExtension) -> WrappedHook | None:
|
|
69
64
|
on_start = getattr(extension, self.LEGACY_ENTER, None)
|
|
70
65
|
on_end = getattr(extension, self.LEGACY_EXIT, None)
|
|
71
66
|
|
|
72
67
|
is_legacy = on_start is not None or on_end is not None
|
|
73
|
-
hook_fn:
|
|
68
|
+
hook_fn: Hook | None = getattr(type(extension), self.HOOK_NAME)
|
|
74
69
|
hook_fn = hook_fn if hook_fn is not self.default_hook else None
|
|
75
70
|
if is_legacy and hook_fn is not None:
|
|
76
71
|
raise ValueError(
|
|
@@ -111,8 +106,8 @@ class ExtensionContextManagerBase:
|
|
|
111
106
|
@staticmethod
|
|
112
107
|
def from_legacy(
|
|
113
108
|
extension: SchemaExtension,
|
|
114
|
-
on_start:
|
|
115
|
-
on_end:
|
|
109
|
+
on_start: Callable[[], None] | None = None,
|
|
110
|
+
on_end: Callable[[], None] | None = None,
|
|
116
111
|
) -> WrappedHook:
|
|
117
112
|
if iscoroutinefunction(on_start) or iscoroutinefunction(on_end):
|
|
118
113
|
|
|
@@ -176,9 +171,9 @@ class ExtensionContextManagerBase:
|
|
|
176
171
|
|
|
177
172
|
def __exit__(
|
|
178
173
|
self,
|
|
179
|
-
exc_type:
|
|
180
|
-
exc_val:
|
|
181
|
-
exc_tb:
|
|
174
|
+
exc_type: type[BaseException] | None,
|
|
175
|
+
exc_val: BaseException | None,
|
|
176
|
+
exc_tb: TracebackType | None,
|
|
182
177
|
) -> None:
|
|
183
178
|
self.exit_stack.__exit__(exc_type, exc_val, exc_tb)
|
|
184
179
|
|
|
@@ -195,9 +190,9 @@ class ExtensionContextManagerBase:
|
|
|
195
190
|
|
|
196
191
|
async def __aexit__(
|
|
197
192
|
self,
|
|
198
|
-
exc_type:
|
|
199
|
-
exc_val:
|
|
200
|
-
exc_tb:
|
|
193
|
+
exc_type: type[BaseException] | None,
|
|
194
|
+
exc_val: BaseException | None,
|
|
195
|
+
exc_tb: TracebackType | None,
|
|
201
196
|
) -> None:
|
|
202
197
|
await self.async_exit_stack.__aexit__(exc_type, exc_val, exc_tb)
|
|
203
198
|
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
from strawberry.extensions import SchemaExtension
|
|
6
6
|
from strawberry.types.nodes import convert_arguments
|
|
7
7
|
from strawberry.utils.await_maybe import await_maybe
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
|
|
10
12
|
from graphql import DirectiveNode, GraphQLResolveInfo
|
|
11
13
|
|
|
12
14
|
from strawberry.directive import StrawberryDirective
|
|
@@ -29,7 +31,9 @@ class DirectivesExtension(SchemaExtension):
|
|
|
29
31
|
) -> AwaitableOrValue[Any]:
|
|
30
32
|
value = await await_maybe(_next(root, info, *args, **kwargs))
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
nodes = list(info.field_nodes)
|
|
35
|
+
|
|
36
|
+
for directive in nodes[0].directives:
|
|
33
37
|
if directive.name.value in SPECIFIED_DIRECTIVES:
|
|
34
38
|
continue
|
|
35
39
|
strawberry_directive, arguments = process_directive(directive, value, info)
|
|
@@ -49,7 +53,9 @@ class DirectivesExtensionSync(SchemaExtension):
|
|
|
49
53
|
) -> AwaitableOrValue[Any]:
|
|
50
54
|
value = _next(root, info, *args, **kwargs)
|
|
51
55
|
|
|
52
|
-
|
|
56
|
+
nodes = list(info.field_nodes)
|
|
57
|
+
|
|
58
|
+
for directive in nodes[0].directives:
|
|
53
59
|
if directive.name.value in SPECIFIED_DIRECTIVES:
|
|
54
60
|
continue
|
|
55
61
|
strawberry_directive, arguments = process_directive(directive, value, info)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import itertools
|
|
4
|
-
from collections.abc import Awaitable
|
|
4
|
+
from collections.abc import Awaitable, Callable
|
|
5
5
|
from functools import cached_property
|
|
6
|
-
from typing import TYPE_CHECKING, Any
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
|
-
from
|
|
9
|
+
from typing import TypeAlias
|
|
10
10
|
|
|
11
11
|
from strawberry.types import Info
|
|
12
12
|
from strawberry.types.field import StrawberryField
|
|
@@ -69,7 +69,7 @@ def _get_async_resolvers(
|
|
|
69
69
|
|
|
70
70
|
def build_field_extension_resolvers(
|
|
71
71
|
field: StrawberryField,
|
|
72
|
-
) -> list[
|
|
72
|
+
) -> list[SyncExtensionResolver | AsyncExtensionResolver]:
|
|
73
73
|
"""Builds a list of resolvers for a field with extensions.
|
|
74
74
|
|
|
75
75
|
Verifies that all of the field extensions for a given field support
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
from collections.abc import Iterator
|
|
2
|
-
from typing import
|
|
1
|
+
from collections.abc import Callable, Iterator
|
|
2
|
+
from typing import Any
|
|
3
3
|
|
|
4
4
|
from graphql.error import GraphQLError
|
|
5
|
+
from graphql.execution.execute import ExecutionResult as GraphQLExecutionResult
|
|
5
6
|
|
|
6
7
|
from strawberry.extensions.base_extension import SchemaExtension
|
|
8
|
+
from strawberry.types.execution import ExecutionResult as StrawberryExecutionResult
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
def default_should_mask_error(_: GraphQLError) -> bool:
|
|
@@ -33,18 +35,27 @@ class MaskErrors(SchemaExtension):
|
|
|
33
35
|
original_error=None,
|
|
34
36
|
)
|
|
35
37
|
|
|
38
|
+
# TODO: proper typing
|
|
39
|
+
def _process_result(self, result: Any) -> None:
|
|
40
|
+
if not result.errors:
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
processed_errors: list[GraphQLError] = []
|
|
44
|
+
|
|
45
|
+
for error in result.errors:
|
|
46
|
+
if self.should_mask_error(error):
|
|
47
|
+
processed_errors.append(self.anonymise_error(error))
|
|
48
|
+
else:
|
|
49
|
+
processed_errors.append(error)
|
|
50
|
+
|
|
51
|
+
result.errors = processed_errors
|
|
52
|
+
|
|
36
53
|
def on_operation(self) -> Iterator[None]:
|
|
37
54
|
yield
|
|
38
|
-
result = self.execution_context.result
|
|
39
|
-
if result and result.errors:
|
|
40
|
-
processed_errors: list[GraphQLError] = []
|
|
41
|
-
for error in result.errors:
|
|
42
|
-
if self.should_mask_error(error):
|
|
43
|
-
processed_errors.append(self.anonymise_error(error))
|
|
44
|
-
else:
|
|
45
|
-
processed_errors.append(error)
|
|
46
|
-
|
|
47
|
-
result.errors = processed_errors
|
|
48
55
|
|
|
56
|
+
result = self.execution_context.result
|
|
49
57
|
|
|
50
|
-
|
|
58
|
+
if isinstance(result, (GraphQLExecutionResult, StrawberryExecutionResult)):
|
|
59
|
+
self._process_result(result)
|
|
60
|
+
elif result:
|
|
61
|
+
self._process_result(result.initial_result)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Union
|
|
2
|
-
|
|
3
1
|
from graphql import (
|
|
4
2
|
ExecutableDefinitionNode,
|
|
5
3
|
FieldNode,
|
|
@@ -64,7 +62,7 @@ def create_validator(max_alias_count: int) -> type[ValidationRule]:
|
|
|
64
62
|
|
|
65
63
|
|
|
66
64
|
def count_fields_with_alias(
|
|
67
|
-
selection_set_owner:
|
|
65
|
+
selection_set_owner: ExecutableDefinitionNode | FieldNode | InlineFragmentNode,
|
|
68
66
|
) -> int:
|
|
69
67
|
if selection_set_owner.selection_set is None:
|
|
70
68
|
return 0
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from collections.abc import Iterator
|
|
2
2
|
from functools import lru_cache
|
|
3
|
-
from typing import Optional
|
|
4
3
|
|
|
5
4
|
from graphql.language.parser import parse
|
|
6
5
|
|
|
@@ -25,7 +24,7 @@ class ParserCache(SchemaExtension):
|
|
|
25
24
|
```
|
|
26
25
|
"""
|
|
27
26
|
|
|
28
|
-
def __init__(self, maxsize:
|
|
27
|
+
def __init__(self, maxsize: int | None = None) -> None:
|
|
29
28
|
"""Initialize the ParserCache.
|
|
30
29
|
|
|
31
30
|
Args:
|
|
@@ -28,12 +28,11 @@
|
|
|
28
28
|
from __future__ import annotations
|
|
29
29
|
|
|
30
30
|
import re
|
|
31
|
+
from collections.abc import Callable
|
|
31
32
|
from dataclasses import dataclass
|
|
32
33
|
from typing import (
|
|
33
34
|
TYPE_CHECKING,
|
|
34
|
-
|
|
35
|
-
Optional,
|
|
36
|
-
Union,
|
|
35
|
+
TypeAlias,
|
|
37
36
|
)
|
|
38
37
|
|
|
39
38
|
from graphql import GraphQLError
|
|
@@ -61,12 +60,17 @@ from strawberry.extensions.utils import is_introspection_key
|
|
|
61
60
|
if TYPE_CHECKING:
|
|
62
61
|
from collections.abc import Iterable
|
|
63
62
|
|
|
64
|
-
IgnoreType =
|
|
63
|
+
IgnoreType: TypeAlias = Callable[[str], bool] | re.Pattern | str
|
|
65
64
|
|
|
66
|
-
FieldArgumentType =
|
|
67
|
-
bool
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
FieldArgumentType: TypeAlias = (
|
|
66
|
+
bool
|
|
67
|
+
| int
|
|
68
|
+
| float
|
|
69
|
+
| str
|
|
70
|
+
| list["FieldArgumentType"]
|
|
71
|
+
| dict[str, "FieldArgumentType"]
|
|
72
|
+
)
|
|
73
|
+
FieldArgumentsType: TypeAlias = dict[str, FieldArgumentType]
|
|
70
74
|
|
|
71
75
|
|
|
72
76
|
@dataclass
|
|
@@ -99,8 +103,8 @@ class QueryDepthLimiter(AddValidationRules):
|
|
|
99
103
|
def __init__(
|
|
100
104
|
self,
|
|
101
105
|
max_depth: int,
|
|
102
|
-
callback:
|
|
103
|
-
should_ignore:
|
|
106
|
+
callback: Callable[[dict[str, int]], None] | None = None,
|
|
107
|
+
should_ignore: ShouldIgnoreType | None = None,
|
|
104
108
|
) -> None:
|
|
105
109
|
"""Initialize the QueryDepthLimiter.
|
|
106
110
|
|
|
@@ -122,8 +126,8 @@ class QueryDepthLimiter(AddValidationRules):
|
|
|
122
126
|
|
|
123
127
|
def create_validator(
|
|
124
128
|
max_depth: int,
|
|
125
|
-
should_ignore:
|
|
126
|
-
callback:
|
|
129
|
+
should_ignore: ShouldIgnoreType | None,
|
|
130
|
+
callback: Callable[[dict[str, int]], None] | None = None,
|
|
127
131
|
) -> type[ValidationRule]:
|
|
128
132
|
class DepthLimitValidator(ValidationRule):
|
|
129
133
|
def __init__(self, validation_context: ValidationContext) -> None:
|
|
@@ -218,7 +222,7 @@ def determine_depth(
|
|
|
218
222
|
max_depth: int,
|
|
219
223
|
context: ValidationContext,
|
|
220
224
|
operation_name: str,
|
|
221
|
-
should_ignore:
|
|
225
|
+
should_ignore: ShouldIgnoreType | None,
|
|
222
226
|
) -> int:
|
|
223
227
|
if depth_so_far > max_depth:
|
|
224
228
|
context.report_error(
|
|
@@ -288,7 +292,7 @@ def determine_depth(
|
|
|
288
292
|
raise TypeError(f"Depth crawler cannot handle: {node.kind}") # pragma: no cover
|
|
289
293
|
|
|
290
294
|
|
|
291
|
-
def is_ignored(node: FieldNode, ignore:
|
|
295
|
+
def is_ignored(node: FieldNode, ignore: list[IgnoreType] | None = None) -> bool:
|
|
292
296
|
if ignore is None:
|
|
293
297
|
return False
|
|
294
298
|
|
strawberry/extensions/runner.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import inspect
|
|
4
|
-
from typing import TYPE_CHECKING, Any
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
5
|
|
|
6
6
|
from strawberry.extensions.context import (
|
|
7
7
|
ExecutingContextManager,
|
|
@@ -23,7 +23,7 @@ class SchemaExtensionsRunner:
|
|
|
23
23
|
def __init__(
|
|
24
24
|
self,
|
|
25
25
|
execution_context: ExecutionContext,
|
|
26
|
-
extensions:
|
|
26
|
+
extensions: list[SchemaExtension] | None = None,
|
|
27
27
|
) -> None:
|
|
28
28
|
self.execution_context = execution_context
|
|
29
29
|
self.extensions = extensions or []
|
|
@@ -4,7 +4,7 @@ import dataclasses
|
|
|
4
4
|
import time
|
|
5
5
|
from datetime import datetime, timezone
|
|
6
6
|
from inspect import isawaitable
|
|
7
|
-
from typing import TYPE_CHECKING, Any
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
8
|
|
|
9
9
|
from strawberry.extensions import SchemaExtension
|
|
10
10
|
from strawberry.extensions.utils import get_path_from_info
|
|
@@ -12,7 +12,7 @@ from strawberry.extensions.utils import get_path_from_info
|
|
|
12
12
|
from .utils import should_skip_tracing
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
|
-
from collections.abc import Generator
|
|
15
|
+
from collections.abc import Callable, Generator
|
|
16
16
|
|
|
17
17
|
from graphql import GraphQLResolveInfo
|
|
18
18
|
|
|
@@ -38,7 +38,7 @@ class ApolloResolverStats:
|
|
|
38
38
|
field_name: str
|
|
39
39
|
return_type: Any
|
|
40
40
|
start_offset: int
|
|
41
|
-
duration:
|
|
41
|
+
duration: int | None = None
|
|
42
42
|
|
|
43
43
|
def to_json(self) -> dict[str, Any]:
|
|
44
44
|
return {
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import hashlib
|
|
4
4
|
from functools import cached_property
|
|
5
5
|
from inspect import isawaitable
|
|
6
|
-
from typing import TYPE_CHECKING, Any
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
7
|
|
|
8
8
|
import ddtrace
|
|
9
9
|
from packaging import version
|
|
@@ -19,7 +19,7 @@ else:
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
|
-
from collections.abc import Generator, Iterator
|
|
22
|
+
from collections.abc import Callable, Generator, Iterator
|
|
23
23
|
|
|
24
24
|
from graphql import GraphQLResolveInfo
|
|
25
25
|
|
|
@@ -30,7 +30,7 @@ class DatadogTracingExtension(SchemaExtension):
|
|
|
30
30
|
def __init__(
|
|
31
31
|
self,
|
|
32
32
|
*,
|
|
33
|
-
execution_context:
|
|
33
|
+
execution_context: ExecutionContext | None = None,
|
|
34
34
|
) -> None:
|
|
35
35
|
if execution_context:
|
|
36
36
|
self.execution_context = execution_context
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Callable
|
|
3
4
|
from copy import deepcopy
|
|
4
5
|
from inspect import isawaitable
|
|
5
6
|
from typing import (
|
|
6
7
|
TYPE_CHECKING,
|
|
7
8
|
Any,
|
|
8
|
-
Callable,
|
|
9
|
-
Optional,
|
|
10
|
-
Union,
|
|
11
9
|
)
|
|
12
10
|
|
|
13
11
|
from opentelemetry import trace
|
|
@@ -33,16 +31,16 @@ ArgFilter = Callable[[dict[str, Any], "GraphQLResolveInfo"], dict[str, Any]]
|
|
|
33
31
|
|
|
34
32
|
|
|
35
33
|
class OpenTelemetryExtension(SchemaExtension):
|
|
36
|
-
_arg_filter:
|
|
34
|
+
_arg_filter: ArgFilter | None
|
|
37
35
|
_span_holder: dict[LifecycleStep, Span]
|
|
38
36
|
_tracer: Tracer
|
|
39
37
|
|
|
40
38
|
def __init__(
|
|
41
39
|
self,
|
|
42
40
|
*,
|
|
43
|
-
execution_context:
|
|
44
|
-
arg_filter:
|
|
45
|
-
tracer_provider:
|
|
41
|
+
execution_context: ExecutionContext | None = None,
|
|
42
|
+
arg_filter: ArgFilter | None = None,
|
|
43
|
+
tracer_provider: trace.TracerProvider | None = None,
|
|
46
44
|
) -> None:
|
|
47
45
|
self._arg_filter = arg_filter
|
|
48
46
|
self._tracer = trace.get_tracer("strawberry", tracer_provider=tracer_provider)
|
|
@@ -129,7 +127,7 @@ class OpenTelemetryExtension(SchemaExtension):
|
|
|
129
127
|
return bytes(value) # Convert bytearray and memoryview to bytes
|
|
130
128
|
return str(value)
|
|
131
129
|
|
|
132
|
-
def convert_set_to_allowed_types(self, value:
|
|
130
|
+
def convert_set_to_allowed_types(self, value: set | frozenset) -> str:
|
|
133
131
|
return (
|
|
134
132
|
"{" + ", ".join(str(self.convert_to_allowed_types(x)) for x in value) + "}"
|
|
135
133
|
)
|