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
strawberry/relay/utils.py CHANGED
@@ -3,11 +3,11 @@ from __future__ import annotations
3
3
  import base64
4
4
  import dataclasses
5
5
  import sys
6
- from typing import TYPE_CHECKING, Any, Union
6
+ from typing import TYPE_CHECKING, Any
7
7
  from typing_extensions import Self, assert_never
8
8
 
9
9
  from strawberry.types.base import StrawberryObjectDefinition
10
- from strawberry.types.nodes import InlineFragment, Selection
10
+ from strawberry.types.nodes import InlineFragment
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from strawberry.types.info import Info
@@ -39,7 +39,7 @@ def from_base64(value: str) -> tuple[str, str]:
39
39
  return res[0], res[1]
40
40
 
41
41
 
42
- def to_base64(type_: Union[str, type, StrawberryObjectDefinition], node_id: Any) -> str:
42
+ def to_base64(type_: str | type | StrawberryObjectDefinition, node_id: Any) -> str:
43
43
  """Encode the type name and node id to a base64 string.
44
44
 
45
45
  Args:
@@ -83,31 +83,19 @@ def should_resolve_list_connection_edges(info: Info) -> bool:
83
83
 
84
84
  """
85
85
  resolve_for_field_names = {"edges", "pageInfo"}
86
-
87
- def _check_selection(selection: Selection) -> bool:
88
- """Recursively inspect the selection to check if the user requested to resolve the `edges` field.
89
-
90
- Args:
91
- selection (Selection): The selection to check.
92
-
93
- Returns:
94
- bool: True if the user requested to resolve the `edges` field of a connection, False otherwise.
95
- """
86
+ # Recursively inspect the selection to check if the user requested to resolve the `edges` field.
87
+ stack = []
88
+ for selection_field in info.selected_fields:
89
+ stack.extend(selection_field.selections)
90
+ while stack:
91
+ selection = stack.pop()
96
92
  if (
97
93
  not isinstance(selection, InlineFragment)
98
94
  and selection.name in resolve_for_field_names
99
95
  ):
100
96
  return True
101
- if selection.selections:
102
- return any(
103
- _check_selection(selection) for selection in selection.selections
104
- )
105
- return False
106
-
107
- for selection_field in info.selected_fields:
108
- for selection in selection_field.selections:
109
- if _check_selection(selection):
110
- return True
97
+ if nested_selections := getattr(selection, "selections", None):
98
+ stack.extend(nested_selections)
111
99
  return False
112
100
 
113
101
 
strawberry/resolvers.py CHANGED
@@ -1,4 +1,5 @@
1
- from typing import Any, Callable
1
+ from collections.abc import Callable
2
+ from typing import Any
2
3
 
3
4
 
4
5
  def is_default_resolver(func: Callable[..., Any]) -> bool:
@@ -2,6 +2,7 @@ import warnings
2
2
  from typing_extensions import TypedDict
3
3
 
4
4
  from sanic.request import Request
5
+
5
6
  from strawberry.http.temporal_response import TemporalResponse
6
7
 
7
8
 
strawberry/sanic/utils.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Optional, Union, cast
3
+ from typing import TYPE_CHECKING, Any, cast
4
4
 
5
5
  if TYPE_CHECKING:
6
6
  from sanic.request import File, Request
@@ -21,12 +21,12 @@ def convert_request_to_files_dict(request: Request) -> dict[str, Any]:
21
21
 
22
22
  Note that the dictionary entries are lists.
