strawberry-graphql 0.235.1.dev1719337273__py3-none-any.whl → 0.236.0__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.
Files changed (182) hide show
  1. strawberry/__init__.py +17 -11
  2. strawberry/aiohttp/handlers/graphql_transport_ws_handler.py +3 -0
  3. strawberry/aiohttp/handlers/graphql_ws_handler.py +3 -0
  4. strawberry/aiohttp/test/client.py +3 -0
  5. strawberry/aiohttp/views.py +3 -0
  6. strawberry/annotation.py +19 -22
  7. strawberry/asgi/__init__.py +3 -3
  8. strawberry/asgi/handlers/graphql_transport_ws_handler.py +3 -0
  9. strawberry/asgi/handlers/graphql_ws_handler.py +3 -0
  10. strawberry/asgi/test/client.py +3 -0
  11. strawberry/chalice/views.py +12 -3
  12. strawberry/channels/handlers/__init__.py +0 -0
  13. strawberry/channels/handlers/base.py +5 -5
  14. strawberry/channels/handlers/graphql_transport_ws_handler.py +3 -0
  15. strawberry/channels/handlers/graphql_ws_handler.py +3 -0
  16. strawberry/channels/handlers/http_handler.py +5 -2
  17. strawberry/channels/handlers/ws_handler.py +4 -1
  18. strawberry/channels/router.py +9 -5
  19. strawberry/channels/testing.py +11 -4
  20. strawberry/cli/commands/upgrade/__init__.py +13 -5
  21. strawberry/cli/commands/upgrade/_fake_progress.py +2 -1
  22. strawberry/cli/commands/upgrade/_run_codemod.py +18 -1
  23. strawberry/codegen/exceptions.py +8 -0
  24. strawberry/codegen/query_codegen.py +16 -7
  25. strawberry/codegen/types.py +32 -1
  26. strawberry/codemods/update_imports.py +136 -0
  27. strawberry/dataloader.py +13 -0
  28. strawberry/directive.py +52 -4
  29. strawberry/django/context.py +4 -1
  30. strawberry/django/test/client.py +3 -0
  31. strawberry/django/views.py +3 -0
  32. strawberry/exceptions/__init__.py +5 -5
  33. strawberry/exceptions/duplicated_type_name.py +1 -1
  34. strawberry/exceptions/invalid_argument_type.py +3 -3
  35. strawberry/exceptions/invalid_union_type.py +5 -6
  36. strawberry/exceptions/missing_arguments_annotations.py +1 -1
  37. strawberry/exceptions/missing_dependencies.py +10 -2
  38. strawberry/exceptions/missing_return_annotation.py +1 -1
  39. strawberry/exceptions/permission_fail_silently_requires_optional.py +3 -3
  40. strawberry/exceptions/scalar_already_registered.py +1 -1
  41. strawberry/exceptions/unresolved_field_type.py +2 -2
  42. strawberry/exceptions/utils/source_finder.py +5 -2
  43. strawberry/experimental/pydantic/conversion.py +5 -5
  44. strawberry/experimental/pydantic/conversion_types.py +4 -2
  45. strawberry/experimental/pydantic/error_type.py +2 -2
  46. strawberry/experimental/pydantic/fields.py +2 -2
  47. strawberry/experimental/pydantic/object_type.py +11 -7
  48. strawberry/experimental/pydantic/utils.py +4 -5
  49. strawberry/ext/dataclasses/dataclasses.py +2 -1
  50. strawberry/ext/mypy_plugin.py +10 -8
  51. strawberry/extensions/add_validation_rules.py +27 -23
  52. strawberry/extensions/base_extension.py +6 -4
  53. strawberry/extensions/directives.py +4 -1
  54. strawberry/extensions/disable_validation.py +15 -12
  55. strawberry/extensions/field_extension.py +11 -5
  56. strawberry/extensions/mask_errors.py +3 -0
  57. strawberry/extensions/max_aliases.py +21 -19
  58. strawberry/extensions/max_tokens.py +14 -16
  59. strawberry/extensions/parser_cache.py +22 -19
  60. strawberry/extensions/pyinstrument.py +4 -8
  61. strawberry/extensions/query_depth_limiter.py +22 -23
  62. strawberry/extensions/runner.py +3 -0
  63. strawberry/extensions/tracing/apollo.py +3 -0
  64. strawberry/extensions/tracing/datadog.py +7 -2
  65. strawberry/extensions/tracing/opentelemetry.py +3 -0
  66. strawberry/extensions/tracing/sentry.py +3 -0
  67. strawberry/extensions/tracing/utils.py +3 -0
  68. strawberry/extensions/utils.py +3 -0
  69. strawberry/extensions/validation_cache.py +23 -20
  70. strawberry/fastapi/context.py +3 -0
  71. strawberry/fastapi/handlers/graphql_transport_ws_handler.py +3 -0
  72. strawberry/fastapi/handlers/graphql_ws_handler.py +3 -0
  73. strawberry/fastapi/router.py +3 -0
  74. strawberry/federation/argument.py +4 -1
  75. strawberry/federation/enum.py +5 -3
  76. strawberry/federation/field.py +6 -3
  77. strawberry/federation/mutation.py +2 -0
  78. strawberry/federation/object_type.py +7 -4
  79. strawberry/federation/scalar.py +43 -20
  80. strawberry/federation/schema.py +12 -9
  81. strawberry/federation/schema_directive.py +2 -2
  82. strawberry/federation/schema_directives.py +19 -1
  83. strawberry/federation/types.py +5 -2
  84. strawberry/federation/union.py +27 -8
  85. strawberry/field_extensions/input_mutation.py +5 -2
  86. strawberry/file_uploads/scalars.py +3 -1
  87. strawberry/file_uploads/utils.py +3 -0
  88. strawberry/flask/views.py +8 -2
  89. strawberry/http/__init__.py +9 -0
  90. strawberry/http/async_base_view.py +4 -3
  91. strawberry/http/base.py +5 -7
  92. strawberry/http/exceptions.py +3 -0
  93. strawberry/http/ides.py +3 -0
  94. strawberry/http/sync_base_view.py +4 -3
  95. strawberry/http/temporal_response.py +3 -0
  96. strawberry/http/types.py +5 -2
  97. strawberry/http/typevars.py +3 -0
  98. strawberry/litestar/controller.py +6 -0
  99. strawberry/litestar/handlers/__init__.py +0 -0
  100. strawberry/litestar/handlers/graphql_transport_ws_handler.py +3 -0
  101. strawberry/litestar/handlers/graphql_ws_handler.py +3 -0
  102. strawberry/parent.py +27 -21
  103. strawberry/permission.py +70 -27
  104. strawberry/printer/ast_from_value.py +4 -1
  105. strawberry/printer/printer.py +8 -5
  106. strawberry/quart/views.py +3 -0
  107. strawberry/relay/exceptions.py +7 -0
  108. strawberry/relay/fields.py +70 -45
  109. strawberry/relay/types.py +78 -78
  110. strawberry/relay/utils.py +10 -1
  111. strawberry/resolvers.py +3 -0
  112. strawberry/sanic/context.py +3 -0
  113. strawberry/sanic/utils.py +10 -8
  114. strawberry/sanic/views.py +5 -9
  115. strawberry/scalars.py +6 -2
  116. strawberry/schema/base.py +7 -4
  117. strawberry/schema/compat.py +12 -2
  118. strawberry/schema/config.py +3 -0
  119. strawberry/schema/exceptions.py +3 -0
  120. strawberry/schema/execute.py +3 -0
  121. strawberry/schema/name_converter.py +12 -9
  122. strawberry/schema/schema.py +46 -9
  123. strawberry/schema/schema_converter.py +16 -14
  124. strawberry/schema/types/base_scalars.py +3 -1
  125. strawberry/schema/types/concrete_type.py +4 -4
  126. strawberry/schema/types/scalar.py +8 -1
  127. strawberry/schema/validation_rules/one_of.py +3 -0
  128. strawberry/schema_codegen/__init__.py +3 -0
  129. strawberry/schema_directive.py +2 -2
  130. strawberry/starlite/controller.py +3 -0
  131. strawberry/starlite/handlers/__init__.py +0 -0
  132. strawberry/starlite/handlers/graphql_transport_ws_handler.py +3 -0
  133. strawberry/starlite/handlers/graphql_ws_handler.py +3 -0
  134. strawberry/subscriptions/__init__.py +6 -0
  135. strawberry/subscriptions/protocols/graphql_transport_ws/__init__.py +5 -0
  136. strawberry/subscriptions/protocols/graphql_transport_ws/handlers.py +12 -17
  137. strawberry/subscriptions/protocols/graphql_transport_ws/types.py +21 -25
  138. strawberry/subscriptions/protocols/graphql_ws/__init__.py +14 -0
  139. strawberry/subscriptions/protocols/graphql_ws/handlers.py +8 -5
  140. strawberry/subscriptions/protocols/graphql_ws/types.py +11 -0
  141. strawberry/test/client.py +44 -29
  142. strawberry/tools/create_type.py +27 -8
  143. strawberry/tools/merge_types.py +5 -3
  144. strawberry/types/__init__.py +8 -1
  145. strawberry/{arguments.py → types/arguments.py} +44 -13
  146. strawberry/{auto.py → types/auto.py} +21 -3
  147. strawberry/types/{types.py → base.py} +234 -10
  148. strawberry/{enum.py → types/enum.py} +69 -9
  149. strawberry/types/execution.py +3 -0
  150. strawberry/{field.py → types/field.py} +46 -23
  151. strawberry/types/fields/resolver.py +2 -2
  152. strawberry/types/graphql.py +3 -0
  153. strawberry/types/info.py +50 -7
  154. strawberry/{lazy_type.py → types/lazy_type.py} +50 -0
  155. strawberry/types/mutation.py +351 -0
  156. strawberry/types/nodes.py +4 -2
  157. strawberry/{object_type.py → types/object_type.py} +108 -29
  158. strawberry/{private.py → types/private.py} +13 -6
  159. strawberry/{custom_scalar.py → types/scalar.py} +39 -23
  160. strawberry/types/type_resolver.py +21 -16
  161. strawberry/{union.py → types/union.py} +24 -9
  162. strawberry/{unset.py → types/unset.py} +20 -0
  163. strawberry/utils/aio.py +8 -0
  164. strawberry/utils/await_maybe.py +3 -0
  165. strawberry/utils/dataclasses.py +3 -0
  166. strawberry/utils/debug.py +5 -2
  167. strawberry/utils/deprecations.py +3 -0
  168. strawberry/utils/graphql_lexer.py +3 -0
  169. strawberry/utils/importer.py +3 -0
  170. strawberry/utils/inspect.py +39 -30
  171. strawberry/utils/logging.py +3 -0
  172. strawberry/utils/operation.py +3 -0
  173. strawberry/utils/str_converters.py +3 -0
  174. strawberry/utils/typing.py +33 -16
  175. {strawberry_graphql-0.235.1.dev1719337273.dist-info → strawberry_graphql-0.236.0.dist-info}/METADATA +1 -1
  176. strawberry_graphql-0.236.0.dist-info/RECORD +255 -0
  177. strawberry/mutation.py +0 -8
  178. strawberry/type.py +0 -232
  179. strawberry_graphql-0.235.1.dev1719337273.dist-info/RECORD +0 -252
  180. {strawberry_graphql-0.235.1.dev1719337273.dist-info → strawberry_graphql-0.236.0.dist-info}/LICENSE +0 -0
  181. {strawberry_graphql-0.235.1.dev1719337273.dist-info → strawberry_graphql-0.236.0.dist-info}/WHEEL +0 -0
  182. {strawberry_graphql-0.235.1.dev1719337273.dist-info → strawberry_graphql-0.236.0.dist-info}/entry_points.txt +0 -0
