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.

Files changed (161) hide show
  1. strawberry/__init__.py +2 -0
  2. strawberry/aiohttp/test/client.py +8 -15
  3. strawberry/aiohttp/views.py +15 -64
  4. strawberry/annotation.py +70 -25
  5. strawberry/asgi/__init__.py +22 -56
  6. strawberry/asgi/test/client.py +6 -6
  7. strawberry/chalice/views.py +13 -79
  8. strawberry/channels/handlers/base.py +7 -8
  9. strawberry/channels/handlers/http_handler.py +50 -32
  10. strawberry/channels/handlers/ws_handler.py +12 -14
  11. strawberry/channels/router.py +3 -4
  12. strawberry/channels/testing.py +7 -9
  13. strawberry/cli/__init__.py +7 -6
  14. strawberry/cli/commands/codegen.py +7 -7
  15. strawberry/cli/commands/dev.py +72 -0
  16. strawberry/cli/commands/schema_codegen.py +1 -2
  17. strawberry/cli/commands/server.py +3 -44
  18. strawberry/cli/commands/upgrade/__init__.py +3 -3
  19. strawberry/cli/commands/upgrade/_run_codemod.py +2 -2
  20. strawberry/cli/constants.py +1 -2
  21. strawberry/cli/{debug_server.py → dev_server.py} +3 -7
  22. strawberry/codegen/plugins/print_operation.py +2 -2
  23. strawberry/codegen/plugins/python.py +2 -2
  24. strawberry/codegen/query_codegen.py +20 -30
  25. strawberry/codegen/types.py +32 -32
  26. strawberry/codemods/__init__.py +9 -0
  27. strawberry/codemods/annotated_unions.py +2 -2
  28. strawberry/codemods/maybe_optional.py +118 -0
  29. strawberry/dataloader.py +28 -24
  30. strawberry/directive.py +6 -7
  31. strawberry/django/test/client.py +3 -3
  32. strawberry/django/views.py +21 -91
  33. strawberry/exceptions/__init__.py +4 -4
  34. strawberry/exceptions/conflicting_arguments.py +2 -2
  35. strawberry/exceptions/duplicated_type_name.py +4 -4
  36. strawberry/exceptions/exception.py +3 -3
  37. strawberry/exceptions/handler.py +8 -7
  38. strawberry/exceptions/invalid_argument_type.py +2 -2
  39. strawberry/exceptions/invalid_superclass_interface.py +2 -2
  40. strawberry/exceptions/invalid_union_type.py +4 -4
  41. strawberry/exceptions/missing_arguments_annotations.py +2 -2
  42. strawberry/exceptions/missing_dependencies.py +2 -4
  43. strawberry/exceptions/missing_field_annotation.py +2 -2
  44. strawberry/exceptions/missing_return_annotation.py +2 -2
  45. strawberry/exceptions/object_is_not_a_class.py +2 -2
  46. strawberry/exceptions/object_is_not_an_enum.py +2 -2
  47. strawberry/exceptions/permission_fail_silently_requires_optional.py +2 -2
  48. strawberry/exceptions/private_strawberry_field.py +2 -2
  49. strawberry/exceptions/scalar_already_registered.py +2 -2
  50. strawberry/exceptions/syntax.py +3 -3
  51. strawberry/exceptions/unresolved_field_type.py +2 -2
  52. strawberry/exceptions/utils/source_finder.py +25 -25
  53. strawberry/experimental/pydantic/_compat.py +8 -7
  54. strawberry/experimental/pydantic/conversion.py +2 -2
  55. strawberry/experimental/pydantic/conversion_types.py +2 -2
  56. strawberry/experimental/pydantic/error_type.py +10 -12
  57. strawberry/experimental/pydantic/fields.py +9 -15
  58. strawberry/experimental/pydantic/object_type.py +17 -25
  59. strawberry/experimental/pydantic/utils.py +1 -2
  60. strawberry/ext/mypy_plugin.py +12 -14
  61. strawberry/extensions/base_extension.py +2 -1
  62. strawberry/extensions/context.py +13 -18
  63. strawberry/extensions/directives.py +9 -3
  64. strawberry/extensions/field_extension.py +4 -4
  65. strawberry/extensions/mask_errors.py +24 -13
  66. strawberry/extensions/max_aliases.py +1 -3
  67. strawberry/extensions/parser_cache.py +1 -2
  68. strawberry/extensions/query_depth_limiter.py +18 -14
  69. strawberry/extensions/runner.py +2 -2
  70. strawberry/extensions/tracing/apollo.py +3 -3
  71. strawberry/extensions/tracing/datadog.py +3 -3
  72. strawberry/extensions/tracing/opentelemetry.py +6 -8
  73. strawberry/extensions/tracing/utils.py +3 -1
  74. strawberry/extensions/utils.py +2 -2
  75. strawberry/extensions/validation_cache.py +2 -3
  76. strawberry/fastapi/context.py +6 -6
  77. strawberry/fastapi/router.py +43 -42
  78. strawberry/federation/argument.py +4 -5
  79. strawberry/federation/enum.py +18 -21
  80. strawberry/federation/field.py +94 -97
  81. strawberry/federation/object_type.py +56 -58
  82. strawberry/federation/scalar.py +27 -35
  83. strawberry/federation/schema.py +15 -16
  84. strawberry/federation/schema_directive.py +7 -6
  85. strawberry/federation/schema_directives.py +11 -11
  86. strawberry/federation/union.py +4 -4
  87. strawberry/flask/views.py +16 -85
  88. strawberry/http/__init__.py +30 -20
  89. strawberry/http/async_base_view.py +208 -89
  90. strawberry/http/base.py +28 -11
  91. strawberry/http/exceptions.py +5 -7
  92. strawberry/http/ides.py +2 -3
  93. strawberry/http/sync_base_view.py +115 -69
  94. strawberry/http/types.py +3 -3
  95. strawberry/litestar/controller.py +43 -77
  96. strawberry/permission.py +4 -6
  97. strawberry/printer/ast_from_value.py +3 -5
  98. strawberry/printer/printer.py +18 -15
  99. strawberry/quart/views.py +16 -48
  100. strawberry/relay/exceptions.py +4 -4
  101. strawberry/relay/fields.py +33 -32
  102. strawberry/relay/types.py +32 -35
  103. strawberry/relay/utils.py +11 -23
  104. strawberry/resolvers.py +2 -1
  105. strawberry/sanic/context.py +1 -0
  106. strawberry/sanic/utils.py +3 -3
  107. strawberry/sanic/views.py +15 -54
  108. strawberry/scalars.py +2 -2
  109. strawberry/schema/_graphql_core.py +55 -0
  110. strawberry/schema/base.py +32 -33
  111. strawberry/schema/compat.py +9 -9
  112. strawberry/schema/config.py +10 -1
  113. strawberry/schema/exceptions.py +1 -3
  114. strawberry/schema/name_converter.py +9 -8
  115. strawberry/schema/schema.py +133 -100
  116. strawberry/schema/schema_converter.py +96 -58
  117. strawberry/schema/types/base_scalars.py +1 -1
  118. strawberry/schema/types/concrete_type.py +5 -5
  119. strawberry/schema/validation_rules/maybe_null.py +136 -0
  120. strawberry/schema_codegen/__init__.py +3 -3
  121. strawberry/schema_directive.py +7 -6
  122. strawberry/static/graphiql.html +5 -5
  123. strawberry/streamable.py +35 -0
  124. strawberry/subscriptions/protocols/graphql_transport_ws/handlers.py +5 -16
  125. strawberry/subscriptions/protocols/graphql_transport_ws/types.py +20 -20
  126. strawberry/subscriptions/protocols/graphql_ws/handlers.py +5 -12
  127. strawberry/subscriptions/protocols/graphql_ws/types.py +14 -14
  128. strawberry/test/client.py +18 -18
  129. strawberry/tools/create_type.py +2 -3
  130. strawberry/types/arguments.py +41 -28
  131. strawberry/types/auto.py +3 -4
  132. strawberry/types/base.py +25 -27
  133. strawberry/types/enum.py +22 -25
  134. strawberry/types/execution.py +21 -16
  135. strawberry/types/field.py +109 -130
  136. strawberry/types/fields/resolver.py +19 -21
  137. strawberry/types/info.py +5 -11
  138. strawberry/types/lazy_type.py +2 -3
  139. strawberry/types/maybe.py +12 -3
  140. strawberry/types/mutation.py +115 -118
  141. strawberry/types/nodes.py +2 -2
  142. strawberry/types/object_type.py +43 -63
  143. strawberry/types/scalar.py +37 -43
  144. strawberry/types/union.py +12 -14
  145. strawberry/utils/aio.py +12 -9
  146. strawberry/utils/await_maybe.py +3 -3
  147. strawberry/utils/deprecations.py +2 -2
  148. strawberry/utils/importer.py +1 -2
  149. strawberry/utils/inspect.py +4 -6
  150. strawberry/utils/logging.py +2 -2
  151. strawberry/utils/operation.py +4 -4
  152. strawberry/utils/typing.py +18 -83
  153. {strawberry_graphql-0.275.7.dist-info → strawberry_graphql-0.284.3.dist-info}/METADATA +14 -8
  154. strawberry_graphql-0.284.3.dist-info/RECORD +243 -0
  155. {strawberry_graphql-0.275.7.dist-info → strawberry_graphql-0.284.3.dist-info}/WHEEL +1 -1
  156. strawberry/utils/dataclasses.py +0 -37
  157. strawberry/utils/debug.py +0 -46
  158. strawberry/utils/graphql_lexer.py +0 -35
  159. strawberry_graphql-0.275.7.dist-info/RECORD +0 -241
  160. {strawberry_graphql-0.275.7.dist-info → strawberry_graphql-0.284.3.dist-info}/entry_points.txt +0 -0
  161. {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( # noqa: PLR0915
118
+ def type(
120
119
  model: builtins.type[PydanticModel],
121
120
  *,
122
- fields: Optional[list[str]] = None,
123
- name: Optional[str] = None,
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: Optional[str] = None,
127
- directives: Optional[Sequence[object]] = (),
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]]: # noqa: PLR0915
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: Optional[dict[str, Any]] = None
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: Optional[list[str]] = None,
314
- name: Optional[str] = None,
305
+ fields: list[str] | None = None,
306
+ name: str | None = None,
315
307
  is_interface: bool = False,
316
- description: Optional[str] = None,
317
- directives: Optional[Sequence[object]] = (),
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: Optional[list[str]] = None,
344
- name: Optional[str] = None,
335
+ fields: list[str] | None = None,
336
+ name: str | None = None,
345
337
  is_input: bool = False,
346
- description: Optional[str] = None,
347
- directives: Optional[Sequence[object]] = (),
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
- ) -> Union[NoArgAnyCallable, dataclasses._MISSING_TYPE]:
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
@@ -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: Optional[tuple[int, ...]] = None
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: Optional[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: Optional[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: Union[SemanticAnalyzerPluginInterface, CheckerPluginInterface],
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: Optional[TypeVarType] = None,
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
- ) -> Optional[Callable[[DynamicClassDefContext], None]]:
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) -> Union[Callable[..., Type], None]:
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
- ) -> Optional[Callable[[ClassDefContext], None]]:
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) -> typing.Type[StrawberryPlugin]:
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, Callable
5
+ from typing import TYPE_CHECKING, Any
5
6
 
