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.
- 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 -22
- 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 +8 -2
- strawberry/http/__init__.py +9 -0
- strawberry/http/async_base_view.py +4 -3
- strawberry/http/base.py +5 -7
- 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 +5 -2
- 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 +5 -9
- 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} +50 -0
- 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.1.dev1719337273.dist-info → strawberry_graphql-0.236.0.dist-info}/METADATA +1 -1
- strawberry_graphql-0.236.0.dist-info/RECORD +255 -0
- strawberry/mutation.py +0 -8
- strawberry/type.py +0 -232
- strawberry_graphql-0.235.1.dev1719337273.dist-info/RECORD +0 -252
- {strawberry_graphql-0.235.1.dev1719337273.dist-info → strawberry_graphql-0.236.0.dist-info}/LICENSE +0 -0
- {strawberry_graphql-0.235.1.dev1719337273.dist-info → strawberry_graphql-0.236.0.dist-info}/WHEEL +0 -0
- {strawberry_graphql-0.235.1.dev1719337273.dist-info → strawberry_graphql-0.236.0.dist-info}/entry_points.txt +0 -0
@@ -16,25 +16,28 @@ from typing import (
|
|
16
16
|
from typing_extensions import Annotated, get_args, get_origin
|
17
17
|
|
18
18
|
from strawberry.annotation import StrawberryAnnotation
|
19
|
-
from strawberry.
|
20
|
-
from strawberry.
|
21
|
-
from strawberry.
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
from .
|
19
|
+
from strawberry.exceptions import MultipleStrawberryArgumentsError, UnsupportedTypeError
|
20
|
+
from strawberry.scalars import is_scalar
|
21
|
+
from strawberry.types.base import (
|
22
|
+
StrawberryList,
|
23
|
+
StrawberryOptional,
|
24
|
+
has_object_definition,
|
25
|
+
)
|
26
|
+
from strawberry.types.enum import EnumDefinition
|
27
|
+
from strawberry.types.lazy_type import LazyType, StrawberryLazyReference
|
28
|
+
from strawberry.types.unset import UNSET as _deprecated_UNSET
|
29
|
+
from strawberry.types.unset import _deprecated_is_unset # noqa # type: ignore
|
27
30
|
|
28
31
|
if TYPE_CHECKING:
|
29
|
-
from strawberry.custom_scalar import ScalarDefinition, ScalarWrapper
|
30
32
|
from strawberry.schema.config import StrawberryConfig
|
31
|
-
from strawberry.
|
33
|
+
from strawberry.types.base import StrawberryType
|
34
|
+
from strawberry.types.scalar import ScalarDefinition, ScalarWrapper
|
32
35
|
|
33
36
|
|
34
37
|
DEPRECATED_NAMES: Dict[str, str] = {
|
35
38
|
"UNSET": (
|
36
39
|
"importing `UNSET` from `strawberry.arguments` is deprecated, "
|
37
|
-
"import instead from `strawberry` or from `strawberry.unset`"
|
40
|
+
"import instead from `strawberry` or from `strawberry.types.unset`"
|
38
41
|
),
|
39
42
|
"is_unset": "`is_unset` is deprecated use `value is UNSET` instead",
|
40
43
|
}
|
@@ -202,8 +205,8 @@ def convert_arguments(
|
|
202
205
|
"""Converts a nested dictionary to a dictionary of actual types.
|
203
206
|
|
204
207
|
It deals with conversion of input types to proper dataclasses and
|
205
|
-
also uses a sentinel value for unset values.
|
206
|
-
|
208
|
+
also uses a sentinel value for unset values.
|
209
|
+
"""
|
207
210
|
if not arguments:
|
208
211
|
return {}
|
209
212
|
|
@@ -234,6 +237,34 @@ def argument(
|
|
234
237
|
directives: Iterable[object] = (),
|
235
238
|
metadata: Optional[Mapping[Any, Any]] = None,
|
236
239
|
) -> StrawberryArgumentAnnotation:
|
240
|
+
"""Function to add metadata to an argument, like a description or deprecation reason.
|
241
|
+
|
242
|
+
Args:
|
243
|
+
description: The GraphQL description of the argument
|
244
|
+
name: The GraphQL name of the argument
|
245
|
+
deprecation_reason: The reason why this argument is deprecated,
|
246
|
+
setting this will mark the argument as deprecated
|
247
|
+
directives: The directives to attach to the argument
|
248
|
+
metadata: Metadata to attach to the argument, this can be used
|
249
|
+
to store custom data that can be used by custom logic or plugins
|
250
|
+
|
251
|
+
Returns:
|
252
|
+
A StrawberryArgumentAnnotation object that can be used to customise an argument
|
253
|
+
|
254
|
+
Example:
|
255
|
+
```python
|
256
|
+
import strawberry
|
257
|
+
|
258
|
+
|
259
|
+
@strawberry.type
|
260
|
+
class Query:
|
261
|
+
@strawberry.field
|
262
|
+
def example(
|
263
|
+
self, info, value: int = strawberry.argument(description="The value")
|
264
|
+
) -> int:
|
265
|
+
return value
|
266
|
+
```
|
267
|
+
"""
|
237
268
|
return StrawberryArgumentAnnotation(
|
238
269
|
description=description,
|
239
270
|
name=name,
|
@@ -3,9 +3,8 @@ from __future__ import annotations
|
|
3
3
|
from typing import Any, Optional, Union, cast
|
4
4
|
from typing_extensions import Annotated, get_args, get_origin
|
5
5
|
|
6
|
-
from strawberry.
|
7
|
-
|
8
|
-
from .annotation import StrawberryAnnotation
|
6
|
+
from strawberry.annotation import StrawberryAnnotation
|
7
|
+
from strawberry.types.base import StrawberryType
|
9
8
|
|
10
9
|
|
11
10
|
class StrawberryAutoMeta(type):
|
@@ -77,3 +76,22 @@ class StrawberryAuto(metaclass=StrawberryAutoMeta):
|
|
77
76
|
|
78
77
|
|
79
78
|
auto = Annotated[Any, StrawberryAuto()]
|
79
|
+
"""Special marker for automatic annotation.
|
80
|
+
|
81
|
+
A special value that can be used to automatically infer the type of a field
|
82
|
+
when using integrations like Strawberry Django or Strawberry Pydantic.
|
83
|
+
|
84
|
+
Example:
|
85
|
+
```python
|
86
|
+
import strawberry
|
87
|
+
|
88
|
+
from my_user_app import models
|
89
|
+
|
90
|
+
|
91
|
+
@strawberry.django.type(models.User)
|
92
|
+
class User:
|
93
|
+
name: strawberry.auto
|
94
|
+
```
|
95
|
+
"""
|
96
|
+
|
97
|
+
__all__ = ["auto"]
|
@@ -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
|
|