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
@@ -1,56 +1,21 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import warnings
4
- from typing import TYPE_CHECKING, Any, Optional, Union, cast
4
+ from typing import TYPE_CHECKING
5
5
 
6
6
  from chalice.app import Request, Response
7
- from strawberry.http.exceptions import HTTPException
8
- from strawberry.http.sync_base_view import SyncBaseHTTPView, SyncHTTPRequestAdapter
7
+ from lia import ChaliceHTTPRequestAdapter, HTTPException
8
+
9
+ from strawberry.http.sync_base_view import SyncBaseHTTPView
9
10
  from strawberry.http.temporal_response import TemporalResponse
10
11
  from strawberry.http.typevars import Context, RootValue
11
12
 
12
13
  if TYPE_CHECKING:
13
- from collections.abc import Mapping
14
-
15
14
  from strawberry.http import GraphQLHTTPResponse
16
15
  from strawberry.http.ides import GraphQL_IDE
17
- from strawberry.http.types import HTTPMethod, QueryParams
18
16
  from strawberry.schema import BaseSchema
19
17
 
20
18
 
21
- class ChaliceHTTPRequestAdapter(SyncHTTPRequestAdapter):
22
- def __init__(self, request: Request) -> None:
23
- self.request = request
24
-
25
- @property
26
- def query_params(self) -> QueryParams:
27
- return self.request.query_params or {}
28
-
29
- @property
30
- def body(self) -> Union[str, bytes]:
31
- return self.request.raw_body
32
-
33
- @property
34
- def method(self) -> HTTPMethod:
35
- return cast("HTTPMethod", self.request.method.upper())
36
-
37
- @property
38
- def headers(self) -> Mapping[str, str]:
39
- return self.request.headers
40
-
41
- @property
42
- def post_data(self) -> Mapping[str, Union[str, bytes]]:
43
- raise NotImplementedError
44
-
45
- @property
46
- def files(self) -> Mapping[str, Any]:
47
- raise NotImplementedError
48
-
49
- @property
50
- def content_type(self) -> Optional[str]:
51
- return self.request.headers.get("Content-Type", None)
52
-
53
-
54
19
  class GraphQLView(
55
20
  SyncBaseHTTPView[Request, Response, TemporalResponse, Context, RootValue]
56
21
  ):