strawberry/parent.py CHANGED
@@ -8,31 +8,37 @@ class StrawberryParent: ...
8
8
  T = TypeVar("T")
9
9
 
10
10
  Parent = Annotated[T, StrawberryParent()]
11
- Parent.__doc__ = """Represents a parameter holding the parent resolver's value.
11
+ """Represents a parameter holding the parent resolver's value.
12
12
 
13
13
  This can be used when defining a resolver on a type when the parent isn't expected
14
14
  to return the type itself.
15
15
 
16
16
  Example:
17
17
 
18
- >>> import strawberry
19
- >>> from dataclasses import dataclass
20
- >>>
21
- >>> @dataclass
22
- >>> class UserRow:
23
- ... id_: str
24
- ...
25
- >>> @strawberry.type
26
- ... class User:
27
- ... @strawberry.field
28
- ... @staticmethod
29
- ... async def name(parent: strawberry.Parent[UserRow]) -> str:
30
- ... return f"User Number {parent.id}"
31
- ...
32
- >>> @strawberry.type
33
- >>> class Query:
34
- ... @strawberry.field
35
- ... def user(self) -> User:
36
- ... return UserRow(id_="1234")
37
- ...
18
+ ```python
19
+ import strawberry
20
+ from dataclasses import dataclass
21
+
22
+
23
+ @dataclass
24
+ class UserRow:
25
+ id_: str
26
+
27
+
28
+ @strawberry.type
29
+ class User:
30
+ @strawberry.field
31
+ @staticmethod
32
+ async def name(parent: strawberry.Parent[UserRow]) -> str:
33
+ return f"User Number {parent.id_}"
34
+
35
+
36
+ @strawberry.type
37
+ class Query:
38
+ @strawberry.field
39
+ def user(self) -> User:
40
+ return UserRow(id_="1234")
41
+ ```
38
42
  """
43
+
44
+ __all__ = ["Parent"]
strawberry/permission.py CHANGED
@@ -21,7 +21,7 @@ from strawberry.exceptions.permission_fail_silently_requires_optional import (
21
21
  )
22
22
  from strawberry.extensions import FieldExtension
23
23
  from strawberry.schema_directive import Location, StrawberrySchemaDirective
24
- from strawberry.type import StrawberryList, StrawberryOptional
24
+ from strawberry.types.base import StrawberryList, StrawberryOptional
25
25
  from strawberry.utils.await_maybe import await_maybe
26
26
 
27
27
  if TYPE_CHECKING:
@@ -31,13 +31,25 @@ if TYPE_CHECKING:
31
31
  AsyncExtensionResolver,
32
32
  SyncExtensionResolver,
33
33
  )
34
- from strawberry.field import StrawberryField
35
34
  from strawberry.types import Info
35
+ from strawberry.types.field import StrawberryField
36
36
 
37
37
 
38
38
  class BasePermission(abc.ABC):
39
- """
40
- Base class for creating permissions
39
+ """Base class for permissions. All permissions should inherit from this class.
40
+
41
+ Example:
42
+
43
+ ```python
44
+ from strawberry.permission import BasePermission
45
+
46
+
47
+ class IsAuthenticated(BasePermission):
48
+ message = "User is not authenticated"
49
+
50
+ def has_permission(self, source, info, **kwargs):
51
+ return info.context["user"].is_authenticated
52
+ ```
41
53
  """