23
23
  """
24
- request_files = cast("Optional[dict[str, list[File]]]", request.files)
24
+ request_files = cast("dict[str, list[File]] | None", request.files)
25
25
 
26
26
  if not request_files:
27
27
  return {}
28
28
 
29
- files_dict: dict[str, Union[File, list[File]]] = {}
29
+ files_dict: dict[str, File | list[File]] = {}
30
30
 
31
31
  for field_name, file_list in request_files.items():
32
32
  assert len(file_list) == 1
strawberry/sanic/views.py CHANGED
@@ -5,70 +5,29 @@ import warnings
5
5
  from typing import (
6
6
  TYPE_CHECKING,
7
7
  Any,
8
- Callable,
9
- Optional,
10
- cast,
8
+ TypeGuard,
11
9
  )
12
- from typing_extensions import TypeGuard
13
10
 
11
+ from lia import HTTPException, SanicHTTPRequestAdapter
14
12
  from sanic.request import Request
15
13
  from sanic.response import HTTPResponse, html
16
14
  from sanic.views import HTTPMethodView
17
- from strawberry.http.async_base_view import AsyncBaseHTTPView, AsyncHTTPRequestAdapter
18
- from strawberry.http.exceptions import HTTPException
15
+
16
+ from strawberry.http.async_base_view import AsyncBaseHTTPView
19
17
  from strawberry.http.temporal_response import TemporalResponse
20
- from strawberry.http.types import FormData, HTTPMethod, QueryParams
21
18
  from strawberry.http.typevars import (
22
19
  Context,
23
20
  RootValue,
24
21
  )
25
- from strawberry.sanic.utils import convert_request_to_files_dict
26
22
 
27
23
  if TYPE_CHECKING:
28
- from collections.abc import AsyncGenerator, Mapping
24
+ from collections.abc import AsyncGenerator, Callable
29
25
 
30
26
  from strawberry.http import GraphQLHTTPResponse
31
27
  from strawberry.http.ides import GraphQL_IDE
32
28
  from strawberry.schema import BaseSchema
33
29
 
34
30
 
35
- class SanicHTTPRequestAdapter(AsyncHTTPRequestAdapter):
36
- def __init__(self, request: Request) -> None:
37
- self.request = request
38
-
39
- @property
40
- def query_params(self) -> QueryParams:
41
- # Just a heads up, Sanic's request.args uses urllib.parse.parse_qs
42
- # to parse query string parameters. This returns a dictionary where
43
- # the keys are the unique variable names and the values are lists
44
- # of values for each variable name. To ensure consistency, we're
45
- # enforcing the use of the first value in each list.
46
- args = self.request.get_args(keep_blank_values=True)
47
- return {k: args.get(k, None) for k in args}
48
-
49
- @property
50
- def method(self) -> HTTPMethod:
51
- return cast("HTTPMethod", self.request.method.upper())
52
-
53
- @property
54
- def headers(self) -> Mapping[str, str]:
55
- return self.request.headers
56
-
57
- @property
58
- def content_type(self) -> Optional[str]:
59
- return self.request.content_type
60
-
61
- async def get_body(self) -> str:
62
- return self.request.body.decode()
63
-
64
- async def get_form_data(self) -> FormData:
65
- assert self.request.form is not None
66
-
67
- files = convert_request_to_files_dict(self.request)
68
-
69
- return FormData(form=self.request.form, files=files)
70
-
71
-
72
31
  class GraphQLView(
73
32
  AsyncBaseHTTPView[
74
33
  Request,
@@ -104,11 +63,11 @@ class GraphQLView(
104
63
  def __init__(
105
64
  self,
106
65
  schema: BaseSchema,
107
- graphiql: Optional[bool] = None,
108
- graphql_ide: Optional[GraphQL_IDE] = "graphiql",
66
+ graphiql: bool | None = None,
67
+ graphql_ide: GraphQL_IDE | None = "graphiql",
109
68
  allow_queries_via_get: bool = True,
110
- json_encoder: Optional[type[json.JSONEncoder]] = None,
111
- json_dumps_params: Optional[dict[str, Any]] = None,
69
+ json_encoder: type[json.JSONEncoder] | None = None,
70
+ json_dumps_params: dict[str, Any] | None = None,
112
71
  multipart_uploads_enabled: bool = False,
113
72
  ) -> None:
114
73
  self.schema = schema
@@ -143,7 +102,7 @@ class GraphQLView(
143
102
  else:
144
103
  self.graphql_ide = graphql_ide
145
104
 
146
- async def get_root_value(self, request: Request) -> Optional[RootValue]:
105
+ async def get_root_value(self, request: Request) -> RootValue | None:
147
106
  return None
148
107
 
149
108
  async def get_context(
@@ -158,7 +117,9 @@ class GraphQLView(
158
117
  return TemporalResponse()
159
118
 
160
119
  def create_response(
161
- self, response_data: GraphQLHTTPResponse, sub_response: TemporalResponse
120
+ self,
121
+ response_data: GraphQLHTTPResponse | list[GraphQLHTTPResponse],
122
+ sub_response: TemporalResponse,
162
123
  ) -> HTTPResponse:
163
124
  status_code = sub_response.status_code
164
125
 
@@ -216,11 +177,11 @@ class GraphQLView(
216
177
  def is_websocket_request(self, request: Request) -> TypeGuard[Request]:
217
178
  return False
218
179
 
219
- async def pick_websocket_subprotocol(self, request: Request) -> Optional[str]:
180
+ async def pick_websocket_subprotocol(self, request: Request) -> str | None:
220
181
  raise NotImplementedError
221
182
 
222
183
  async def create_websocket_response(
223
- self, request: Request, subprotocol: Optional[str]
184
+ self, request: Request, subprotocol: str | None
224
185
  ) -> TemporalResponse:
225
186
  raise NotImplementedError
226
187
 
strawberry/scalars.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import base64
4
- from typing import TYPE_CHECKING, Any, NewType, Union
4
+ from typing import TYPE_CHECKING, Any, NewType
5
5
 
6
6
  from strawberry.types.scalar import scalar
7
7
 
@@ -59,7 +59,7 @@ Base64 = scalar(
59
59
 
60
60
  def is_scalar(
61
61
  annotation: Any,
62
- scalar_registry: Mapping[object, Union[ScalarWrapper, ScalarDefinition]],
62
+ scalar_registry: Mapping[object, ScalarWrapper | ScalarDefinition],
63
63
  ) -> bool:
64
64
  if annotation in scalar_registry:
65
65
  return True
@@ -0,0 +1,55 @@
1
+ from typing import TypeAlias, Union
2
+
3
+ from graphql.execution import ExecutionContext as GraphQLExecutionContext
4
+ from graphql.execution import ExecutionResult as OriginalGraphQLExecutionResult
5
+ from graphql.execution import execute, subscribe
6
+
7
+ from strawberry.types import ExecutionResult
8
+
9
+ try:
10
+ from graphql import ( # type: ignore[attr-defined]
11
+ ExperimentalIncrementalExecutionResults as GraphQLIncrementalExecutionResults,
12
+ )
13
+ from graphql.execution import ( # type: ignore[attr-defined]
14
+ InitialIncrementalExecutionResult,
15
+ experimental_execute_incrementally,
16
+ )
17
+ from graphql.type.directives import ( # type: ignore[attr-defined]
18
+ GraphQLDeferDirective,
19
+ GraphQLStreamDirective,
20
+ )
21
+
22
+ incremental_execution_directives = (
23
+ GraphQLDeferDirective,
24
+ GraphQLStreamDirective,
25
+ )
26
+
27
+ GraphQLExecutionResult: TypeAlias = (
28
+ OriginalGraphQLExecutionResult | InitialIncrementalExecutionResult
29
+ )
30
+
31
+ except ImportError:
32
+ GraphQLIncrementalExecutionResults = type(None)
33
+ GraphQLExecutionResult = OriginalGraphQLExecutionResult # type: ignore
34
+
35
+ incremental_execution_directives = () # type: ignore
36
+ experimental_execute_incrementally = None
37
+
38
+
39
+ # TODO: give this a better name, maybe also a better place
40
+ ResultType = Union[ # noqa: UP007
41
+ OriginalGraphQLExecutionResult,
42
+ GraphQLIncrementalExecutionResults,
43
+ ExecutionResult,
44
+ ]
45
+
46
+ __all__ = [
47
+ "GraphQLExecutionContext",
48
+ "GraphQLExecutionResult",
49
+ "GraphQLIncrementalExecutionResults",
50
+ "ResultType",
51
+ "execute",
52
+ "experimental_execute_incrementally",
53
+ "incremental_execution_directives",
54
+ "subscribe",
55
+ ]
strawberry/schema/base.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from abc import abstractmethod
4
- from typing import TYPE_CHECKING, Any, Optional, Union
4
+ from typing import TYPE_CHECKING, Any
5
5
  from typing_extensions import Protocol
6
6
 
7
7
  from strawberry.utils.logging import StrawberryLogger
@@ -34,33 +34,33 @@ class BaseSchema(Protocol):
34
34
  config: StrawberryConfig
35
35
  schema_converter: GraphQLCoreConverter
36
36
  query: type[WithStrawberryObjectDefinition]
37
- mutation: Optional[type[WithStrawberryObjectDefinition]]
38
- subscription: Optional[type[WithStrawberryObjectDefinition]]
37
+ mutation: type[WithStrawberryObjectDefinition] | None
38
+ subscription: type[WithStrawberryObjectDefinition] | None
39
39
  schema_directives: list[object]
40
40
 
41
41
  @abstractmethod
42
42
  async def execute(
43
43
  self,
44
- query: Optional[str],
45
- variable_values: Optional[dict[str, Any]] = None,
46
- context_value: Optional[Any] = None,
47
- root_value: Optional[Any] = None,
48
- operation_name: Optional[str] = None,
49
- allowed_operation_types: Optional[Iterable[OperationType]] = None,
50
- operation_extensions: Optional[dict[str, Any]] = None,
44
+ query: str | None,
45
+ variable_values: dict[str, Any] | None = None,
46
+ context_value: Any | None = None,
47
+ root_value: Any | None = None,
48
+ operation_name: str | None = None,
49
+ allowed_operation_types: Iterable[OperationType] | None = None,
50
+ operation_extensions: dict[str, Any] | None = None,
51
51
  ) -> ExecutionResult:
52
52
  raise NotImplementedError
53
53
 
54
54
  @abstractmethod
55
55
  def execute_sync(
56
56
  self,
57
- query: Optional[str],
58
- variable_values: Optional[dict[str, Any]] = None,
59
- context_value: Optional[Any] = None,
60
- root_value: Optional[Any] = None,
61
- operation_name: Optional[str] = None,
62
- allowed_operation_types: Optional[Iterable[OperationType]] = None,
63
- operation_extensions: Optional[dict[str, Any]] = None,
57
+ query: str | None,
58
+ variable_values: dict[str, Any] | None = None,
59
+ context_value: Any | None = None,
60
+ root_value: Any | None = None,
61
+ operation_name: str | None = None,
62
+ allowed_operation_types: Iterable[OperationType] | None = None,
63
+ operation_extensions: dict[str, Any] | None = None,
64
64
  ) -> ExecutionResult:
65
65
  raise NotImplementedError
66
66
 
@@ -68,29 +68,28 @@ class BaseSchema(Protocol):
68
68
  async def subscribe(
69
69
  self,
70
70
  query: str,
71
- variable_values: Optional[dict[str, Any]] = None,
72
- context_value: Optional[Any] = None,
73
- root_value: Optional[Any] = None,
74
- operation_name: Optional[str] = None,
75
- operation_extensions: Optional[dict[str, Any]] = None,
71
+ variable_values: dict[str, Any] | None = None,
72
+ context_value: Any | None = None,
73
+ root_value: Any | None = None,
74
+ operation_name: str | None = None,
75
+ operation_extensions: dict[str, Any] | None = None,
76
76
  ) -> SubscriptionResult:
77
77
  raise NotImplementedError
78
78
 
79
79
  @abstractmethod
80
80
  def get_type_by_name(
81
81
  self, name: str
82
- ) -> Optional[
83
- Union[
84
- StrawberryObjectDefinition,
85
- ScalarDefinition,
86
- EnumDefinition,
87
- StrawberryUnion,
88
- ]
89
- ]:
82
+ ) -> (
83
+ StrawberryObjectDefinition
84
+ | ScalarDefinition
85
+ | EnumDefinition
86
+ | StrawberryUnion
87
+ | None
88
+ ):
90
89
  raise NotImplementedError
91
90
 
92
91
  @abstractmethod
93
- def get_directive_by_name(self, graphql_name: str) -> Optional[StrawberryDirective]:
92
+ def get_directive_by_name(self, graphql_name: str) -> StrawberryDirective | None:
94
93
  raise NotImplementedError
95
94
 
96
95
  @abstractmethod
@@ -108,7 +107,7 @@ class BaseSchema(Protocol):
108
107
  def _process_errors(
109
108
  self,
110
109
  errors: list[GraphQLError],
111
- execution_context: Optional[ExecutionContext] = None,
110
+ execution_context: ExecutionContext | None = None,
112
111
  ) -> None:
113
112
  if self.config.disable_field_suggestions:
114
113
  for error in errors:
@@ -119,7 +118,7 @@ class BaseSchema(Protocol):
119
118
  def process_errors(
120
119
  self,
121
120
  errors: list[GraphQLError],
122
- execution_context: Optional[ExecutionContext] = None,
121
+ execution_context: ExecutionContext | None = None,
123
122
  ) -> None:
124
123
  for error in errors:
125
124
  StrawberryLogger.error(error, execution_context)
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Union
3
+ from typing import TYPE_CHECKING
4
4
 
5
5
  from strawberry.scalars import is_scalar as is_strawberry_scalar
6
6
  from strawberry.types.base import StrawberryType, has_object_definition
@@ -11,40 +11,40 @@ from strawberry.types.base import StrawberryType, has_object_definition
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from collections.abc import Mapping
14
- from typing_extensions import TypeGuard
14
+ from typing import TypeGuard
15
15
 
16
16
  from strawberry.types.scalar import ScalarDefinition, ScalarWrapper
17
17
 
18
18
 
19
- def is_input_type(type_: Union[StrawberryType, type]) -> TypeGuard[type]:
19
+ def is_input_type(type_: StrawberryType | type) -> TypeGuard[type]:
20
20
  if not has_object_definition(type_):
21
21
  return False
22
22
  return type_.__strawberry_definition__.is_input
23
23
 
24
24
 
25
- def is_interface_type(type_: Union[StrawberryType, type]) -> TypeGuard[type]:
25
+ def is_interface_type(type_: StrawberryType | type) -> TypeGuard[type]:
26
26
  if not has_object_definition(type_):
27
27
  return False
28
28
  return type_.__strawberry_definition__.is_interface
29
29
 
30
30
 
31
31
  def is_scalar(
32
- type_: Union[StrawberryType, type],
33
- scalar_registry: Mapping[object, Union[ScalarWrapper, ScalarDefinition]],
32
+ type_: StrawberryType | type,
33
+ scalar_registry: Mapping[object, ScalarWrapper | ScalarDefinition],
34
34
  ) -> TypeGuard[type]:
35
35
  return is_strawberry_scalar(type_, scalar_registry)
36
36
 
37
37
 
38
- def is_enum(type_: Union[StrawberryType, type]) -> TypeGuard[type]:
38
+ def is_enum(type_: StrawberryType | type) -> TypeGuard[type]:
39
39
  return hasattr(type_, "_enum_definition")
40
40
 
41
41
 
42
- def is_schema_directive(type_: Union[StrawberryType, type]) -> TypeGuard[type]:
42
+ def is_schema_directive(type_: StrawberryType | type) -> TypeGuard[type]:
43
43
  return hasattr(type_, "__strawberry_directive__")
44
44
 
45
45
 
46
46
  # TODO: do we still need this?
47
- def is_graphql_generic(type_: Union[StrawberryType, type]) -> bool:
47
+ def is_graphql_generic(type_: StrawberryType | type) -> bool:
48
48
  if has_object_definition(type_):
49
49
  return type_.__strawberry_definition__.is_graphql_generic
50
50
 
@@ -1,12 +1,19 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import InitVar, dataclass, field
4
- from typing import Any, Callable
4
+ from typing import TYPE_CHECKING, Any, TypedDict
5
5
 
6
6
  from strawberry.types.info import Info
7
7
 
8
8
  from .name_converter import NameConverter
9
9
 
10
+ if TYPE_CHECKING:
11
+ from collections.abc import Callable
12
+
13
+
14
+ class BatchingConfig(TypedDict):
15
+ max_operations: int
16
+
10
17
 
11
18
  @dataclass
12
19
  class StrawberryConfig:
@@ -17,7 +24,9 @@ class StrawberryConfig:
17
24
  relay_use_legacy_global_id: bool = False
18
25
  disable_field_suggestions: bool = False
19
26
  info_class: type[Info] = Info
27
+ enable_experimental_incremental_execution: bool = False
20
28
  _unsafe_disable_same_type_validation: bool = False
29
+ batching_config: BatchingConfig | None = None
21
30
 
22
31
  def __post_init__(
23
32
  self,
@@ -1,12 +1,10 @@
1
- from typing import Optional
2
-
3
1
  from strawberry.types.graphql import OperationType
4
2
 
5
3
 
6
4
  class CannotGetOperationTypeError(Exception):
7
5
  """Internal error raised when we cannot get the operation type from a GraphQL document."""
8
6
 
9
- def __init__(self, operation_name: Optional[str]) -> None:
7
+ def __init__(self, operation_name: str | None) -> None:
10
8
  self.operation_name = operation_name
11
9
 
12
10
  def as_http_error_reason(self) -> str:
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Optional, Union, cast
3
+ from typing import TYPE_CHECKING, cast
4
4
  from typing_extensions import Protocol
5
5
 
6
6
  from strawberry.directive import StrawberryDirective
@@ -26,7 +26,7 @@ if TYPE_CHECKING:
26
26
 
27
27
  class HasGraphQLName(Protocol):
28
28
  python_name: str
29
- graphql_name: Optional[str]
29
+ graphql_name: str | None
30
30
 
31
31
 
32
32
  class NameConverter:
@@ -41,7 +41,7 @@ class NameConverter:
41
41
 
42
42
  def from_type(
43
43
  self,
44
- type_: Union[StrawberryType, StrawberryDirective],
44
+ type_: StrawberryType | StrawberryDirective,
45
45
  ) -> str:
46
46
  if isinstance(type_, (StrawberryDirective, StrawberrySchemaDirective)):
47
47
  return self.from_directive(type_)
@@ -85,7 +85,7 @@ class NameConverter:
85
85
  return enum_value.name
86
86
 
87
87
  def from_directive(
88
- self, directive: Union[StrawberryDirective, StrawberrySchemaDirective]
88
+ self, directive: StrawberryDirective | StrawberrySchemaDirective
89
89
  ) -> str:
90
90
  name = self.get_graphql_name(directive)
91
91
 
@@ -134,7 +134,7 @@ class NameConverter:
134
134
  def from_generic(
135
135
  self,
136
136
  generic_type: StrawberryObjectDefinition,
137
- types: list[Union[StrawberryType, type]],
137
+ types: list[StrawberryType | type],
138
138
  ) -> str:
139
139
  generic_type_name = generic_type.name
140
140
 
@@ -146,12 +146,13 @@ class NameConverter:
146
146
 
147
147
  return "".join(names) + generic_type_name
148
148
 
149
- def get_name_from_type(self, type_: Union[StrawberryType, type]) -> str:
149
+ def get_name_from_type(self, type_: StrawberryType | type) -> str:
150
150
  type_ = eval_type(type_)
151
151
 
152
152
  if isinstance(type_, LazyType):
153
- name = type_.type_name
154
- elif isinstance(type_, EnumDefinition):
153
+ type_ = type_.resolve_type()
154
+
155
+ if isinstance(type_, EnumDefinition):
155
156
  name = type_.name
156
157
  elif isinstance(type_, StrawberryUnion):
157
158
  name = type_.graphql_name if type_.graphql_name else self.from_union(type_)