@@ -60,8 +25,8 @@ class GraphQLView(
60
25
  def __init__(
61
26
  self,
62
27
  schema: BaseSchema,
63
- graphiql: Optional[bool] = None,
64
- graphql_ide: Optional[GraphQL_IDE] = "graphiql",
28
+ graphiql: bool | None = None,
29
+ graphql_ide: GraphQL_IDE | None = "graphiql",
65
30
  allow_queries_via_get: bool = True,
66
31
  ) -> None:
67
32
  self.allow_queries_via_get = allow_queries_via_get
@@ -76,7 +41,7 @@ class GraphQLView(
76
41
  else:
77
42
  self.graphql_ide = graphql_ide
78
43
 
79
- def get_root_value(self, request: Request) -> Optional[RootValue]:
44
+ def get_root_value(self, request: Request) -> RootValue | None:
80
45
  return None
81
46
 
82
47
  def render_graphql_ide(self, request: Request) -> Response:
@@ -88,33 +53,13 @@ class GraphQLView(
88
53
  def get_sub_response(self, request: Request) -> TemporalResponse:
89
54
  return TemporalResponse()
90
55
 
91
- @staticmethod
92
- def error_response(
93
- message: str,
94
- error_code: str,
95
- http_status_code: int,
96
- headers: Optional[dict[str, str | list[str]]] = None,
97
- ) -> Response:
98
- """A wrapper for error responses.
99
-
100
- Args:
101
- message: The error message.
102
- error_code: The error code.
103
- http_status_code: The HTTP status code.
104
- headers: The headers to include in the response.
105
-
106
- Returns:
107
- An errors response.
108
- """
109
- body = {"Code": error_code, "Message": message}
110
-
111
- return Response(body=body, status_code=http_status_code, headers=headers)
112
-
113
56
  def get_context(self, request: Request, response: TemporalResponse) -> Context:
114
57
  return {"request": request, "response": response} # type: ignore
115
58
 
116
59
  def create_response(
117
- self, response_data: GraphQLHTTPResponse, sub_response: TemporalResponse
60
+ self,
61
+ response_data: GraphQLHTTPResponse | list[GraphQLHTTPResponse],
62
+ sub_response: TemporalResponse,
118
63
  ) -> Response:
119
64
  status_code = 200
120
65
 
@@ -134,20 +79,9 @@ class GraphQLView(
134
79
  try:
135
80
  return self.run(request=request)
136
81
  except HTTPException as e:
137
- error_code_map = {
138
- 400: "BadRequestError",
139
- 401: "UnauthorizedError",
140
- 403: "ForbiddenError",
141
- 404: "NotFoundError",
142
- 409: "ConflictError",
143
- 429: "TooManyRequestsError",
144
- 500: "ChaliceViewError",
145
- }
146
-
147
- return self.error_response(
148
- error_code=error_code_map.get(e.status_code, "ChaliceViewError"),
149
- message=e.reason,
150
- http_status_code=e.status_code,
82
+ return Response(
83
+ body=e.reason,
84
+ status_code=e.status_code,
151
85
  )
152
86
 
153
87
 
@@ -2,13 +2,12 @@ import asyncio
2
2
  import contextlib
3
3
  import warnings
4
4
  from collections import defaultdict
5
- from collections.abc import AsyncGenerator, Awaitable, Sequence
5
+ from collections.abc import AsyncGenerator, Awaitable, Callable, Sequence
6
6
  from typing import (
7
7
  Any,
8
- Callable,
9
- Optional,
8
+ Literal,
10
9
  )
11
- from typing_extensions import Literal, Protocol, TypedDict
10
+ from typing_extensions import Protocol, TypedDict
12
11
  from weakref import WeakSet
13
12
 
14
13
  from channels.consumer import AsyncConsumer
@@ -54,7 +53,7 @@ class ChannelsConsumer(AsyncConsumer):
54
53
  """Base channels async consumer."""
55
54
 
56
55
  channel_name: str
57
- channel_layer: Optional[ChannelsLayer]
56
+ channel_layer: ChannelsLayer | None
58
57
  channel_receive: Callable[[], Awaitable[dict]]
59
58
 
60
59
  def __init__(self, *args: str, **kwargs: Any) -> None:
@@ -80,7 +79,7 @@ class ChannelsConsumer(AsyncConsumer):
80
79
  self,
81
80
  type: str,
82
81
  *,
83
- timeout: Optional[float] = None,
82
+ timeout: float | None = None,
84
83
  groups: Sequence[str] = (),
85
84
  ) -> AsyncGenerator[Any, None]:
86
85
  """Listen for messages sent to this consumer.
@@ -139,7 +138,7 @@ class ChannelsConsumer(AsyncConsumer):
139
138
  self,
140
139
  type: str,
141
140
  *,
142
- timeout: Optional[float] = None,
141
+ timeout: float | None = None,
143
142
  groups: Sequence[str] = (),
144
143
  ) -> AsyncGenerator[Any, None]:
145
144
  """Listen for messages sent to this consumer.
@@ -188,7 +187,7 @@ class ChannelsConsumer(AsyncConsumer):
188
187
  await self.channel_layer.group_discard(group, self.channel_name)
189
188
 
190
189
  async def _listen_to_channel_generator(
191
- self, queue: asyncio.Queue, timeout: Optional[float]
190
+ self, queue: asyncio.Queue, timeout: float | None
192
191
  ) -> AsyncGenerator[Any, None]:
193
192
  """Generator for listen_to_channel method.
194
193
 
@@ -5,34 +5,27 @@ import json
5
5
  import warnings
6
6
  from functools import cached_property
7
7
  from io import BytesIO
8
- from typing import (
9
- TYPE_CHECKING,
10
- Any,
11
- Callable,
12
- Optional,
13
- Union,
14
- )
15
- from typing_extensions import TypeGuard, assert_never
8
+ from typing import TYPE_CHECKING, Any, TypeGuard
9
+ from typing_extensions import assert_never
16
10
  from urllib.parse import parse_qs
17
11
 
12
+ from channels.db import database_sync_to_async
13
+ from channels.generic.http import AsyncHttpConsumer
18
14
  from django.conf import settings
19
15
  from django.core.files import uploadhandler
20
16
  from django.http.multipartparser import MultiPartParser
17
+ from lia import AsyncHTTPRequestAdapter, FormData, HTTPException, SyncHTTPRequestAdapter
21
18
 
22
- from channels.db import database_sync_to_async
23
- from channels.generic.http import AsyncHttpConsumer
24
- from strawberry.http.async_base_view import AsyncBaseHTTPView, AsyncHTTPRequestAdapter
25
- from strawberry.http.exceptions import HTTPException
26
- from strawberry.http.sync_base_view import SyncBaseHTTPView, SyncHTTPRequestAdapter
19
+ from strawberry.http.async_base_view import AsyncBaseHTTPView
20
+ from strawberry.http.sync_base_view import SyncBaseHTTPView
27
21
  from strawberry.http.temporal_response import TemporalResponse
28
- from strawberry.http.types import FormData
29
22
  from strawberry.http.typevars import Context, RootValue
30
23
  from strawberry.types.unset import UNSET
31
24
 
32
25
  from .base import ChannelsConsumer
33
26
 
34
27
  if TYPE_CHECKING:
35
- from collections.abc import AsyncGenerator, Mapping
28
+ from collections.abc import AsyncGenerator, Callable, Mapping
36
29
 
37
30
  from strawberry.http import GraphQLHTTPResponse
38
31
  from strawberry.http.ides import GraphQL_IDE
@@ -84,7 +77,7 @@ class ChannelsRequest:
84
77
  return self.consumer.scope["method"].upper()
85
78
 
86
79
  @property
87
- def content_type(self) -> Optional[str]:
80
+ def content_type(self) -> str | None:
88
81
  return self.headers.get("content-type", None)
89
82
 
90
83
  @cached_property
@@ -130,9 +123,31 @@ class BaseChannelsRequestAdapter:
130
123
  return self.request.headers
131
124
 
132
125
  @property
133
- def content_type(self) -> Optional[str]:
126
+ def content_type(self) -> str | None:
134
127
  return self.request.content_type
135
128
 
129
+ @property
130
+ def url(self) -> str:
131
+ scheme = self.request.consumer.scope["scheme"]
132
+ host = self.headers.get("host", "localhost")
133
+ path = self.request.consumer.scope["path"]
134
+ query_string = self.request.consumer.scope["query_string"]
135
+ url = f"{scheme}://{host}{path}"
136
+ if query_string:
137
+ url += f"?{query_string.decode()}"
138
+ return url
139
+
140
+ @property
141
+ def cookies(self) -> Mapping[str, str]:
142
+ cookie_header = self.headers.get("cookie", "")
143
+ cookies = {}
144
+ if cookie_header:
145
+ for cookie in cookie_header.split(";"):
146
+ if "=" in cookie:
147
+ key, value = cookie.split("=", 1)
148
+ cookies[key.strip()] = value.strip()
149
+ return cookies
150
+
136
151
 
137
152
  class ChannelsRequestAdapter(BaseChannelsRequestAdapter, AsyncHTTPRequestAdapter):
138
153
  async def get_body(self) -> bytes:
@@ -148,23 +163,26 @@ class SyncChannelsRequestAdapter(BaseChannelsRequestAdapter, SyncHTTPRequestAdap
148
163
  return self.request.body
149
164
 
150
165
  @property
151
- def post_data(self) -> Mapping[str, Union[str, bytes]]:
152
- return self.request.form_data["form"]
166
+ def post_data(self) -> Mapping[str, str | bytes]:
167
+ return self.request.form_data.form
153
168
 
154
169
  @property
155
170
  def files(self) -> Mapping[str, Any]:
156
- return self.request.form_data["files"]
171
+ return self.request.form_data.files
172
+
173
+ def get_form_data(self) -> FormData:
174
+ return self.request.form_data
157
175
 
158
176
 
159
177
  class BaseGraphQLHTTPConsumer(ChannelsConsumer, AsyncHttpConsumer):
160
178
  graphql_ide_html: str
161
- graphql_ide: Optional[GraphQL_IDE] = "graphiql"
179
+ graphql_ide: GraphQL_IDE | None = "graphiql"
162
180
 
163
181
  def __init__(
164
182
  self,
165
183
  schema: BaseSchema,
166
- graphiql: Optional[bool] = None,
167
- graphql_ide: Optional[GraphQL_IDE] = "graphiql",
184
+ graphiql: bool | None = None,
185
+ graphql_ide: GraphQL_IDE | None = "graphiql",
168
186
  allow_queries_via_get: bool = True,
169
187
  multipart_uploads_enabled: bool = False,
170
188
  **kwargs: Any,
@@ -186,7 +204,9 @@ class BaseGraphQLHTTPConsumer(ChannelsConsumer, AsyncHttpConsumer):
186
204
  super().__init__(**kwargs)
187
205
 
188
206
  def create_response(
189
- self, response_data: GraphQLHTTPResponse, sub_response: TemporalResponse
207
+ self,
208
+ response_data: GraphQLHTTPResponse | list[GraphQLHTTPResponse],
209
+ sub_response: TemporalResponse,
190
210
  ) -> ChannelsResponse:
191
211
  return ChannelsResponse(
192
212
  content=json.dumps(response_data).encode(),
@@ -227,7 +247,7 @@ class GraphQLHTTPConsumer(
227
247
  BaseGraphQLHTTPConsumer,
228
248
  AsyncBaseHTTPView[
229
249
  ChannelsRequest,
230
- Union[ChannelsResponse, MultipartChannelsResponse],
250
+ ChannelsResponse | MultipartChannelsResponse,
231
251
  TemporalResponse,
232
252
  ChannelsRequest,
233
253
  TemporalResponse,
@@ -259,7 +279,7 @@ class GraphQLHTTPConsumer(
259
279
  allow_queries_via_get: bool = True
260
280
  request_adapter_class = ChannelsRequestAdapter
261
281
 
262
- async def get_root_value(self, request: ChannelsRequest) -> Optional[RootValue]:
282
+ async def get_root_value(self, request: ChannelsRequest) -> RootValue | None:
263
283
  return None # pragma: no cover
264
284
 
265
285
  async def get_context(
@@ -302,13 +322,11 @@ class GraphQLHTTPConsumer(
302
322
  ) -> TypeGuard[ChannelsRequest]:
303
323
  return False
304
324
 
305
- async def pick_websocket_subprotocol(
306
- self, request: ChannelsRequest
307
- ) -> Optional[str]:
325
+ async def pick_websocket_subprotocol(self, request: ChannelsRequest) -> str | None:
308
326
  return None
309
327
 
310
328
  async def create_websocket_response(
311
- self, request: ChannelsRequest, subprotocol: Optional[str]
329
+ self, request: ChannelsRequest, subprotocol: str | None
312
330
  ) -> TemporalResponse:
313
331
  raise NotImplementedError
314
332
 
@@ -333,7 +351,7 @@ class SyncGraphQLHTTPConsumer(
333
351
  allow_queries_via_get: bool = True
334
352
  request_adapter_class = SyncChannelsRequestAdapter
335
353
 
336
- def get_root_value(self, request: ChannelsRequest) -> Optional[RootValue]:
354
+ def get_root_value(self, request: ChannelsRequest) -> RootValue | None:
337
355
  return None # pragma: no cover
338
356
 
339
357
  def get_context(
@@ -361,7 +379,7 @@ class SyncGraphQLHTTPConsumer(
361
379
  self,
362
380
  request: ChannelsRequest,
363
381
  context: Context = UNSET,
364
- root_value: Optional[RootValue] = UNSET,
382
+ root_value: RootValue | None = UNSET,
365
383
  ) -> ChannelsResponse | MultipartChannelsResponse:
366
384
  return super().run(request, context, root_value)
367
385
 
@@ -5,11 +5,9 @@ import datetime
5
5
  import json
6
6
  from typing import (
7
7
  TYPE_CHECKING,
8
- Optional,
9
8
  TypedDict,
10
- Union,
9
+ TypeGuard,
11
10
  )
12
- from typing_extensions import TypeGuard
13
11
 
14
12
  from strawberry.http.async_base_view import AsyncBaseHTTPView, AsyncWebSocketAdapter
15
13
  from strawberry.http.exceptions import NonJsonMessageReceived, NonTextMessageReceived
@@ -62,7 +60,7 @@ class ChannelsWebSocketAdapter(AsyncWebSocketAdapter):
62
60
 
63
61
 
64
62
  class MessageQueueData(TypedDict):
65
- message: Union[str, None]
63
+ message: str | None
66
64
  disconnected: bool
67
65
 
68
66
 
@@ -102,19 +100,18 @@ class GraphQLWSConsumer(
102
100
  ```
103
101
  """
104
102
 
105
- websocket_adapter_class = ChannelsWebSocketAdapter
103
+ websocket_adapter_class = ChannelsWebSocketAdapter # type: ignore
106
104
 
107
105
  def __init__(
108
106
  self,
109
107
  schema: BaseSchema,
110
108
  keep_alive: bool = False,
111
109
  keep_alive_interval: float = 1,
112
- debug: bool = False,
113
110
  subscription_protocols: Sequence[str] = (
114
111
  GRAPHQL_TRANSPORT_WS_PROTOCOL,
115
112
  GRAPHQL_WS_PROTOCOL,
116
113
  ),
117
- connection_init_wait_timeout: Optional[datetime.timedelta] = None,
114
+ connection_init_wait_timeout: datetime.timedelta | None = None,
118
115
  ) -> None:
119
116
  if connection_init_wait_timeout is None:
120
117
  connection_init_wait_timeout = datetime.timedelta(minutes=1)
@@ -122,10 +119,9 @@ class GraphQLWSConsumer(
122
119
  self.schema = schema
123
120
  self.keep_alive = keep_alive
124
121
  self.keep_alive_interval = keep_alive_interval
125
- self.debug = debug
126
122
  self.protocols = subscription_protocols
127
123
  self.message_queue: asyncio.Queue[MessageQueueData] = asyncio.Queue()
128
- self.run_task: Optional[asyncio.Task] = None
124
+ self.run_task: asyncio.Task | None = None
129
125
 
130
126
  super().__init__()
131
127
 
@@ -133,7 +129,7 @@ class GraphQLWSConsumer(
133
129
  self.run_task = asyncio.create_task(self.run(self))
134
130
 
135
131
  async def receive(
136
- self, text_data: Optional[str] = None, bytes_data: Optional[bytes] = None
132
+ self, text_data: str | None = None, bytes_data: bytes | None = None
137
133
  ) -> None:
138
134
  if text_data:
139
135
  self.message_queue.put_nowait({"message": text_data, "disconnected": False})
@@ -145,7 +141,7 @@ class GraphQLWSConsumer(
145
141
  assert self.run_task
146
142
  await self.run_task
147
143
 
148
- async def get_root_value(self, request: GraphQLWSConsumer) -> Optional[RootValue]:
144
+ async def get_root_value(self, request: GraphQLWSConsumer) -> RootValue | None:
149
145
  return None
150
146
 
151
147
  async def get_context(
@@ -164,7 +160,9 @@ class GraphQLWSConsumer(
164
160
  raise NotImplementedError
165
161
 
166
162
  def create_response(
167
- self, response_data: GraphQLHTTPResponse, sub_response: GraphQLWSConsumer
163
+ self,
164
+ response_data: GraphQLHTTPResponse | list[GraphQLHTTPResponse],
165
+ sub_response: GraphQLWSConsumer,
168
166
  ) -> GraphQLWSConsumer:
169
167
  raise NotImplementedError
170
168
 
@@ -178,14 +176,14 @@ class GraphQLWSConsumer(
178
176
 
179
177
  async def pick_websocket_subprotocol(
180
178
  self, request: GraphQLWSConsumer
181
- ) -> Optional[str]:
179
+ ) -> str | None:
182
180
  protocols = request.scope["subprotocols"]
183
181
  intersection = set(protocols) & set(self.protocols)
184
182
  sorted_intersection = sorted(intersection, key=protocols.index)
185
183
  return next(iter(sorted_intersection), None)
186
184
 
187
185
  async def create_websocket_response(
188
- self, request: GraphQLWSConsumer, subprotocol: Optional[str]
186
+ self, request: GraphQLWSConsumer, subprotocol: str | None
189
187
  ) -> GraphQLWSConsumer:
190
188
  await request.accept(subprotocol=subprotocol)
191
189
  return request
@@ -7,11 +7,10 @@ on preferences and client support. Then it hands off to the appropriate consumer
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from typing import TYPE_CHECKING, Optional
11
-
12
- from django.urls import re_path
10
+ from typing import TYPE_CHECKING
13
11
 
14
12
  from channels.routing import ProtocolTypeRouter, URLRouter
13
+ from django.urls import re_path
15
14
 
16
15
  from .handlers.http_handler import GraphQLHTTPConsumer
17
16
  from .handlers.ws_handler import GraphQLWSConsumer
@@ -47,7 +46,7 @@ class GraphQLProtocolTypeRouter(ProtocolTypeRouter):
47
46
  def __init__(
48
47
  self,
49
48
  schema: BaseSchema,
50
- django_application: Optional[str] = None,
49
+ django_application: str | None = None,
51
50
  url_pattern: str = "^graphql",
52
51
  ) -> None:
53
52
  http_urls = [re_path(url_pattern, GraphQLHTTPConsumer.as_asgi(schema=schema))]
@@ -4,13 +4,11 @@ import uuid
4
4
  from typing import (
5
5
  TYPE_CHECKING,
6
6
  Any,
7
- Optional,
8
- Union,
9
7
  )
10
8
 
9
+ from channels.testing.websocket import WebsocketCommunicator
11
10
  from graphql import GraphQLError, GraphQLFormattedError
12
11
 
13
- from channels.testing.websocket import WebsocketCommunicator
14
12
  from strawberry.subscriptions import GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL
15
13
  from strawberry.subscriptions.protocols.graphql_transport_ws import (
16
14
  types as transport_ws_types,
@@ -53,7 +51,7 @@ class GraphQLWebsocketCommunicator(WebsocketCommunicator):
53
51
  self,
54
52
  application: ASGIApplication,
55
53
  path: str,
56
- headers: Optional[list[tuple[bytes, bytes]]] = None,
54
+ headers: list[tuple[bytes, bytes]] | None = None,
57
55
  protocol: str = GRAPHQL_TRANSPORT_WS_PROTOCOL,
58
56
  connection_params: dict | None = None,
59
57
  **kwargs: Any,
@@ -83,9 +81,9 @@ class GraphQLWebsocketCommunicator(WebsocketCommunicator):
83
81
 
84
82
  async def __aexit__(
85
83
  self,
86
- exc_type: Optional[type[BaseException]],
87
- exc_val: Optional[BaseException],
88
- exc_tb: Optional[TracebackType],
84
+ exc_type: type[BaseException] | None,
85
+ exc_val: BaseException | None,
86
+ exc_tb: TracebackType | None,
89
87
  ) -> None:
90
88
  await self.disconnect()
91
89
 
@@ -114,8 +112,8 @@ class GraphQLWebsocketCommunicator(WebsocketCommunicator):
114
112
  # get transformed into `FormattedExecutionResult` on the wire, but we attempt
115
113
  # to do a limited representation of them here, to make testing simpler.
116
114
  async def subscribe(
117
- self, query: str, variables: Optional[dict] = None
118
- ) -> Union[ExecutionResult, AsyncIterator[ExecutionResult]]:
115
+ self, query: str, variables: dict | None = None
116
+ ) -> ExecutionResult | AsyncIterator[ExecutionResult]:
119
117
  id_ = uuid.uuid4().hex
120
118
 
121
119
  if self.protocol == GRAPHQL_TRANSPORT_WS_PROTOCOL:
@@ -1,15 +1,16 @@
1
1
  try:
2
2
  from .app import app
3
- from .commands.codegen import codegen as codegen # noqa: PLC0414
4
- from .commands.export_schema import export_schema as export_schema # noqa: PLC0414
3
+ from .commands.codegen import codegen as codegen
4
+ from .commands.dev import dev as dev
5
+ from .commands.export_schema import export_schema as export_schema
5
6
  from .commands.locate_definition import (
6
- locate_definition as locate_definition, # noqa: PLC0414
7
+ locate_definition as locate_definition,
7
8
  )
8
9
  from .commands.schema_codegen import (
9
- schema_codegen as schema_codegen, # noqa: PLC0414
10
+ schema_codegen as schema_codegen,
10
11
  )
11
- from .commands.server import server as server # noqa: PLC0414
12
- from .commands.upgrade import upgrade as upgrade # noqa: PLC0414
12
+ from .commands.server import server as server
13
+ from .commands.upgrade import upgrade as upgrade
13
14
 
14
15
  def run() -> None:
15
16
  app()
@@ -4,7 +4,7 @@ import functools
4
4
  import importlib
5
5
  import inspect
6
6
  from pathlib import Path # noqa: TC003
7
- from typing import Optional, Union, cast
7
+ from typing import cast
8
8
 
9
9
  import rich
10
10
  import typer
@@ -22,9 +22,9 @@ def _is_codegen_plugin(obj: object) -> bool:
22
22
  )
23
23
 
24
24
 
25
- def _import_plugin(plugin: str) -> Optional[type[QueryCodegenPlugin]]:
25
+ def _import_plugin(plugin: str) -> type[QueryCodegenPlugin] | None:
26
26
  module_name = plugin
27
- symbol_name: Optional[str] = None
27
+ symbol_name: str | None = None
28
28
 
29
29
  if ":" in plugin:
30
30
  module_name, symbol_name = plugin.split(":", 1)
@@ -61,7 +61,7 @@ def _import_plugin(plugin: str) -> Optional[type[QueryCodegenPlugin]]:
61
61
  @functools.lru_cache
62
62
  def _load_plugin(
63
63
  plugin_path: str,
64
- ) -> type[Union[QueryCodegenPlugin, ConsolePlugin]]:
64
+ ) -> type[QueryCodegenPlugin | ConsolePlugin]:
65
65
  # try to import plugin_name from current folder
66
66
  # then try to import from strawberry.codegen.plugins
67
67
 
@@ -79,7 +79,7 @@ def _load_plugin(
79
79
 
80
80
  def _load_plugins(
81
81
  plugin_ids: list[str], query: Path
82
- ) -> list[Union[QueryCodegenPlugin, ConsolePlugin]]:
82
+ ) -> list[QueryCodegenPlugin | ConsolePlugin]:
83
83
  plugins = []
84
84
  for ptype_id in plugin_ids:
85
85
  ptype = _load_plugin(ptype_id)
@@ -91,7 +91,7 @@ def _load_plugins(
91
91
 
92
92
  @app.command(help="Generate code from a query")
93
93
  def codegen(
94
- query: Optional[list[Path]] = typer.Argument(
94
+ query: list[Path] | None = typer.Argument(
95
95
  default=None, exists=True, dir_okay=False
96
96
  ),
97
97
  schema: str = typer.Option(..., help="Python path to the schema file"),
@@ -120,7 +120,7 @@ def codegen(
120
120
  "-p",
121
121
  "--plugins",
122
122
  ),
123
- cli_plugin: Optional[str] = None,
123
+ cli_plugin: str | None = None,
124
124
  ) -> None:
125
125
  if not query:
126
126
  return