strawberry-graphql 0.283.0__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 (146) hide show
  1. strawberry/aiohttp/test/client.py +8 -15
  2. strawberry/aiohttp/views.py +12 -15
  3. strawberry/annotation.py +19 -23
  4. strawberry/asgi/__init__.py +18 -17
  5. strawberry/asgi/test/client.py +6 -6
  6. strawberry/chalice/views.py +6 -6
  7. strawberry/channels/handlers/base.py +7 -8
  8. strawberry/channels/handlers/http_handler.py +18 -20
  9. strawberry/channels/handlers/ws_handler.py +10 -12
  10. strawberry/channels/router.py +3 -4
  11. strawberry/channels/testing.py +7 -9
  12. strawberry/cli/commands/codegen.py +7 -7
  13. strawberry/cli/commands/schema_codegen.py +1 -2
  14. strawberry/cli/commands/upgrade/__init__.py +1 -3
  15. strawberry/cli/commands/upgrade/_run_codemod.py +2 -2
  16. strawberry/codegen/plugins/print_operation.py +2 -2
  17. strawberry/codegen/plugins/python.py +2 -2
  18. strawberry/codegen/query_codegen.py +20 -30
  19. strawberry/codegen/types.py +32 -32
  20. strawberry/codemods/annotated_unions.py +2 -2
  21. strawberry/dataloader.py +28 -24
  22. strawberry/directive.py +6 -7
  23. strawberry/django/test/client.py +3 -3
  24. strawberry/django/views.py +16 -19
  25. strawberry/exceptions/__init__.py +4 -4
  26. strawberry/exceptions/conflicting_arguments.py +2 -2
  27. strawberry/exceptions/duplicated_type_name.py +4 -4
  28. strawberry/exceptions/exception.py +3 -3
  29. strawberry/exceptions/handler.py +8 -7
  30. strawberry/exceptions/invalid_argument_type.py +2 -2
  31. strawberry/exceptions/invalid_superclass_interface.py +2 -2
  32. strawberry/exceptions/invalid_union_type.py +4 -4
  33. strawberry/exceptions/missing_arguments_annotations.py +2 -2
  34. strawberry/exceptions/missing_dependencies.py +2 -4
  35. strawberry/exceptions/missing_field_annotation.py +2 -2
  36. strawberry/exceptions/missing_return_annotation.py +2 -2
  37. strawberry/exceptions/object_is_not_a_class.py +2 -2
  38. strawberry/exceptions/object_is_not_an_enum.py +2 -2
  39. strawberry/exceptions/permission_fail_silently_requires_optional.py +2 -2
  40. strawberry/exceptions/private_strawberry_field.py +2 -2
  41. strawberry/exceptions/scalar_already_registered.py +2 -2
  42. strawberry/exceptions/syntax.py +3 -3
  43. strawberry/exceptions/unresolved_field_type.py +2 -2
  44. strawberry/exceptions/utils/source_finder.py +25 -25
  45. strawberry/experimental/pydantic/_compat.py +8 -7
  46. strawberry/experimental/pydantic/conversion.py +2 -2
  47. strawberry/experimental/pydantic/conversion_types.py +2 -2
  48. strawberry/experimental/pydantic/error_type.py +10 -12
  49. strawberry/experimental/pydantic/fields.py +9 -15
  50. strawberry/experimental/pydantic/object_type.py +15 -23
  51. strawberry/experimental/pydantic/utils.py +1 -2
  52. strawberry/ext/mypy_plugin.py +12 -14
  53. strawberry/extensions/base_extension.py +2 -1
  54. strawberry/extensions/context.py +13 -18
  55. strawberry/extensions/directives.py +3 -1
  56. strawberry/extensions/field_extension.py +4 -4
  57. strawberry/extensions/max_aliases.py +1 -3
  58. strawberry/extensions/parser_cache.py +1 -2
  59. strawberry/extensions/query_depth_limiter.py +18 -14
  60. strawberry/extensions/runner.py +2 -2
  61. strawberry/extensions/tracing/apollo.py +3 -3
  62. strawberry/extensions/tracing/datadog.py +3 -3
  63. strawberry/extensions/tracing/opentelemetry.py +6 -8
  64. strawberry/extensions/tracing/utils.py +3 -1
  65. strawberry/extensions/utils.py +2 -2
  66. strawberry/extensions/validation_cache.py +1 -2
  67. strawberry/fastapi/context.py +6 -6
  68. strawberry/fastapi/router.py +33 -36
  69. strawberry/federation/argument.py +4 -5
  70. strawberry/federation/enum.py +18 -21
  71. strawberry/federation/field.py +94 -97
  72. strawberry/federation/object_type.py +56 -58
  73. strawberry/federation/scalar.py +27 -35
  74. strawberry/federation/schema.py +15 -16
  75. strawberry/federation/schema_directive.py +7 -6
  76. strawberry/federation/schema_directives.py +11 -11
  77. strawberry/federation/union.py +4 -4
  78. strawberry/flask/views.py +10 -11
  79. strawberry/http/__init__.py +14 -14
  80. strawberry/http/async_base_view.py +23 -28
  81. strawberry/http/base.py +11 -12
  82. strawberry/http/ides.py +2 -3
  83. strawberry/http/sync_base_view.py +11 -13
  84. strawberry/http/types.py +3 -3
  85. strawberry/litestar/controller.py +40 -35
  86. strawberry/permission.py +4 -6
  87. strawberry/printer/ast_from_value.py +3 -5
  88. strawberry/printer/printer.py +8 -13
  89. strawberry/quart/views.py +12 -14
  90. strawberry/relay/exceptions.py +4 -4
  91. strawberry/relay/fields.py +33 -32
  92. strawberry/relay/types.py +31 -34
  93. strawberry/relay/utils.py +2 -2
  94. strawberry/resolvers.py +2 -1
  95. strawberry/sanic/context.py +1 -0
  96. strawberry/sanic/utils.py +3 -3
  97. strawberry/sanic/views.py +11 -14
  98. strawberry/scalars.py +2 -2
  99. strawberry/schema/_graphql_core.py +5 -5
  100. strawberry/schema/base.py +32 -33
  101. strawberry/schema/compat.py +9 -9
  102. strawberry/schema/config.py +5 -2
  103. strawberry/schema/exceptions.py +1 -3
  104. strawberry/schema/name_converter.py +6 -6
  105. strawberry/schema/schema.py +55 -60
  106. strawberry/schema/schema_converter.py +27 -22
  107. strawberry/schema/types/base_scalars.py +1 -1
  108. strawberry/schema/types/concrete_type.py +5 -5
  109. strawberry/schema_codegen/__init__.py +3 -3
  110. strawberry/schema_directive.py +7 -6
  111. strawberry/subscriptions/protocols/graphql_transport_ws/handlers.py +5 -6
  112. strawberry/subscriptions/protocols/graphql_transport_ws/types.py +20 -20
  113. strawberry/subscriptions/protocols/graphql_ws/handlers.py +5 -6
  114. strawberry/subscriptions/protocols/graphql_ws/types.py +14 -14
  115. strawberry/test/client.py +18 -18
  116. strawberry/tools/create_type.py +2 -3
  117. strawberry/types/arguments.py +25 -26
  118. strawberry/types/auto.py +3 -4
  119. strawberry/types/base.py +25 -27
  120. strawberry/types/enum.py +22 -25
  121. strawberry/types/execution.py +14 -15
  122. strawberry/types/field.py +108 -108
  123. strawberry/types/fields/resolver.py +19 -21
  124. strawberry/types/info.py +5 -11
  125. strawberry/types/lazy_type.py +2 -3
  126. strawberry/types/maybe.py +12 -3
  127. strawberry/types/mutation.py +115 -118
  128. strawberry/types/nodes.py +2 -2
  129. strawberry/types/object_type.py +43 -63
  130. strawberry/types/scalar.py +37 -43
  131. strawberry/types/union.py +12 -14
  132. strawberry/utils/aio.py +12 -9
  133. strawberry/utils/await_maybe.py +3 -3
  134. strawberry/utils/deprecations.py +2 -2
  135. strawberry/utils/importer.py +1 -2
  136. strawberry/utils/inspect.py +4 -6
  137. strawberry/utils/logging.py +2 -2
  138. strawberry/utils/operation.py +4 -4
  139. strawberry/utils/typing.py +18 -83
  140. {strawberry_graphql-0.283.0.dist-info → strawberry_graphql-0.284.3.dist-info}/METADATA +2 -2
  141. strawberry_graphql-0.284.3.dist-info/RECORD +243 -0
  142. strawberry/utils/dataclasses.py +0 -37
  143. strawberry_graphql-0.283.0.dist-info/RECORD +0 -244
  144. {strawberry_graphql-0.283.0.dist-info → strawberry_graphql-0.284.3.dist-info}/WHEEL +0 -0
  145. {strawberry_graphql-0.283.0.dist-info → strawberry_graphql-0.284.3.dist-info}/entry_points.txt +0 -0
  146. {strawberry_graphql-0.283.0.dist-info → strawberry_graphql-0.284.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,22 +1,14 @@
1
- import sys
2
- from collections.abc import Iterable
1
+ from collections.abc import Callable, Iterable
3
2
  from typing import (
4
3
  Any,
5
- Callable,
6
4
  NewType,
7
- Optional,
8
5
  TypeVar,
9
- Union,
10
6
  overload,
11
7
  )
12
8
 
13
9
  from strawberry.types.scalar import ScalarWrapper, _process_scalar
14
10
 
15
- # in python 3.10+ NewType is a class
16
- if sys.version_info >= (3, 10):
17
- _T = TypeVar("_T", bound=Union[type, NewType])
18
- else:
19
- _T = TypeVar("_T", bound=type)
11
+ _T = TypeVar("_T", bound=type | NewType)
20
12
 
21
13
 
22
14
  def identity(x: _T) -> _T: # pragma: no cover
@@ -26,18 +18,18 @@ def identity(x: _T) -> _T: # pragma: no cover
26
18
  @overload
27
19
  def scalar(
28
20
  *,
29
- name: Optional[str] = None,
30
- description: Optional[str] = None,
31
- specified_by_url: Optional[str] = None,
21
+ name: str | None = None,
22
+ description: str | None = None,
23
+ specified_by_url: str | None = None,
32
24
  serialize: Callable = identity,
33
- parse_value: Optional[Callable] = None,
34
- parse_literal: Optional[Callable] = None,
25
+ parse_value: Callable | None = None,
26
+ parse_literal: Callable | None = None,
35
27
  directives: Iterable[object] = (),
36
28
  authenticated: bool = False,
37
29
  inaccessible: bool = False,
38
- policy: Optional[list[list[str]]] = None,
39
- requires_scopes: Optional[list[list[str]]] = None,
40
- tags: Optional[Iterable[str]] = (),
30
+ policy: list[list[str]] | None = None,
31
+ requires_scopes: list[list[str]] | None = None,
32
+ tags: Iterable[str] | None = (),
41
33
  ) -> Callable[[_T], _T]: ...
42
34
 
43
35
 
@@ -45,36 +37,36 @@ def scalar(
45
37
  def scalar(
46
38
  cls: _T,
47
39
  *,
48
- name: Optional[str] = None,
49
- description: Optional[str] = None,
50
- specified_by_url: Optional[str] = None,
40
+ name: str | None = None,
41
+ description: str | None = None,
42
+ specified_by_url: str | None = None,
51
43
  serialize: Callable = identity,
52
- parse_value: Optional[Callable] = None,
53
- parse_literal: Optional[Callable] = None,
44
+ parse_value: Callable | None = None,
45
+ parse_literal: Callable | None = None,
54
46
  directives: Iterable[object] = (),
55
47
  authenticated: bool = False,
56
48
  inaccessible: bool = False,
57
- policy: Optional[list[list[str]]] = None,
58
- requires_scopes: Optional[list[list[str]]] = None,
59
- tags: Optional[Iterable[str]] = (),
49
+ policy: list[list[str]] | None = None,
50
+ requires_scopes: list[list[str]] | None = None,
51
+ tags: Iterable[str] | None = (),
60
52
  ) -> _T: ...
61
53
 
62
54
 
63
55
  def scalar(
64
- cls: Optional[_T] = None,
56
+ cls: _T | None = None,
65
57
  *,
66
- name: Optional[str] = None,
67
- description: Optional[str] = None,
68
- specified_by_url: Optional[str] = None,
58
+ name: str | None = None,
59
+ description: str | None = None,
60
+ specified_by_url: str | None = None,
69
61
  serialize: Callable = identity,
70
- parse_value: Optional[Callable] = None,
71
- parse_literal: Optional[Callable] = None,
62
+ parse_value: Callable | None = None,
63
+ parse_literal: Callable | None = None,
72
64
  directives: Iterable[object] = (),
73
65
  authenticated: bool = False,
74
66
  inaccessible: bool = False,
75
- policy: Optional[list[list[str]]] = None,
76
- requires_scopes: Optional[list[list[str]]] = None,
77
- tags: Optional[Iterable[str]] = (),
67
+ policy: list[list[str]] | None = None,
68
+ requires_scopes: list[list[str]] | None = None,
69
+ tags: Iterable[str] | None = (),
78
70
  ) -> Any:
79
71
  """Annotates a class or type as a GraphQL custom scalar.
80
72
 
@@ -44,18 +44,17 @@ FederationAny = scalar(NewType("_Any", object), name="_Any") # type: ignore
44
44
  class Schema(BaseSchema):
45
45
  def __init__(
46
46
  self,
47
- query: Optional[type] = None,
48
- mutation: Optional[type] = None,
49
- subscription: Optional[type] = None,
47
+ query: type | None = None,
48
+ mutation: type | None = None,
49
+ subscription: type | None = None,
50
50
  # TODO: we should update directives' type in the main schema
51
51
  directives: Iterable[type] = (),
52
52
  types: Iterable[type] = (),
53
53
  extensions: Iterable[Union[type["SchemaExtension"], "SchemaExtension"]] = (),
54
- execution_context_class: Optional[type["GraphQLExecutionContext"]] = None,
54
+ execution_context_class: type["GraphQLExecutionContext"] | None = None,
55
55
  config: Optional["StrawberryConfig"] = None,
56
- scalar_overrides: Optional[
57
- dict[object, Union[type, "ScalarWrapper", "ScalarDefinition"]]
58
- ] = None,
56
+ scalar_overrides: dict[object, Union[type, "ScalarWrapper", "ScalarDefinition"]]
57
+ | None = None,
59
58
  schema_directives: Iterable[object] = (),
60
59
  enable_federation_2: bool = False,
61
60
  ) -> None:
@@ -85,9 +84,9 @@ class Schema(BaseSchema):
85
84
 
86
85
  def _get_federation_query_type(
87
86
  self,
88
- query: Optional[type[WithStrawberryObjectDefinition]],
89
- mutation: Optional[type[WithStrawberryObjectDefinition]],
90
- subscription: Optional[type[WithStrawberryObjectDefinition]],
87
+ query: type[WithStrawberryObjectDefinition] | None,
88
+ mutation: type[WithStrawberryObjectDefinition] | None,
89
+ subscription: type[WithStrawberryObjectDefinition] | None,
91
90
  additional_types: Iterable[type[WithStrawberryObjectDefinition]],
92
91
  ) -> type:
93
92
  """Returns a new query type that includes the _service field.
@@ -124,7 +123,7 @@ class Schema(BaseSchema):
124
123
 
125
124
  if entity_type:
126
125
  self.entities_resolver.__annotations__["return"] = list[
127
- Optional[entity_type] # type: ignore
126
+ entity_type | None # type: ignore
128
127
  ]
129
128
 
130
129
  entities_field = strawberry.field(
@@ -250,7 +249,7 @@ class Schema(BaseSchema):
250
249
  directive_by_url[import_url].add(f"@{name}")
251
250
 
252
251
  def _add_link_directives(
253
- self, additional_directives: Optional[list[object]] = None
252
+ self, additional_directives: list[object] | None = None
254
253
  ) -> None:
255
254
  from .schema_directives import FederationDirective, Link
256
255
 
@@ -312,11 +311,11 @@ class Schema(BaseSchema):
312
311
 
313
312
 
314
313
  def _get_entity_type(
315
- query: Optional[type[WithStrawberryObjectDefinition]],
316
- mutation: Optional[type[WithStrawberryObjectDefinition]],
317
- subscription: Optional[type[WithStrawberryObjectDefinition]],
314
+ query: type[WithStrawberryObjectDefinition] | None,
315
+ mutation: type[WithStrawberryObjectDefinition] | None,
316
+ subscription: type[WithStrawberryObjectDefinition] | None,
318
317
  additional_types: Iterable[type[WithStrawberryObjectDefinition]],
319
- ) -> Optional[StrawberryUnion]:
318
+ ) -> StrawberryUnion | None:
320
319
  # recursively iterate over the schema to find all types annotated with @key
321
320
  # if no types are annotated with @key, then the _Entity union and Query._entities
322
321
  # field should not be added to the schema
@@ -1,5 +1,6 @@
1
1
  import dataclasses
2
- from typing import Callable, Optional, TypeVar
2
+ from collections.abc import Callable
3
+ from typing import TypeVar
3
4
  from typing_extensions import dataclass_transform
4
5
 
5
6
  from strawberry.directive import directive_field
@@ -11,12 +12,12 @@ from strawberry.types.type_resolver import _get_fields
11
12
 
12
13
  @dataclasses.dataclass
13
14
  class ComposeOptions:
14
- import_url: Optional[str]
15
+ import_url: str | None
15
16
 
16
17
 
17
18
  @dataclasses.dataclass
18
19
  class StrawberryFederationSchemaDirective(StrawberrySchemaDirective):
19
- compose_options: Optional[ComposeOptions] = None
20
+ compose_options: ComposeOptions | None = None
20
21
 
21
22
 
22
23
  T = TypeVar("T", bound=type)
@@ -30,12 +31,12 @@ T = TypeVar("T", bound=type)
30
31
  def schema_directive(
31
32
  *,
32
33
  locations: list[Location],
33
- description: Optional[str] = None,
34
- name: Optional[str] = None,
34
+ description: str | None = None,
35
+ name: str | None = None,
35
36
  repeatable: bool = False,
36
37
  print_definition: bool = True,
37
38
  compose: bool = False,
38
- import_url: Optional[str] = None,
39
+ import_url: str | None = None,
39
40
  ) -> Callable[[T], T]:
40
41
  def _wrap(cls: T) -> T:
41
42
  cls = _wrap_dataclass(cls) # type: ignore
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import ClassVar, Optional
2
+ from typing import ClassVar
3
3
 
4
4
  from strawberry import directive_field
5
5
  from strawberry.schema_directive import Location, schema_directive
@@ -59,7 +59,7 @@ class Provides(FederationDirective):
59
59
  )
60
60
  class Key(FederationDirective):
61
61
  fields: FieldSet
62
- resolvable: Optional[bool] = True
62
+ resolvable: bool | None = True
63
63
  imported_from: ClassVar[ImportedFrom] = ImportedFrom(
64
64
  name="key", url="https://specs.apollo.dev/federation/v2.7"
65
65
  )
@@ -81,17 +81,17 @@ class Shareable(FederationDirective):
81
81
  locations=[Location.SCHEMA], name="link", repeatable=True, print_definition=False
82
82
  )
