strawberry-graphql 0.235.2__py3-none-any.whl → 0.236.1__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.
- strawberry/__init__.py +17 -11
- strawberry/aiohttp/handlers/graphql_transport_ws_handler.py +3 -0
- strawberry/aiohttp/handlers/graphql_ws_handler.py +3 -0
- strawberry/aiohttp/test/client.py +3 -0
- strawberry/aiohttp/views.py +3 -0
- strawberry/annotation.py +19 -19
- strawberry/asgi/__init__.py +3 -3
- strawberry/asgi/handlers/graphql_transport_ws_handler.py +3 -0
- strawberry/asgi/handlers/graphql_ws_handler.py +3 -0
- strawberry/asgi/test/client.py +3 -0
- strawberry/chalice/views.py +12 -3
- strawberry/channels/handlers/__init__.py +0 -0
- strawberry/channels/handlers/base.py +5 -5
- strawberry/channels/handlers/graphql_transport_ws_handler.py +3 -0
- strawberry/channels/handlers/graphql_ws_handler.py +3 -0
- strawberry/channels/handlers/http_handler.py +5 -2
- strawberry/channels/handlers/ws_handler.py +4 -1
- strawberry/channels/router.py +9 -5
- strawberry/channels/testing.py +11 -4
- strawberry/cli/commands/upgrade/__init__.py +13 -5
- strawberry/cli/commands/upgrade/_fake_progress.py +2 -1
- strawberry/cli/commands/upgrade/_run_codemod.py +18 -1
- strawberry/codegen/exceptions.py +8 -0
- strawberry/codegen/query_codegen.py +16 -7
- strawberry/codegen/types.py +32 -1
- strawberry/codemods/update_imports.py +136 -0
- strawberry/dataloader.py +13 -0
- strawberry/directive.py +52 -4
- strawberry/django/context.py +4 -1
- strawberry/django/test/client.py +3 -0
- strawberry/django/views.py +3 -0
- strawberry/exceptions/__init__.py +5 -5
- strawberry/exceptions/duplicated_type_name.py +1 -1
- strawberry/exceptions/invalid_argument_type.py +3 -3
- strawberry/exceptions/invalid_union_type.py +5 -6
- strawberry/exceptions/missing_arguments_annotations.py +1 -1
- strawberry/exceptions/missing_dependencies.py +10 -2
- strawberry/exceptions/missing_return_annotation.py +1 -1
- strawberry/exceptions/permission_fail_silently_requires_optional.py +3 -3
- strawberry/exceptions/scalar_already_registered.py +1 -1
- strawberry/exceptions/unresolved_field_type.py +2 -2
- strawberry/exceptions/utils/source_finder.py +5 -2
- strawberry/experimental/pydantic/conversion.py +5 -5
- strawberry/experimental/pydantic/conversion_types.py +4 -2
- strawberry/experimental/pydantic/error_type.py +2 -2
- strawberry/experimental/pydantic/fields.py +2 -2
- strawberry/experimental/pydantic/object_type.py +11 -7
- strawberry/experimental/pydantic/utils.py +4 -5
- strawberry/ext/dataclasses/dataclasses.py +2 -1
- strawberry/ext/mypy_plugin.py +10 -8
- strawberry/extensions/add_validation_rules.py +27 -23
- strawberry/extensions/base_extension.py +6 -4
- strawberry/extensions/directives.py +4 -1
- strawberry/extensions/disable_validation.py +15 -12
- strawberry/extensions/field_extension.py +11 -5
- strawberry/extensions/mask_errors.py +3 -0
- strawberry/extensions/max_aliases.py +21 -19
- strawberry/extensions/max_tokens.py +14 -16
- strawberry/extensions/parser_cache.py +22 -19
- strawberry/extensions/pyinstrument.py +4 -8
- strawberry/extensions/query_depth_limiter.py +22 -23
- strawberry/extensions/runner.py +3 -0
- strawberry/extensions/tracing/apollo.py +3 -0
- strawberry/extensions/tracing/datadog.py +7 -2
- strawberry/extensions/tracing/opentelemetry.py +3 -0
- strawberry/extensions/tracing/sentry.py +3 -0
- strawberry/extensions/tracing/utils.py +3 -0
- strawberry/extensions/utils.py +3 -0
- strawberry/extensions/validation_cache.py +23 -20
- strawberry/fastapi/context.py +3 -0
- strawberry/fastapi/handlers/graphql_transport_ws_handler.py +3 -0
- strawberry/fastapi/handlers/graphql_ws_handler.py +3 -0
- strawberry/fastapi/router.py +3 -0
- strawberry/federation/argument.py +4 -1
- strawberry/federation/enum.py +5 -3
- strawberry/federation/field.py +6 -3
- strawberry/federation/mutation.py +2 -0
- strawberry/federation/object_type.py +7 -4
- strawberry/federation/scalar.py +43 -20
- strawberry/federation/schema.py +12 -9
- strawberry/federation/schema_directive.py +2 -2
- strawberry/federation/schema_directives.py +19 -1
- strawberry/federation/types.py +5 -2
- strawberry/federation/union.py +27 -8
- strawberry/field_extensions/input_mutation.py +5 -2
- strawberry/file_uploads/scalars.py +3 -1
- strawberry/file_uploads/utils.py +3 -0
- strawberry/flask/views.py +6 -0
- strawberry/http/__init__.py +9 -0
- strawberry/http/async_base_view.py +4 -3
- strawberry/http/base.py +3 -0
- strawberry/http/exceptions.py +3 -0
- strawberry/http/ides.py +3 -0
- strawberry/http/sync_base_view.py +4 -3
- strawberry/http/temporal_response.py +3 -0
- strawberry/http/types.py +3 -0
- strawberry/http/typevars.py +3 -0
- strawberry/litestar/controller.py +6 -0
- strawberry/litestar/handlers/__init__.py +0 -0
- strawberry/litestar/handlers/graphql_transport_ws_handler.py +3 -0
- strawberry/litestar/handlers/graphql_ws_handler.py +3 -0
- strawberry/parent.py +27 -21
- strawberry/permission.py +70 -27
- strawberry/printer/ast_from_value.py +4 -1
- strawberry/printer/printer.py +8 -5
- strawberry/quart/views.py +3 -0
- strawberry/relay/exceptions.py +7 -0
- strawberry/relay/fields.py +70 -45
- strawberry/relay/types.py +78 -78
- strawberry/relay/utils.py +10 -1
- strawberry/resolvers.py +3 -0
- strawberry/sanic/context.py +3 -0
- strawberry/sanic/utils.py +10 -8
- strawberry/sanic/views.py +4 -2
- strawberry/scalars.py +6 -2
- strawberry/schema/base.py +7 -4
- strawberry/schema/compat.py +12 -2
- strawberry/schema/config.py +3 -0
- strawberry/schema/exceptions.py +3 -0
- strawberry/schema/execute.py +3 -0
- strawberry/schema/name_converter.py +12 -9
- strawberry/schema/schema.py +46 -9
- strawberry/schema/schema_converter.py +16 -14
- strawberry/schema/types/base_scalars.py +3 -1
- strawberry/schema/types/concrete_type.py +4 -4
- strawberry/schema/types/scalar.py +8 -1
- strawberry/schema/validation_rules/one_of.py +3 -0
- strawberry/schema_codegen/__init__.py +3 -0
- strawberry/schema_directive.py +2 -2
- strawberry/starlite/controller.py +3 -0
- strawberry/starlite/handlers/__init__.py +0 -0
- strawberry/starlite/handlers/graphql_transport_ws_handler.py +3 -0
- strawberry/starlite/handlers/graphql_ws_handler.py +3 -0
- strawberry/subscriptions/__init__.py +6 -0
- strawberry/subscriptions/protocols/graphql_transport_ws/__init__.py +5 -0
- strawberry/subscriptions/protocols/graphql_transport_ws/handlers.py +12 -17
- strawberry/subscriptions/protocols/graphql_transport_ws/types.py +21 -25
- strawberry/subscriptions/protocols/graphql_ws/__init__.py +14 -0
- strawberry/subscriptions/protocols/graphql_ws/handlers.py +8 -5
- strawberry/subscriptions/protocols/graphql_ws/types.py +11 -0
- strawberry/test/client.py +44 -29
- strawberry/tools/create_type.py +27 -8
- strawberry/tools/merge_types.py +5 -3
- strawberry/types/__init__.py +8 -1
- strawberry/{arguments.py → types/arguments.py} +44 -13
- strawberry/{auto.py → types/auto.py} +21 -3
- strawberry/types/{types.py → base.py} +234 -10
- strawberry/{enum.py → types/enum.py} +69 -9
- strawberry/types/execution.py +3 -0
- strawberry/{field.py → types/field.py} +46 -23
- strawberry/types/fields/resolver.py +2 -2
- strawberry/types/graphql.py +3 -0
- strawberry/types/info.py +50 -7
- strawberry/{lazy_type.py → types/lazy_type.py} +56 -4
- strawberry/types/mutation.py +351 -0
- strawberry/types/nodes.py +4 -2
- strawberry/{object_type.py → types/object_type.py} +108 -29
- strawberry/{private.py → types/private.py} +13 -6
- strawberry/{custom_scalar.py → types/scalar.py} +39 -23
- strawberry/types/type_resolver.py +21 -16
- strawberry/{union.py → types/union.py} +24 -9
- strawberry/{unset.py → types/unset.py} +20 -0
- strawberry/utils/aio.py +8 -0
- strawberry/utils/await_maybe.py +3 -0
- strawberry/utils/dataclasses.py +3 -0
- strawberry/utils/debug.py +5 -2
- strawberry/utils/deprecations.py +3 -0
- strawberry/utils/graphql_lexer.py +3 -0
- strawberry/utils/importer.py +3 -0
- strawberry/utils/inspect.py +39 -30
- strawberry/utils/logging.py +3 -0
- strawberry/utils/operation.py +3 -0
- strawberry/utils/str_converters.py +3 -0
- strawberry/utils/typing.py +33 -16
- {strawberry_graphql-0.235.2.dist-info → strawberry_graphql-0.236.1.dist-info}/METADATA +1 -1
- strawberry_graphql-0.236.1.dist-info/RECORD +255 -0
- strawberry/mutation.py +0 -8
- strawberry/type.py +0 -232
- strawberry_graphql-0.235.2.dist-info/RECORD +0 -252
- {strawberry_graphql-0.235.2.dist-info → strawberry_graphql-0.236.1.dist-info}/LICENSE +0 -0
- {strawberry_graphql-0.235.2.dist-info → strawberry_graphql-0.236.1.dist-info}/WHEEL +0 -0
- {strawberry_graphql-0.235.2.dist-info → strawberry_graphql-0.236.1.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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
"""
|
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
|
225
|
+
if not cls:
|
169
226
|
return wrap
|
170
227
|
|
171
|
-
return wrap(
|
228
|
+
return wrap(cls)
|
229
|
+
|
230
|
+
|
231
|
+
__all__ = ["EnumValue", "EnumDefinition", "EnumValueDefinition", "enum", "enum_value"]
|
strawberry/types/execution.py
CHANGED
@@ -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.
|
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 .
|
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
|
-
|
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
|
-
|
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
|
-
|
544
|
-
|
545
|
-
|
562
|
+
```python
|
563
|
+
import strawberry
|
564
|
+
|
546
565
|
|
547
|
-
|
548
|
-
|
549
|
-
|
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.
|
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
|
|
strawberry/types/graphql.py
CHANGED
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.
|
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"]
|