42
54
 
43
55
  message: Optional[str] = None
@@ -52,16 +64,39 @@ class BasePermission(abc.ABC):
52
64
  def has_permission(
53
65
  self, source: Any, info: Info, **kwargs: Any
54
66
  ) -> Union[bool, Awaitable[bool]]:
67
+ """Check if the permission should be accepted.
68
+
69
+ This method should be overridden by the subclasses.
70
+ """
55
71
  raise NotImplementedError(
56
72
  "Permission classes should override has_permission method"
57
73
  )
58
74
 
59
75
  def on_unauthorized(self) -> None:
60
- """
61
- Default error raising for permissions.
62
- This can be overridden to customize the behavior.
63
- """
76
+ """Default error raising for permissions.
77
+
78
+ This method can be overridden to customize the error raised when the permission is not granted.
79
+
80
+ Example:
81
+
82
+ ```python
83
+ from strawberry.permission import BasePermission
84
+
85
+
86
+ class CustomPermissionError(PermissionError):
87
+ pass
88
+
64
89
 
90
+ class IsAuthenticated(BasePermission):
91
+ message = "User is not authenticated"
92
+
93
+ def has_permission(self, source, info, **kwargs):
94
+ return info.context["user"].is_authenticated
95
+
96
+ def on_unauthorized(self) -> None:
97
+ raise CustomPermissionError(self.message)
98
+ ```
99
+ """
65
100
  # Instantiate error class