83
83
  class Link:
84
- url: Optional[str]
85
- as_: Optional[str] = directive_field(name="as")
86
- for_: Optional[LinkPurpose] = directive_field(name="for")
87
- import_: Optional[list[Optional[LinkImport]]] = directive_field(name="import")
84
+ url: str | None
85
+ as_: str | None = directive_field(name="as")
86
+ for_: LinkPurpose | None = directive_field(name="for")
87
+ import_: list[LinkImport | None] | None = directive_field(name="import")
88
88
 
89
89
  def __init__(
90
90
  self,
91
- url: Optional[str] = UNSET,
92
- as_: Optional[str] = UNSET,
93
- for_: Optional[LinkPurpose] = UNSET,
94
- import_: Optional[list[Optional[LinkImport]]] = UNSET,
91
+ url: str | None = UNSET,
92
+ as_: str | None = UNSET,
93
+ for_: LinkPurpose | None = UNSET,
94
+ import_: list[LinkImport | None] | None = UNSET,
95
95
  ) -> None:
96
96
  self.url = url
97
97
  self.as_ = as_
@@ -128,7 +128,7 @@ class Tag(FederationDirective):
128
128
  )
129
129
  class Override(FederationDirective):
130
130
  override_from: str = directive_field(name="from")
131
- label: Optional[str] = UNSET
131
+ label: str | None = UNSET
132
132
  imported_from: ClassVar[ImportedFrom] = ImportedFrom(
133
133
  name="override", url="https://specs.apollo.dev/federation/v2.7"
134
134
  )