6
7
  from strawberry.utils.await_maybe import AsyncIteratorOrIterator, AwaitableOrValue
7
8
 
@@ -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
- Union[
32
- contextlib.AbstractAsyncContextManager[None],
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) -> Optional[WrappedHook]:
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: Optional[Hook] = getattr(type(extension), self.HOOK_NAME)
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: Optional[Callable[[], None]] = None,
115
- on_end: Optional[Callable[[], None]] = None,
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: Optional[type[BaseException]],
180
- exc_val: Optional[BaseException],
181
- exc_tb: Optional[TracebackType],
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: Optional[type[BaseException]],
199
- exc_val: Optional[BaseException],
200
- exc_tb: Optional[TracebackType],
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, Callable
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
- for directive in info.field_nodes[0].directives:
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
- for directive in info.field_nodes[0].directives:
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, Callable, Union
6
+ from typing import TYPE_CHECKING, Any
7
7
 
8
8
  if TYPE_CHECKING:
9
- from typing_extensions import TypeAlias
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[Union[SyncExtensionResolver, AsyncExtensionResolver]]:
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 Callable
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
- __all__ = ["MaskErrors"]
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: Union[ExecutableDefinitionNode, FieldNode, InlineFragmentNode],
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: Optional[int] = None) -> None:
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
- Callable,
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 = Union[Callable[[str], bool], re.Pattern, str]
63
+ IgnoreType: TypeAlias = Callable[[str], bool] | re.Pattern | str
65
64
 
