strawberry-graphql 0.235.2__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 -19
  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 +6 -0
  89. strawberry/http/__init__.py +9 -0
  90. strawberry/http/async_base_view.py +4 -3
  91. strawberry/http/base.py +3 -0
  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 +3 -0
  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 +4 -2
  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.2.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.2.dist-info/RECORD +0 -252
  180. {strawberry_graphql-0.235.2.dist-info → strawberry_graphql-0.236.0.dist-info}/LICENSE +0 -0
  181. {strawberry_graphql-0.235.2.dist-info → strawberry_graphql-0.236.0.dist-info}/WHEEL +0 -0
  182. {strawberry_graphql-0.235.2.dist-info → strawberry_graphql-0.236.0.dist-info}/entry_points.txt +0 -0
@@ -1,10 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import dataclasses
4
+ from abc import ABC, abstractmethod
4
5
  from typing import (
5
6
  TYPE_CHECKING,
6
7
  Any,
7
8
  Callable,
9
+ ClassVar,
8
10
  Dict,
9
11
  List,
10
12
  Mapping,
@@ -13,29 +15,237 @@ from typing import (
13
15
  Type,
14
16
  TypeVar,
15
17
  Union,
18
+ overload,
16
19
  )
17
- from typing_extensions import Self, deprecated
20
+ from typing_extensions import Literal, Protocol, Self, deprecated
18
21
 
19
- from strawberry.type import (
20
- StrawberryList,
21
- StrawberryType,
22
- StrawberryTypeVar,
23
- WithStrawberryObjectDefinition,
24
- )
25
22
  from strawberry.utils.deprecations import DEPRECATION_MESSAGES, DeprecatedDescriptor
26
23
  from strawberry.utils.inspect import get_specialized_type_var_map
24
+ from strawberry.utils.typing import is_concrete_generic
27
25
  from strawberry.utils.typing import is_generic as is_type_generic
28
26
 
29
27
  if TYPE_CHECKING:
28
+ from typing_extensions import TypeGuard
29
+
30
30
  from graphql import GraphQLAbstractType, GraphQLResolveInfo
31
31
 
32
- from strawberry.field import StrawberryField
32
+ from strawberry.types.field import StrawberryField
33
+
34
+
35
+ class StrawberryType(ABC):
36
+ """The base class for all types that Strawberry uses.
37
+
38
+ Every type that is decorated by strawberry should have a dunder
39
+ `__strawberry_definition__` with an instance of a StrawberryType that contains
40
+ the parsed information that strawberry created.
41
+
42
+ NOTE: ATM this is only true for @type @interface @input follow
43
+ https://github.com/strawberry-graphql/strawberry/issues/2841 to see progress.
44
+ """
45
+
46
+ @property
47
+ def type_params(self) -> List[TypeVar]:
48
+ return []
49
+
50
+ @property
51
+ def is_one_of(self) -> bool:
52
+ return False
53
+
54
+ @abstractmethod
55
+ def copy_with(
56
+ self,
57
+ type_var_map: Mapping[
58
+ str, Union[StrawberryType, Type[WithStrawberryObjectDefinition]]
59
+ ],
60
+ ) -> Union[StrawberryType, Type[WithStrawberryObjectDefinition]]:
61
+ raise NotImplementedError()
62
+
63
+ @property
64
+ @abstractmethod
65
+ def is_graphql_generic(self) -> bool:
66
+ raise NotImplementedError()
67
+
68
+ def has_generic(self, type_var: TypeVar) -> bool:
69
+ return False
70
+
71
+ def __eq__(self, other: object) -> bool:
72
+ from strawberry.annotation import StrawberryAnnotation
73
+
74
+ if isinstance(other, StrawberryType):
75
+ return self is other
76
+
77
+ elif isinstance(other, StrawberryAnnotation):
78
+ return self == other.resolve()
79
+
80
+ else:
81
+ # This could be simplified if StrawberryAnnotation.resolve() always returned
82
+ # a StrawberryType
83
+ resolved = StrawberryAnnotation(other).resolve()
84
+ if isinstance(resolved, StrawberryType):
85
+ return self == resolved
86
+ else:
87
+ return NotImplemented
88
+
89
+ def __hash__(self) -> int:
90
+ # TODO: Is this a bad idea? __eq__ objects are supposed to have the same hash
91
+ return id(self)
92
+
93
+
94
+ class StrawberryContainer(StrawberryType):
95
+ def __init__(
96
+ self, of_type: Union[StrawberryType, Type[WithStrawberryObjectDefinition], type]
97
+ ) -> None:
98
+ self.of_type = of_type
99
+
100
+ def __hash__(self) -> int:
101
+ return hash((self.__class__, self.of_type))
102
+
103
+ def __eq__(self, other: object) -> bool:
104
+ if isinstance(other, StrawberryType):
105
+ if isinstance(other, StrawberryContainer):
106
+ return self.of_type == other.of_type
107
+ else:
108
+ return False
109
+
110
+ return super().__eq__(other)
111
+
112
+ @property
113
+ def type_params(self) -> List[TypeVar]:
114
+ if has_object_definition(self.of_type):
115
+ parameters = getattr(self.of_type, "__parameters__", None)
116
+
117
+ return list(parameters) if parameters else []
118
+
119
+ elif isinstance(self.of_type, StrawberryType):
120
+ return self.of_type.type_params
121
+
122
+ else:
123
+ return []
124
+
125
+ def copy_with(
126
+ self,
127
+ type_var_map: Mapping[
128
+ str, Union[StrawberryType, Type[WithStrawberryObjectDefinition]]
129
+ ],
130
+ ) -> Self:
131
+ of_type_copy = self.of_type
132
+
133
+ if has_object_definition(self.of_type):
134
+ type_definition = self.of_type.__strawberry_definition__
135
+
136
+ if type_definition.is_graphql_generic:
137
+ of_type_copy = type_definition.copy_with(type_var_map)
138
+
139
+ elif (
140
+ isinstance(self.of_type, StrawberryType) and self.of_type.is_graphql_generic
141
+ ):
142
+ of_type_copy = self.of_type.copy_with(type_var_map)
143
+
144
+ return type(self)(of_type_copy)
145
+
146
+ @property
147
+ def is_graphql_generic(self) -> bool:
148
+ from strawberry.schema.compat import is_graphql_generic
149
+
150
+ type_ = self.of_type
151
+
152
+ return is_graphql_generic(type_)
153
+
154
+ def has_generic(self, type_var: TypeVar) -> bool:
155
+ if isinstance(self.of_type, StrawberryType):
156
+ return self.of_type.has_generic(type_var)
157
+ return False
158
+
159
+
160
+ class StrawberryList(StrawberryContainer): ...
161
+
162
+
163
+ class StrawberryOptional(StrawberryContainer): ...
164
+
165
+
166
+ class StrawberryTypeVar(StrawberryType):
167
+ def __init__(self, type_var: TypeVar) -> None:
168
+ self.type_var = type_var
169
+
170
+ def copy_with(
171
+ self, type_var_map: Mapping[str, Union[StrawberryType, type]]
172
+ ) -> Union[StrawberryType, type]:
173
+ return type_var_map[self.type_var.__name__]
174
+
175
+ @property
176
+ def is_graphql_generic(self) -> bool:
177
+ return True
178
+
179
+ def has_generic(self, type_var: TypeVar) -> bool:
180
+ return self.type_var == type_var
181
+
182
+ @property
183
+ def type_params(self) -> List[TypeVar]:
184
+ return [self.type_var]
185
+
186
+ def __eq__(self, other: object) -> bool:
187
+ if isinstance(other, StrawberryTypeVar):
188
+ return self.type_var == other.type_var
189
+ if isinstance(other, TypeVar):
190
+ return self.type_var == other
191
+
192
+ return super().__eq__(other)
193
+
194
+ def __hash__(self) -> int:
195
+ return hash(self.type_var)
196
+
197
+
198
+ class WithStrawberryObjectDefinition(Protocol):
199
+ __strawberry_definition__: ClassVar[StrawberryObjectDefinition]
200
+
201
+
202
+ def has_object_definition(
203
+ obj: Any,
204
+ ) -> TypeGuard[Type[WithStrawberryObjectDefinition]]:
205
+ if hasattr(obj, "__strawberry_definition__"):
206
+ return True
207
+ # TODO: Generics remove dunder members here, so we inject it here.
208
+ # Would be better to avoid it somehow.
209
+ # https://github.com/python/cpython/blob/3a314f7c3df0dd7c37da7d12b827f169ee60e1ea/Lib/typing.py#L1152
210
+ if is_concrete_generic(obj):
211
+ concrete = obj.__origin__
212
+ if hasattr(concrete, "__strawberry_definition__"):
213
+ obj.__strawberry_definition__ = concrete.__strawberry_definition__
214
+ return True
215
+ return False
216
+
217
+
218
+ @overload
219
+ def get_object_definition(
220
+ obj: Any,
221
+ *,
222
+ strict: Literal[True],
223
+ ) -> StrawberryObjectDefinition: ...
224
+
225
+
226
+ @overload
227
+ def get_object_definition(
228
+ obj: Any,
229
+ *,
230
+ strict: bool = False,
231
+ ) -> Optional[StrawberryObjectDefinition]: ...
232
+
233
+
234
+ def get_object_definition(
235
+ obj: Any,
236
+ *,
237
+ strict: bool = False,
238
+ ) -> Optional[StrawberryObjectDefinition]:
239
+ definition = obj.__strawberry_definition__ if has_object_definition(obj) else None
240
+ if strict and definition is None:
241
+ raise TypeError(f"{obj!r} does not have a StrawberryObjectDefinition")
242
+
243
+ return definition
33
244
 
34
245
 
35
246
  @dataclasses.dataclass(eq=False)
36
247
  class StrawberryObjectDefinition(StrawberryType):
37
- """
38
- Encapsulates definitions for Input / Object / interface GraphQL Types.
248
+ """Encapsulates definitions for Input / Object / interface GraphQL Types.
39
249
 
40
250
  In order get the definition from a decorated object you can use
41
251
  `has_object_definition` or `get_object_definition` as a shortcut.
@@ -247,3 +457,17 @@ if TYPE_CHECKING:
247
457
 
248
458
  else:
249
459
  TypeDefinition = StrawberryObjectDefinition
460
+
461
+
462
+ __all__ = [
463
+ "StrawberryContainer",
464
+ "StrawberryList",
465
+ "StrawberryObjectDefinition",
466
+ "StrawberryOptional",
467
+ "StrawberryType",
468
+ "StrawberryTypeVar",
469
+ "TypeDefinition",
470
+ "WithStrawberryObjectDefinition",
471
+ "get_object_definition",
472
+ "has_object_definition",
473
+ ]
@@ -12,9 +12,8 @@ from typing import (
12
12
  overload,
13
13
  )
14
14
 
15
- from strawberry.type import StrawberryType
16
-
17
- from .exceptions import ObjectIsNotAnEnumError
15
+ from strawberry.exceptions import ObjectIsNotAnEnumError
16
+ from strawberry.types.base import StrawberryType
18
17
 
19
18
 
20
19
  @dataclasses.dataclass
@@ -67,6 +66,30 @@ def enum_value(
67
66
  directives: Iterable[object] = (),
68
67
  description: Optional[str] = None,
69
68
  ) -> EnumValueDefinition:
69
+ """Function to customise an enum value, for example to add a description or deprecation reason.
70
+
71
+ Args:
72
+ value: The value of the enum member.
73
+ deprecation_reason: The deprecation reason of the enum member,
74
+ setting this will mark the enum member as deprecated.
75
+ directives: The directives to attach to the enum member.
76
+ description: The GraphQL description of the enum member.
77
+
78
+ Returns:
79
+ An EnumValueDefinition object that can be used to customise an enum member.
80
+
81
+ Example:
82
+ ```python
83
+ from enum import Enum
84
+ import strawberry
85
+
86
+
87
+ @strawberry.enum
88
+ class MyEnum(Enum):
89
+ FIRST_VALUE = strawberry.enum_value(description="The first value")
90
+ SECOND_VALUE = strawberry.enum_value(description="The second value")
91
+ ```
92
+ """
70
93
  return EnumValueDefinition(
71
94
  value=value,
72
95
  deprecation_reason=deprecation_reason,
@@ -131,7 +154,7 @@ def _process_enum(
131
154
 
132
155
  @overload
133
156
  def enum(
134
- _cls: EnumType,
157
+ cls: EnumType,
135
158
  *,
136
159
  name: Optional[str] = None,
137
160
  description: Optional[str] = None,
@@ -141,7 +164,7 @@ def enum(
141
164
 
142
165
  @overload
143
166
  def enum(
144
- _cls: None = None,
167
+ cls: None = None,
145
168
  *,
146
169
  name: Optional[str] = None,
147
170
  description: Optional[str] = None,
@@ -150,13 +173,47 @@ def enum(
150
173
 
151
174
 
152
175
  def enum(
153
- _cls: Optional[EnumType] = None,
176
+ cls: Optional[EnumType] = None,
154
177
  *,
155
178
  name: Optional[str] = None,
156
179
  description: Optional[str] = None,
157
180
  directives: Iterable[object] = (),
158
181
  ) -> Union[EnumType, Callable[[EnumType], EnumType]]:
159
- """Registers the enum in the GraphQL type system.
182
+ """Annotates an Enum class a GraphQL enum.
183
+
184
+ GraphQL enums only have names, while Python enums have names and values,
185
+ Strawberry will use the names of the Python enum as the names of the
186
+ GraphQL enum values.
187
+
188
+ Args:
189
+ cls: The Enum class to be annotated.
190
+ name: The name of the GraphQL enum.
191
+ description: The description of the GraphQL enum.
192
+ directives: The directives to attach to the GraphQL enum.
193
+
194
+ Returns:
195
+ The decorated Enum class.
196
+
197
+ Example:
198
+ ```python
199
+ from enum import Enum
200
+ import strawberry
201
+
202
+
203
+ @strawberry.enum
204
+ class MyEnum(Enum):
205
+ FIRST_VALUE = "first_value"
206
+ SECOND_VALUE = "second_value"
207
+ ```
208
+
209
+ The above code will generate the following GraphQL schema:
210
+
211
+ ```graphql
212
+ enum MyEnum {
213
+ FIRST_VALUE
214
+ SECOND_VALUE
215
+ }
216
+ ```
160
217
 
161
218
  If name is passed, the name of the GraphQL type will be
162
219
  the value passed of name instead of the Enum class name.
@@ -165,7 +222,10 @@ def enum(
165
222
  def wrap(cls: EnumType) -> EnumType:
166
223
  return _process_enum(cls, name, description, directives=directives)
167
224
 
168
- if not _cls:
225
+ if not cls:
169
226
  return wrap
170
227
 
171
- return wrap(_cls)
228
+ return wrap(cls)
229
+
230
+
231
+ __all__ = ["EnumValue", "EnumDefinition", "EnumValueDefinition", "enum", "enum_value"]
@@ -94,3 +94,6 @@ class ExecutionResult:
94
94
 
95
95
  class ParseOptions(TypedDict):
96
96
  max_tokens: NotRequired[int]
97
+
98
+
99
+ __all__ = ["ExecutionContext", "ExecutionResult", "ParseOptions"]
@@ -24,25 +24,24 @@ from typing import (
24
24
 
25
25
  from strawberry.annotation import StrawberryAnnotation
26
26
  from strawberry.exceptions import InvalidArgumentTypeError, InvalidDefaultFactoryError
27
- from strawberry.type import (
27
+ from strawberry.types.base import (
28
28
  StrawberryType,
29
29
  WithStrawberryObjectDefinition,
30
30
  has_object_definition,
31
31
  )
32
- from strawberry.union import StrawberryUnion
32
+ from strawberry.types.union import StrawberryUnion
33
33
 
34
- from .types.fields.resolver import StrawberryResolver
34
+ from .fields.resolver import StrawberryResolver
35
35
 
36
36
  if TYPE_CHECKING:
37
37
  import builtins
38
38
  from typing_extensions import Literal, Self
39
39
 
40
- from strawberry.arguments import StrawberryArgument
41
40
  from strawberry.extensions.field_extension import FieldExtension
41
+ from strawberry.permission import BasePermission
42
+ from strawberry.types.arguments import StrawberryArgument
43
+ from strawberry.types.base import StrawberryObjectDefinition
42
44
  from strawberry.types.info import Info
43
- from strawberry.types.types import StrawberryObjectDefinition
44
-
45
- from .permission import BasePermission
46
45
 
47
46
  T = TypeVar("T")
48
47
 
@@ -64,7 +63,7 @@ UNRESOLVED = object()
64
63
 
65
64
 
66
65
  def _is_generic(resolver_type: Union[StrawberryType, type]) -> bool:
67
- """Returns True if `resolver_type` is generic else False"""
66
+ """Returns True if `resolver_type` is generic else False."""
68
67
  if isinstance(resolver_type, StrawberryType):
69
68
  return resolver_type.is_graphql_generic
70
69
 
@@ -149,7 +148,7 @@ class StrawberryField(dataclasses.Field):
149
148
 
150
149
  # Automatically add the permissions extension
151
150
  if len(self.permission_classes):
152
- from .permission import PermissionExtension
151
+ from strawberry.permission import PermissionExtension
153
152
 
154
153
  if not self.extensions:
155
154
  self.extensions = []
@@ -189,8 +188,7 @@ class StrawberryField(dataclasses.Field):
189
188
  return new_field
190
189
 
191
190
  def __call__(self, resolver: _RESOLVER_TYPE) -> Self:
192
- """Add a resolver to the field"""
193
-
191
+ """Add a resolver to the field."""
194
192
  # Allow for StrawberryResolvers or bare functions to be provided
195
193
  if not isinstance(resolver, StrawberryResolver):
196
194
  resolver = StrawberryResolver(resolver)
@@ -217,12 +215,11 @@ class StrawberryField(dataclasses.Field):
217
215
  def get_result(
218
216
  self, source: Any, info: Optional[Info], args: List[Any], kwargs: Any
219
217
  ) -> Union[Awaitable[Any], Any]:
220
- """
221
- Calls the resolver defined for the StrawberryField.
218
+ """Calls the resolver defined for the StrawberryField.
219
+
222
220
  If the field doesn't have a resolver defined we default
223
221
  to using the default resolver specified in StrawberryConfig.
224
222
  """
225
-
226
223
  if self.base_resolver:
227
224
  return self.base_resolver(*args, **kwargs)
228
225
 
@@ -230,8 +227,9 @@ class StrawberryField(dataclasses.Field):
230
227
 
231
228
  @property
232
229
  def is_basic_field(self) -> bool:
233
- """
234
- Flag indicating if this is a "basic" field that has no resolver or
230
+ """Returns a boolean indicating if the field is a basic field.
231
+
232
+ A "basic" field us a field that has no resolver or
235
233
  permission classes, i.e. it just returns the relevant attribute from
236
234
  the source object. If it is a basic field we can avoid constructing
237
235
  an `Info` object and running any permission checks in the resolver
@@ -538,19 +536,44 @@ def field(
538
536
  ) -> Any:
539
537
  """Annotates a method or property as a GraphQL field.
540
538
 
539
+ Args:
540
+ resolver: The resolver for the field. This can be a function or a `StrawberryResolver`.
541
+ name: The GraphQL name of the field.
542
+ is_subscription: Whether the field is a subscription field.
543
+ description: The GraphQL description of the field.
544
+ permission_classes: The permission classes required to access the field.
545
+ deprecation_reason: The deprecation reason for the field.
546
+ default: The default value for the field.
547
+ default_factory: The default factory for the field.
548
+ metadata: The metadata for the field.
549
+ directives: The directives for the field.
550
+ extensions: The extensions for the field.
551
+ graphql_type: The GraphQL type for the field, useful when you want to use a
552
+ different type in the resolver than the one in the schema.
553
+ init: This parameter is used by PyRight to determine whether this field is
554
+ added in the constructor or not. It is not used to change any behavior
555
+ at the moment.
556
+
557
+ Returns:
558
+ The field.
559
+
541
560
  This is normally used inside a type declaration:
542
561
 
543
- >>> @strawberry.type
544
- >>> class X:
545
- >>> field_abc: str = strawberry.field(description="ABC")
562
+ ```python
563
+ import strawberry
564
+
546
565
 
547
- >>> @strawberry.field(description="ABC")
548
- >>> def field_with_resolver(self) -> str:
549
- >>> return "abc"
566
+ @strawberry.type
567
+ class X:
568
+ field_abc: str = strawberry.field(description="ABC")
569
+
570
+ @strawberry.field(description="ABC")
571
+ def field_with_resolver(self) -> str:
572
+ return "abc"
573
+ ```
550
574
 
551
575
  it can be used both as decorator and as a normal function.
552
576
  """
553
-
554
577
  type_annotation = StrawberryAnnotation.from_annotation(graphql_type)
555
578
 
556
579
  field_ = StrawberryField(
@@ -23,13 +23,13 @@ from typing import (
23
23
  from typing_extensions import Annotated, Protocol, get_origin
24
24
 
25
25
  from strawberry.annotation import StrawberryAnnotation
26
- from strawberry.arguments import StrawberryArgument
27
26
  from strawberry.exceptions import (
28
27
  ConflictingArgumentsError,
29
28
  MissingArgumentsAnnotationsError,
30
29
  )
31
30
  from strawberry.parent import StrawberryParent
32
- from strawberry.type import StrawberryType, has_object_definition
31
+ from strawberry.types.arguments import StrawberryArgument
32
+ from strawberry.types.base import StrawberryType, has_object_definition
33
33
  from strawberry.types.info import Info
34
34
  from strawberry.utils.typing import type_has_annotation
35
35
 
@@ -25,3 +25,6 @@ class OperationType(enum.Enum):
25
25
  }
26
26
 
27
27
  raise ValueError(f"Unsupported HTTP method: {method}") # pragma: no cover
28
+
29
+
30
+ __all__ = ["OperationType"]
strawberry/types/info.py CHANGED
@@ -23,10 +23,13 @@ if TYPE_CHECKING:
23
23
  from graphql.language import FieldNode
24
24
  from graphql.pyutils.path import Path
25
25
 
26
- from strawberry.arguments import StrawberryArgument
27
- from strawberry.field import StrawberryField
28
26
  from strawberry.schema import Schema
29
- from strawberry.type import StrawberryType, WithStrawberryObjectDefinition
27
+ from strawberry.types.arguments import StrawberryArgument
28
+ from strawberry.types.base import (
29
+ StrawberryType,
30
+ WithStrawberryObjectDefinition,
31
+ )
32
+ from strawberry.types.field import StrawberryField
30
33
 
31
34
  from .nodes import Selection
32
35
 
@@ -36,6 +39,36 @@ RootValueType = TypeVar("RootValueType", default=Any)
36
39
 
37
40
  @dataclasses.dataclass
38
41
  class Info(Generic[ContextType, RootValueType]):
42
+ """Class containing information about the current execution.
43
+
44
+ This class is passed to resolvers when there's an argument with type `Info`.
45
+
46
+ Example:
47
+ ```python
48
+ import strawberry
49
+
50
+
51
+ @strawberry.type
52
+ class Query:
53
+ @strawberry.field
54
+ def hello(self, info: strawberry.Info) -> str:
55
+ return f"Hello, {info.context['name']}!"
56
+ ```
57
+
58
+ It also supports passing the type of the context and root types:
59
+
60
+ ```python
61
+ import strawberry
62
+
63
+
64
+ @strawberry.type
65
+ class Query:
66
+ @strawberry.field
67
+ def hello(self, info: strawberry.Info[str, str]) -> str:
68
+ return f"Hello, {info.context}!"
69
+ ```
70
+ """
71
+
39
72
  _raw_info: GraphQLResolveInfo
40
73
  _field: StrawberryField
41
74
 
@@ -48,7 +81,6 @@ class Info(Generic[ContextType, RootValueType]):
48
81
  See:
49
82
  https://discuss.python.org/t/passing-only-one-typevar-of-two-when-using-defaults/49134
50
83
  """
51
-
52
84
  if not isinstance(types, tuple):
53
85
  types = (types, Any) # type: ignore
54
86
 
@@ -56,10 +88,12 @@ class Info(Generic[ContextType, RootValueType]):
56
88
 
57
89
  @property
58
90
  def field_name(self) -> str:
91
+ """The name of the current field being resolved."""
59
92
  return self._raw_info.field_name
60
93
 
61
94
  @property
62
95
  def schema(self) -> Schema:
96
+ """The schema of the current execution."""
63
97
  return self._raw_info.schema._strawberry_schema # type: ignore
64
98
 
65
99
  @property
@@ -74,48 +108,57 @@ class Info(Generic[ContextType, RootValueType]):
74
108
 
75
109
  @cached_property
76
110
  def selected_fields(self) -> List[Selection]:
111
+ """The fields that were selected on the current field's type."""
77
112
  info = self._raw_info
78
113
  return convert_selections(info, info.field_nodes)
79
114
 
80
115
  @property
81
116
  def context(self) -> ContextType:
117
+ """The context passed to the query execution."""
82
118
  return self._raw_info.context
83
119
 
84
120
  @property
85
121
  def root_value(self) -> RootValueType:
122
+ """The root value passed to the query execution."""
86
123
  return self._raw_info.root_value
87
124
 
88
125
  @property
89
126
  def variable_values(self) -> Dict[str, Any]:
127
+ """The variable values passed to the query execution."""
90
128
  return self._raw_info.variable_values
91
129
 
92
130
  @property
93
131
  def return_type(
94
132
  self,
95
133
  ) -> Optional[Union[Type[WithStrawberryObjectDefinition], StrawberryType]]:
134
+ """The return type of the current field being resolved."""
96
135
  return self._field.type
97
136
 
98
137
  @property
99
138
  def python_name(self) -> str:
139
+ """The name of the current field being resolved in Python format."""
100
140
  return self._field.python_name
101
141
 
102
142
  # TODO: create an abstraction on these fields
103
143
  @property
104
144
  def operation(self) -> OperationDefinitionNode:
145
+ """The operation being executed."""
105
146
  return self._raw_info.operation
106
147
 
107
148
  @property
108
149
  def path(self) -> Path:
150
+ """The path of the current field being resolved."""
109
151
  return self._raw_info.path
110
152
 
111
153
  # TODO: parent_type as strawberry types
112
154
 
113
155
  # Helper functions
114
156
  def get_argument_definition(self, name: str) -> Optional[StrawberryArgument]:
115
- """
116
- Get the StrawberryArgument definition for the current field by name.
117
- """
157
+ """Get the StrawberryArgument definition for the current field by name."""
118
158
  try:
119
159
  return next(arg for arg in self._field.arguments if arg.python_name == name)
120
160
  except StopIteration:
121
161
  return None
162
+
163
+
164
+ __all__ = ["Info"]