@@ -1,5 +1,5 @@
1
1
  from collections.abc import Collection, Iterable
2
- from typing import Any, Optional
2
+ from typing import Any
3
3
 
4
4
  from strawberry.types.union import StrawberryUnion
5
5
  from strawberry.types.union import union as base_union
@@ -7,12 +7,12 @@ from strawberry.types.union import union as base_union
7
7
 
8
8
  def union(
9
9
  name: str,
10
- types: Optional[Collection[type[Any]]] = None,
10
+ types: Collection[type[Any]] | None = None,
11
11
  *,
12
- description: Optional[str] = None,
12
+ description: str | None = None,
13
13
  directives: Iterable[object] = (),
14
14
  inaccessible: bool = False,
15
- tags: Optional[Iterable[str]] = (),
15
+ tags: Iterable[str] | None = (),
16
16
  ) -> StrawberryUnion:
17
17
  """Creates a new named Union type.
18
18
 
strawberry/flask/views.py CHANGED
@@ -4,10 +4,8 @@ import warnings
4
4
  from typing import (
5
5
  TYPE_CHECKING,
6
6
  ClassVar,
7
- Optional,
8
- Union,
7
+ TypeGuard,
9
8
  )
10
- from typing_extensions import TypeGuard
11
9
 
12
10
  from lia import AsyncFlaskHTTPRequestAdapter, FlaskHTTPRequestAdapter, HTTPException
13
11
 
@@ -19,19 +17,20 @@ from strawberry.http.typevars import Context, RootValue
19
17
 
20
18
  if TYPE_CHECKING:
21
19
  from flask.typing import ResponseReturnValue
20
+
22
21
  from strawberry.http import GraphQLHTTPResponse
23
22
  from strawberry.http.ides import GraphQL_IDE
24
23
  from strawberry.schema.base import BaseSchema
25
24
 
26
25
 
27
26
  class BaseGraphQLView:
28
- graphql_ide: Optional[GraphQL_IDE]
27
+ graphql_ide: GraphQL_IDE | None
29
28
 
30
29
  def __init__(
31
30
  self,
32
31
  schema: BaseSchema,
33
- graphiql: Optional[bool] = None,
34
- graphql_ide: Optional[GraphQL_IDE] = "graphiql",
32
+ graphiql: bool | None = None,
33
+ graphql_ide: GraphQL_IDE | None = "graphiql",
35
34
  allow_queries_via_get: bool = True,
36
35
  multipart_uploads_enabled: bool = False,
37
36
  ) -> None:
@@ -52,7 +51,7 @@ class BaseGraphQLView:
52
51
 
53
52
  def create_response(
54
53
  self,
55
- response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
54
+ response_data: GraphQLHTTPResponse | list[GraphQLHTTPResponse],
56
55
  sub_response: Response,
57
56
  ) -> Response:
58
57
  sub_response.set_data(self.encode_json(response_data)) # type: ignore
@@ -72,7 +71,7 @@ class GraphQLView(
72
71
  def get_context(self, request: Request, response: Response) -> Context:
73
72
  return {"request": request, "response": response} # type: ignore
74
73
 
75
- def get_root_value(self, request: Request) -> Optional[RootValue]:
74
+ def get_root_value(self, request: Request) -> RootValue | None:
76
75
  return None
77
76
 
78
77
  def get_sub_response(self, request: Request) -> Response:
@@ -105,7 +104,7 @@ class AsyncGraphQLView(
105
104
  async def get_context(self, request: Request, response: Response) -> Context:
106
105
  return {"request": request, "response": response} # type: ignore
107
106
 
108
- async def get_root_value(self, request: Request) -> Optional[RootValue]:
107
+ async def get_root_value(self, request: Request) -> RootValue | None:
109
108
  return None
110
109
 
111
110
  async def get_sub_response(self, request: Request) -> Response:
@@ -127,11 +126,11 @@ class AsyncGraphQLView(
127
126
  def is_websocket_request(self, request: Request) -> TypeGuard[Request]:
128
127
  return False
129
128
 
130
- async def pick_websocket_subprotocol(self, request: Request) -> Optional[str]:
129
+ async def pick_websocket_subprotocol(self, request: Request) -> str | None:
131
130
  raise NotImplementedError
132
131
 
133
132
  async def create_websocket_response(
134
- self, request: Request, subprotocol: Optional[str]
133
+ self, request: Request, subprotocol: str | None
135
134
  ) -> Response:
136
135
  raise NotImplementedError
137
136
 
@@ -1,8 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import Any, Optional
5
- from typing_extensions import Literal, TypedDict
4
+ from typing import Any, Literal
5
+ from typing_extensions import TypedDict
6
6
 
7
7
  from strawberry.schema._graphql_core import (
8
8
  GraphQLIncrementalExecutionResults,
@@ -11,14 +11,14 @@ from strawberry.schema._graphql_core import (
11
11
 
12
12
 
13
13
  class GraphQLHTTPResponse(TypedDict, total=False):
14
- data: Optional[dict[str, object]]
15
- errors: Optional[list[object]]
16
- extensions: Optional[dict[str, object]]
17
- hasNext: Optional[bool]
18
- completed: Optional[list[Any]]
19
- pending: Optional[list[Any]]
20
- initial: Optional[list[Any]]
21
- incremental: Optional[list[Any]]
14
+ data: dict[str, object] | None
15
+ errors: list[object] | None
16
+ extensions: dict[str, object] | None
17
+ hasNext: bool | None
18
+ completed: list[Any] | None
19
+ pending: list[Any] | None
20
+ initial: list[Any] | None
21
+ incremental: list[Any] | None
22
22
 
23
23
 
24
24
  def process_result(result: ResultType) -> GraphQLHTTPResponse:
@@ -39,10 +39,10 @@ def process_result(result: ResultType) -> GraphQLHTTPResponse:
39
39
  class GraphQLRequestData:
40
40
  # query is optional here as it can be added by an extensions
41
41
  # (for example an extension for persisted queries)
42
- query: Optional[str]
43
- variables: Optional[dict[str, Any]]
44
- operation_name: Optional[str]
45
- extensions: Optional[dict[str, Any]]
42
+ query: str | None
43
+ variables: dict[str, Any] | None
44
+ operation_name: str | None
45
+ extensions: dict[str, Any] | None
46
46
  protocol: Literal["http", "multipart-subscription"] = "http"
47
47
 
48
48
 
@@ -2,19 +2,16 @@ import abc
2
2
  import asyncio
3
3
  import contextlib
4
4
  import json
5
- from collections.abc import AsyncGenerator, Mapping
5
+ from collections.abc import AsyncGenerator, Callable, Mapping
6
6
  from datetime import timedelta
7
7
  from typing import (
8
8
  Any,
9
- Callable,
10
9
  Generic,
11
10
  Literal,
12
- Optional,
13
- Union,
11
+ TypeGuard,
14
12
  cast,
15
13
  overload,
16
14
  )
17
- from typing_extensions import TypeGuard
18
15
 
19
16
  from graphql import GraphQLError
20
17
  from lia import AsyncHTTPRequestAdapter, HTTPException
@@ -87,9 +84,9 @@ class AsyncBaseHTTPView(
87
84
  ],
88
85
  ):
89
86
  schema: BaseSchema
90
- graphql_ide: Optional[GraphQL_IDE]
87
+ graphql_ide: GraphQL_IDE | None
91
88
  keep_alive = False
92
- keep_alive_interval: Optional[float] = None
89
+ keep_alive_interval: float | None = None
93
90
  connection_init_wait_timeout: timedelta = timedelta(minutes=1)
94
91
  request_adapter_class: Callable[[Request], AsyncHTTPRequestAdapter]
95
92
  websocket_adapter_class: Callable[
@@ -117,19 +114,19 @@ class AsyncBaseHTTPView(
117
114
  @abc.abstractmethod
118
115
  async def get_context(
119
116
  self,
120
- request: Union[Request, WebSocketRequest],
121
- response: Union[SubResponse, WebSocketResponse],
117
+ request: Request | WebSocketRequest,
118
+ response: SubResponse | WebSocketResponse,
122
119
  ) -> Context: ...
123
120
 
124
121
  @abc.abstractmethod
125
122
  async def get_root_value(
126
- self, request: Union[Request, WebSocketRequest]
127
- ) -> Optional[RootValue]: ...
123
+ self, request: Request | WebSocketRequest
124
+ ) -> RootValue | None: ...
128
125
 
129
126
  @abc.abstractmethod
130
127
  def create_response(
131
128
  self,
132
- response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]],
129
+ response_data: GraphQLHTTPResponse | list[GraphQLHTTPResponse],
133
130
  sub_response: SubResponse,
134
131
  ) -> Response: ...
135
132
 
@@ -147,26 +144,26 @@ class AsyncBaseHTTPView(
147
144
 
148
145
  @abc.abstractmethod
149
146
  def is_websocket_request(
150
- self, request: Union[Request, WebSocketRequest]
147
+ self, request: Request | WebSocketRequest
151
148
  ) -> TypeGuard[WebSocketRequest]: ...
152
149
 
153
150
  @abc.abstractmethod
154
151
  async def pick_websocket_subprotocol(
155
152
  self, request: WebSocketRequest
156
- ) -> Optional[str]: ...
153
+ ) -> str | None: ...
157
154
 
158
155
  @abc.abstractmethod
159
156
  async def create_websocket_response(
160
- self, request: WebSocketRequest, subprotocol: Optional[str]
157
+ self, request: WebSocketRequest, subprotocol: str | None
161
158
  ) -> WebSocketResponse: ...
162
159
 
163
160
  async def execute_operation(
164
161
  self,
165
162
  request: Request,
166
163
  context: Context,
167
- root_value: Optional[RootValue],
164
+ root_value: RootValue | None,
168
165
  sub_response: SubResponse,
169
- ) -> Union[ExecutionResult, list[ExecutionResult], SubscriptionExecutionResult]:
166
+ ) -> ExecutionResult | list[ExecutionResult] | SubscriptionExecutionResult:
170
167
  request_adapter = self.request_adapter_class(request)
171
168
 
172
169
  try:
@@ -223,7 +220,7 @@ class AsyncBaseHTTPView(
223
220
  request_adapter: AsyncHTTPRequestAdapter,
224
221
  sub_response: SubResponse,
225
222
  context: Context,
226
- root_value: Optional[RootValue],
223
+ root_value: RootValue | None,
227
224
  request_data: GraphQLRequestData,
228
225
  ) -> ExecutionResult:
229
226
  allowed_operation_types = OperationType.from_http(request_adapter.method)
@@ -283,7 +280,7 @@ class AsyncBaseHTTPView(
283
280
  self,
284
281
  request: Request,
285
282
  context: Context = UNSET,
286
- root_value: Optional[RootValue] = UNSET,
283
+ root_value: RootValue | None = UNSET,
287
284
  ) -> Response: ...
288
285
 
289
286
  @overload
@@ -291,15 +288,15 @@ class AsyncBaseHTTPView(
291
288
  self,
292
289
  request: WebSocketRequest,
293
290
  context: Context = UNSET,
294
- root_value: Optional[RootValue] = UNSET,
291
+ root_value: RootValue | None = UNSET,
295
292
  ) -> WebSocketResponse: ...
296
293
 
297
294
  async def run(
298
295
  self,
299
- request: Union[Request, WebSocketRequest],
296
+ request: Request | WebSocketRequest,
300
297
  context: Context = UNSET,
301
- root_value: Optional[RootValue] = UNSET,
302
- ) -> Union[Response, WebSocketResponse]:
298
+ root_value: RootValue | None = UNSET,
299
+ ) -> Response | WebSocketResponse:
303
300
  root_value = (
304
301
  await self.get_root_value(request) if root_value is UNSET else root_value
305
302
  )
@@ -373,7 +370,6 @@ class AsyncBaseHTTPView(
373
370
  stream,
374
371
  sub_response,
375
372
  headers={
376
- "Transfer-Encoding": "chunked",
377
373
  "Content-Type": "multipart/mixed;boundary=graphql;subscriptionSpec=1.0,application/json",
378
374
  },
379
375
  )
@@ -442,12 +438,11 @@ class AsyncBaseHTTPView(
442
438
  stream,
443
439
  sub_response,
444
440
  headers={
445
- "Transfer-Encoding": "chunked",
446
441
  "Content-Type": 'multipart/mixed; boundary="-"',
447
442
  },
448
443
  )
449
444
 
450
- response_data: Union[GraphQLHTTPResponse, list[GraphQLHTTPResponse]]
445
+ response_data: GraphQLHTTPResponse | list[GraphQLHTTPResponse]
451
446
 
452
447
  if isinstance(result, list):
453
448
  response_data = []
@@ -618,7 +613,7 @@ class AsyncBaseHTTPView(
618
613
 
619
614
  async def parse_http_body(
620
615
  self, request: AsyncHTTPRequestAdapter
621
- ) -> Union[GraphQLRequestData, list[GraphQLRequestData]]:
616
+ ) -> GraphQLRequestData | list[GraphQLRequestData]:
622
617
  headers = {key.lower(): value for key, value in request.headers.items()}
623
618
  content_type, _ = parse_content_type(request.content_type or "")
624
619
  accept = headers.get("accept", "")
@@ -687,7 +682,7 @@ class AsyncBaseHTTPView(
687
682
 
688
683
  async def on_ws_connect(
689
684
  self, context: Context
690
- ) -> Union[UnsetType, None, dict[str, object]]:
685
+ ) -> UnsetType | None | dict[str, object]:
691
686
  return UNSET
692
687
 
693
688
 
strawberry/http/base.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from collections.abc import Mapping
3
- from typing import Any, Generic, Optional, Union
3
+ from typing import Any, Generic
4
4
  from typing_extensions import Protocol
5
5
 
6
6
  from lia import HTTPException
@@ -15,7 +15,7 @@ from .typevars import Request
15
15
 
16
16
  class BaseRequestProtocol(Protocol):
17
17
  @property
18
- def query_params(self) -> Mapping[str, Optional[Union[str, list[str]]]]: ...
18
+ def query_params(self) -> Mapping[str, str | list[str] | None]: ...
19
19
 
20
20
  @property
21
21
  def method(self) -> HTTPMethod: ...
@@ -25,7 +25,7 @@ class BaseRequestProtocol(Protocol):
25
25
 
26
26
 
27
27
  class BaseView(Generic[Request]):
28
- graphql_ide: Optional[GraphQL_IDE]
28
+ graphql_ide: GraphQL_IDE | None
29
29
  multipart_uploads_enabled: bool = False
30
30
  schema: BaseSchema
31
31
 
@@ -42,13 +42,13 @@ class BaseView(Generic[Request]):
42
42
  def is_request_allowed(self, request: BaseRequestProtocol) -> bool:
43
43
  return request.method in ("GET", "POST")
44
44
 
45
- def parse_json(self, data: Union[str, bytes]) -> Any:
45
+ def parse_json(self, data: str | bytes) -> Any:
46
46
  try:
47
47
  return self.decode_json(data)
48
48
  except json.JSONDecodeError as e:
49
49
  raise HTTPException(400, "Unable to parse request body as JSON") from e
50
50
 
51
- def decode_json(self, data: Union[str, bytes]) -> object:
51
+ def decode_json(self, data: str | bytes) -> object:
52
52
  return json.loads(data)
53
53
 
54
54
  def encode_json(self, data: object) -> str:
@@ -78,13 +78,12 @@ class BaseView(Generic[Request]):
78
78
  def _is_multipart_subscriptions(
79
79
  self, content_type: str, params: dict[str, str]
80
80
  ) -> bool:
81
- if content_type != "multipart/mixed":
82
- return False
83
-
84
- if params.get("boundary") != "graphql":
85
- return False
86
-
87
- return params.get("subscriptionspec", "").startswith("1.0")
81
+ subscription_spec = params.get("subscriptionspec", "").strip("'\"")
82
+ return (
83
+ content_type == "multipart/mixed"
84
+ and ("boundary" not in params or params["boundary"] == "graphql")
85
+ and subscription_spec.startswith("1.0")
86
+ )
88
87
 
89
88
  def _validate_batch_request(
90
89
  self, request_data: list[GraphQLRequestData], protocol: str
strawberry/http/ides.py CHANGED
@@ -1,12 +1,11 @@
1
1
  import pathlib
2
- from typing import Optional
3
- from typing_extensions import Literal
2
+ from typing import Literal
4
3
 
5
4
  GraphQL_IDE = Literal["graphiql", "apollo-sandbox", "pathfinder"]
6
5
 
7
6
 
8
7
  def get_graphql_ide_html(
9
- graphql_ide: Optional[GraphQL_IDE] = "graphiql",
8
+ graphql_ide: GraphQL_IDE | None = "graphiql",
10
9
  ) -> str:
11
10
  here = pathlib.Path(__file__).parents[1]
12
11