66
101
  error = self.error_class(self.message or "")
67
102
 
@@ -91,17 +126,14 @@ class BasePermission(abc.ABC):
91
126
 
92
127
 
93
128
  class PermissionExtension(FieldExtension):
94
- """
95
- Handles permissions for a field
96
- Instantiate this as a field extension with all of the permissions you want to apply
129
+ """Handles permissions for a field.
97
130
 
98
- fail_silently: bool = False will return None or [] if the permission fails
99
- instead of raising an exception. This is only valid for optional or list fields.
131
+ Instantiate this as a field extension with all of the permissions you want to apply.
100
132
 
101
- NOTE:
102
- Currently, this is automatically added to the field, when using
103
- field.permission_classes
104
- This is deprecated behavior, please manually add the extension to field.extensions
133
+ Note:
134
+ Currently, this is automatically added to the field, when using field.permission_classes
135
+
136
+ This is deprecated behaviour, please manually add the extension to field.extensions
105
137
  """
106
138
 
107
139
  def __init__(
@@ -110,16 +142,21 @@ class PermissionExtension(FieldExtension):
110
142
  use_directives: bool = True,
111
143
  fail_silently: bool = False,
112
144
  ) -> None:
145
+ """Initialize the permission extension.
146
+
147
+ Args:
148
+ permissions: List of permissions to apply.
149
+ fail_silently: If True, return None or [] instead of raising an exception.
150
+ This is only valid for optional or list fields.
151
+ use_directives: If True, add schema directives to the field.
152
+ """
113
153
  self.permissions = permissions
114
154
  self.fail_silently = fail_silently
115
155
  self.return_empty_list = False
116
156
  self.use_directives = use_directives
117
157
 
118
158
  def apply(self, field: StrawberryField) -> None:
119
- """
120
- Applies all of the permission directives to the schema
121
- and sets up silent permissions
122
- """
159
+ """Applies all of the permission directives to the schema and sets up silent permissions."""
123
160
  if self.use_directives:
124
161
  field.directives.extend(
125
162
  p.schema_directive for p in self.permissions if p.schema_directive
@@ -147,10 +184,7 @@ class PermissionExtension(FieldExtension):
147
184
  info: Info,
148
185
  **kwargs: Dict[str, Any],
149
186
  ) -> Any:
150
- """
151
- Checks if the permission should be accepted and
152
- raises an exception if not
153
- """
187
+ """Checks if the permission should be accepted and raises an exception if not."""
154
188
  for permission in self.permissions:
155
189
  if not permission.has_permission(source, info, **kwargs):
156
190
  return self._on_unauthorized(permission)
@@ -177,11 +211,20 @@ class PermissionExtension(FieldExtension):
177
211
 
178
212
  @cached_property
179
213
  def supports_sync(self) -> bool:
180
- """The Permission extension always supports async checking using await_maybe,
181
- but only supports sync checking if there are no async permissions"""
214
+ """Whether this extension can be resolved synchronously or not.
215
+
216
+ The Permission extension always supports async checking using await_maybe,
217
+ but only supports sync checking if there are no async permissions.
218
+ """
182
219
  async_permissions = [
183
220
  True
184
221
  for permission in self.permissions
185
222
  if iscoroutinefunction(permission.has_permission)
186
223
  ]
187
224
  return len(async_permissions) == 0
225
+
226
+
227
+ __all__ = [
228
+ "BasePermission",
229
+ "PermissionExtension",
230
+ ]
@@ -27,7 +27,7 @@ from graphql.type import (
27
27
  )
28
28
 
29
29
  import strawberry
30
- from strawberry.type import has_object_definition
30
+ from strawberry.types.base import has_object_definition
31
31
 
32
32
  if TYPE_CHECKING:
33
33
  from graphql.language import ValueNode
@@ -149,3 +149,6 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]:
149
149
 
150
150
  # Not reachable. All possible input types have been considered.
151
151
  raise TypeError(f"Unexpected input type: {inspect(type_)}.") # pragma: no cover
152
+
153
+
154
+ __all__ = ["ast_from_value"]
@@ -37,11 +37,11 @@ from graphql.utilities.print_schema import (
37
37
  )
38
38
  from graphql.utilities.print_schema import print_type as original_print_type
39
39
 
40
- from strawberry.custom_scalar import ScalarWrapper
41
- from strawberry.enum import EnumDefinition
42
40
  from strawberry.schema_directive import Location, StrawberrySchemaDirective
43
- from strawberry.type import StrawberryContainer, has_object_definition
44
- from strawberry.unset import UNSET
41
+ from strawberry.types.base import StrawberryContainer, has_object_definition
42
+ from strawberry.types.enum import EnumDefinition
43
+ from strawberry.types.scalar import ScalarWrapper
44
+ from strawberry.types.unset import UNSET
45
45
 
46
46
  from .ast_from_value import ast_from_value
47
47
 
@@ -55,8 +55,8 @@ if TYPE_CHECKING:
55
55
  )
56
56
  from graphql.type.directives import GraphQLDirective
57
57
 
58
- from strawberry.field import StrawberryField
59
58
  from strawberry.schema import BaseSchema
59
+ from strawberry.types.field import StrawberryField
60
60
 
61
61
 
62
62
  _T = TypeVar("_T")
@@ -588,3 +588,6 @@ def print_schema(schema: BaseSchema) -> str:
588
588
  ),
589
589
  )
590
590
  )
591
+
592
+
593
+ __all__ = ["print_schema"]
strawberry/quart/views.py CHANGED
@@ -102,3 +102,6 @@ class GraphQLView(
102
102
  response=e.reason,
103
103
  status=e.status_code,
104
104
  )
105
+
106
+
107
+ __all__ = ["GraphQLView"]
@@ -102,3 +102,10 @@ class RelayWrongResolverAnnotationError(StrawberryException):
102
102
 
103
103
  source_finder = SourceFinder()
104
104
  return source_finder.find_function_from_object(cast(Callable, self.function))
105
+
106
+
107
+ __all__ = [
108
+ "NodeIDAnnotationError",
109
+ "RelayWrongAnnotationError",
110
+ "RelayWrongResolverAnnotationError",
111
+ ]
@@ -29,20 +29,20 @@ from typing import (
29
29
  from typing_extensions import Annotated, get_origin
30
30
 
31
31
  from strawberry.annotation import StrawberryAnnotation
32
- from strawberry.arguments import StrawberryArgument, argument
33
32
  from strawberry.extensions.field_extension import (
34
33
  AsyncExtensionResolver,
35
34
  FieldExtension,
36
35
  SyncExtensionResolver,
37
36
  )
38
- from strawberry.field import _RESOLVER_TYPE, StrawberryField, field
39
- from strawberry.lazy_type import LazyType
40
37
  from strawberry.relay.exceptions import (
41
38
  RelayWrongAnnotationError,
42
39
  RelayWrongResolverAnnotationError,
43
40
  )
44
- from strawberry.type import StrawberryList, StrawberryOptional
41
+ from strawberry.types.arguments import StrawberryArgument, argument
42
+ from strawberry.types.base import StrawberryList, StrawberryOptional
43
+ from strawberry.types.field import _RESOLVER_TYPE, StrawberryField, field
45
44
  from strawberry.types.fields.resolver import StrawberryResolver
45
+ from strawberry.types.lazy_type import LazyType
46
46
  from strawberry.utils.aio import asyncgen_to_list
47
47
  from strawberry.utils.typing import eval_type, is_generic_alias
48
48
 
@@ -62,7 +62,7 @@ class NodeExtension(FieldExtension):
62
62
  if isinstance(field.type, StrawberryList):
63
63
  resolver = self.get_node_list_resolver(field)
64
64
  else:
65
- resolver = self.get_node_resolver(field)
65
+ resolver = self.get_node_resolver(field) # type: ignore
66
66
 
67
67
  field.base_resolver = StrawberryResolver(resolver, type_override=field.type)
68
68
 
@@ -81,7 +81,9 @@ class NodeExtension(FieldExtension):
81
81
  # async extensions.
82
82
  return await retval if inspect.isawaitable(retval) else retval
83
83
 
84
- def get_node_resolver(self, field: StrawberryField): # noqa: ANN201
84
+ def get_node_resolver(
85
+ self, field: StrawberryField
86
+ ) -> Callable[[Info, GlobalID], Union[Node, None, Awaitable[Union[Node, None]]]]:
85
87
  type_ = field.type
86
88
  is_optional = isinstance(type_, StrawberryOptional)
87
89
 
@@ -97,7 +99,9 @@ class NodeExtension(FieldExtension):
97
99
 
98
100
  return resolver
99
101
 
100
- def get_node_list_resolver(self, field: StrawberryField): # noqa: ANN201
102
+ def get_node_list_resolver(
103
+ self, field: StrawberryField
104
+ ) -> Callable[[Info, List[GlobalID]], Union[List[Node], Awaitable[List[Node]]]]:
101
105
  type_ = field.type
102
106
  assert isinstance(type_, StrawberryList)
103
107
  is_optional = isinstance(type_.of_type, StrawberryOptional)
@@ -390,48 +394,66 @@ def connection(
390
394
  case for this is to provide a filtered iterable of nodes by using some custom
391
395
  filter arguments.
392
396
 
397
+ Args:
398
+ graphql_type: The type of the nodes in the connection. This is used to
399
+ determine the type of the edges and the node field in the connection.
400
+ resolver: The resolver for the connection. This is expected to return an
401
+ iterable of the expected node type.
402
+ name: The GraphQL name of the field.
403
+ is_subscription: Whether the field is a subscription.
404
+ description: The GraphQL description of the field.
405
+ permission_classes: The permission classes to apply to the field.
406
+ deprecation_reason: The deprecation reason of the field.
407
+ default: The default value of the field.
408
+ default_factory: The default factory of the field.
409
+ metadata: The metadata of the field.
410
+ directives: The directives to apply to the field.
411
+ extensions: The extensions to apply to the field.
412
+ init: Used only for type checking purposes.
413
+
393
414
  Examples:
394
- Annotating something like this:
395
-
396
- >>> @strawberry.type
397
- >>> class X:
398
- ... some_node: relay.Connection[SomeType] = relay.connection(
399
- resolver=get_some_nodes,
400
- ... description="ABC",
401
- ... )
402
- ...
403
- ... @relay.connection(relay.Connection[SomeType], description="ABC")
404
- ... def get_some_nodes(self, age: int) -> Iterable[SomeType]:
405
- ... ...
406
-
407
- Will produce a query like this:
408
-
409
- ```
410
- query {
411
- someNode (
412
- before: String
413
- after: String
414
- first: String
415
- after: String
416
- age: Int
417
- ) {
418
- totalCount
419
- pageInfo {
420
- hasNextPage
421
- hasPreviousPage
422
- startCursor
423
- endCursor
424
- }
425
- edges {
426
- cursor
427
- node {
428
- id
429
- ...
430
- }
415
+ Annotating something like this:
416
+
417
+ ```python
418
+ @strawberry.type
419
+ class X:
420
+ some_node: relay.Connection[SomeType] = relay.connection(
421
+ resolver=get_some_nodes,
422
+ description="ABC",
423
+ )
424
+
425
+ @relay.connection(relay.Connection[SomeType], description="ABC")
426
+ def get_some_nodes(self, age: int) -> Iterable[SomeType]: ...
427
+ ```
428
+
429
+ Will produce a query like this:
430
+
431
+ ```graphql
432
+ query {
433
+ someNode (
434
+ before: String
435
+ after: String
436
+ first: String
437
+ after: String
438
+ age: Int
439
+ ) {
440
+ totalCount
441
+ pageInfo {
442
+ hasNextPage
443
+ hasPreviousPage
444
+ startCursor
445
+ endCursor
446
+ }
447
+ edges {
448
+ cursor
449
+ node {
450
+ id
451
+ ...
431
452
  }
432
453
  }
433
454
  }
434
- ```
455
+ }
456
+ ```
435
457
 
436
458
  .. _Relay connections:
437
459
  https://relay.dev/graphql/connections.htm
@@ -454,3 +476,6 @@ def connection(
454
476
  if resolver is not None:
455
477
  f = f(resolver)
456
478
  return f
479
+
480
+
481
+ __all__ = ["node", "connection"]