66
- FieldArgumentType = Union[
67
- bool, int, float, str, list["FieldArgumentType"], dict[str, "FieldArgumentType"]
68
- ]
69
- FieldArgumentsType = dict[str, FieldArgumentType]
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: Optional[Callable[[dict[str, int]], None]] = None,
103
- should_ignore: Optional[ShouldIgnoreType] = None,
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: Optional[ShouldIgnoreType],
126
- callback: Optional[Callable[[dict[str, int]], None]] = None,
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: Optional[ShouldIgnoreType],
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: Optional[list[IgnoreType]] = None) -> bool:
295
+ def is_ignored(node: FieldNode, ignore: list[IgnoreType] | None = None) -> bool:
292
296
  if ignore is None:
293
297
  return False
294
298
 
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import inspect
4
- from typing import TYPE_CHECKING, Any, Optional
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: Optional[list[SchemaExtension]] = None,
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, Callable, Optional
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: Optional[int] = None
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, Callable, Optional
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: Optional[ExecutionContext] = None,
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: Optional[ArgFilter]
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: Optional[ExecutionContext] = None,
44
- arg_filter: Optional[ArgFilter] = None,
45
- tracer_provider: Optional[trace.TracerProvider] = None,
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: Union[set, frozenset]) -> str:
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
  )