strawberry-graphql 0.288.0__py3-none-any.whl → 0.288.2__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.
@@ -1,9 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import (
4
- TYPE_CHECKING,
5
- Any,
6
- )
3
+ from typing import Any
7
4
 
8
5
  import strawberry
9
6
  from strawberry.annotation import StrawberryAnnotation
@@ -16,9 +13,6 @@ from strawberry.types.arguments import StrawberryArgument
16
13
  from strawberry.types.field import StrawberryField
17
14
  from strawberry.utils.str_converters import capitalize_first, to_camel_case
18
15
 
19
- if TYPE_CHECKING:
20
- from strawberry.types.info import Info
21
-
22
16
 
23
17
  class InputMutationExtension(FieldExtension):
24
18
  def apply(self, field: StrawberryField) -> None:
@@ -64,7 +58,7 @@ class InputMutationExtension(FieldExtension):
64
58
  self,
65
59
  next_: SyncExtensionResolver,
66
60
  source: Any,
67
- info: Info,
61
+ info: strawberry.Info,
68
62
  **kwargs: Any,
69
63
  ) -> Any:
70
64
  input_args = kwargs.pop("input")
@@ -79,7 +73,7 @@ class InputMutationExtension(FieldExtension):
79
73
  self,
80
74
  next_: AsyncExtensionResolver,
81
75
  source: Any,
82
- info: Info,
76
+ info: strawberry.Info,
83
77
  **kwargs: Any,
84
78
  ) -> Any:
85
79
  input_args = kwargs.pop("input")
@@ -49,8 +49,8 @@ from .types import Connection, GlobalID, Node
49
49
  if TYPE_CHECKING:
50
50
  from typing import Literal
51
51
 
52
+ import strawberry
52
53
  from strawberry.permission import BasePermission
53
- from strawberry.types.info import Info
54
54
 
55
55
 
56
56
  class NodeExtension(FieldExtension):
@@ -65,12 +65,20 @@ class NodeExtension(FieldExtension):
65
65
  field.base_resolver = StrawberryResolver(resolver, type_override=field.type)
66
66
 
67
67
  def resolve(
68
- self, next_: SyncExtensionResolver, source: Any, info: Info, **kwargs: Any
68
+ self,
69
+ next_: SyncExtensionResolver,
70
+ source: Any,
71
+ info: strawberry.Info,
72
+ **kwargs: Any,
69
73
  ) -> Any:
70
74
  return next_(source, info, **kwargs)
71
75
 
72
76
  async def resolve_async(
73
- self, next_: SyncExtensionResolver, source: Any, info: Info, **kwargs: Any
77
+ self,
78
+ next_: SyncExtensionResolver,
79
+ source: Any,
80
+ info: strawberry.Info,
81
+ **kwargs: Any,
74
82
  ) -> Any:
75
83
  retval = next_(source, info, **kwargs)
76
84
  # If the resolve_nodes method is not async, retval will not actually
@@ -81,12 +89,12 @@ class NodeExtension(FieldExtension):
81
89
 
82
90
  def get_node_resolver(
83
91
  self, field: StrawberryField
84
- ) -> Callable[[Info, GlobalID], Node | None | Awaitable[Node | None]]:
92
+ ) -> Callable[[strawberry.Info, GlobalID], Node | None | Awaitable[Node | None]]:
85
93
  type_ = field.type
86
94
  is_optional = isinstance(type_, StrawberryOptional)
87
95
 
88
96
  def resolver(
89
- info: Info,
97
+ info: strawberry.Info,
90
98
  id: Annotated[GlobalID, argument(description="The ID of the object.")],
91
99
  ) -> Node | None | Awaitable[Node | None]:
92
100
  node_type = id.resolve_type(info)
@@ -114,13 +122,15 @@ class NodeExtension(FieldExtension):
114
122
 
115
123
  def get_node_list_resolver(
116
124
  self, field: StrawberryField
117
- ) -> Callable[[Info, list[GlobalID]], list[Node] | Awaitable[list[Node]]]:
125
+ ) -> Callable[
126
+ [strawberry.Info, list[GlobalID]], list[Node] | Awaitable[list[Node]]
127
+ ]:
118
128
  type_ = field.type
119
129
  assert isinstance(type_, StrawberryList)
120
130
  is_optional = isinstance(type_.of_type, StrawberryOptional)
121
131
 
122
132
  def resolver(
123
- info: Info,
133
+ info: strawberry.Info,
124
134
  ids: Annotated[
125
135
  list[GlobalID], argument(description="The IDs of the objects.")
126
136
  ],
@@ -306,7 +316,7 @@ class ConnectionExtension(FieldExtension):
306
316
  self,
307
317
  next_: SyncExtensionResolver,
308
318
  source: Any,
309
- info: Info,
319
+ info: strawberry.Info,
310
320
  *,
311
321
  before: str | None = None,
312
322
  after: str | None = None,
@@ -329,7 +339,7 @@ class ConnectionExtension(FieldExtension):
329
339
  self,
330
340
  next_: AsyncExtensionResolver,
331
341
  source: Any,
332
- info: Info,
342
+ info: strawberry.Info,
333
343
  *,
334
344
  before: str | None = None,
335
345
  after: str | None = None,
strawberry/relay/utils.py CHANGED
@@ -10,7 +10,7 @@ from strawberry.types.base import StrawberryObjectDefinition
10
10
  from strawberry.types.nodes import InlineFragment
11
11
 
12
12
  if TYPE_CHECKING:
13
- from strawberry.types.info import Info
13
+ import strawberry
14
14
 
15
15
 
16
16
  def from_base64(value: str) -> tuple[str, str]:
@@ -71,7 +71,7 @@ def to_base64(type_: str | type | StrawberryObjectDefinition, node_id: Any) -> s
71
71
  return base64.b64encode(f"{type_name}:{node_id}".encode()).decode()
72
72
 
73
73
 
74
- def should_resolve_list_connection_edges(info: Info) -> bool:
74
+ def should_resolve_list_connection_edges(info: strawberry.Info) -> bool:
75
75
  """Check if the user requested to resolve the `edges` field of a connection.
76
76
 
77
77
  Args:
@@ -113,7 +113,7 @@ class SliceMetadata:
113
113
  @classmethod
114
114
  def from_arguments(
115
115
  cls,
116
- info: Info,
116
+ info: strawberry.Info,
117
117
  *,
118
118
  before: str | None = None,
119
119
  after: str | None = None,
@@ -10,6 +10,7 @@ from typing import (
10
10
  TYPE_CHECKING,
11
11
  Annotated,
12
12
  Any,
13
+ ForwardRef,
13
14
  Generic,
14
15
  NamedTuple,
15
16
  TypeVar,
@@ -97,10 +98,14 @@ class ReservedType(NamedTuple):
97
98
 
98
99
  To preserve backwards-comaptibility, if an annotation was defined but does not match
99
100
  :attr:`type`, then the name is used as a fallback if available.
101
+
102
+ :attr:`alias` is the public name exposed in the `strawberry` module, if it differs
103
+ from the internal class name (e.g. "Parent" for StrawberryParent).
100
104
  """
101
105
 
102
106
  name: str | None
103
107
  type: type
108
+ alias: str | None = None
104
109
 
105
110
  def find(
106
111
  self,
@@ -114,16 +119,18 @@ class ReservedType(NamedTuple):
114
119
  annotation = resolver.strawberry_annotations[parameter]
115
120
  if isinstance(annotation, StrawberryAnnotation):
116
121
  try:
117
- evaled_annotation = annotation.evaluate()
122
+ evaled_annotation: Any = annotation.evaluate()
118
123
  except NameError:
119
- # If this is a strawberry.Parent using ForwardRef, we will fail to
120
- # evaluate at this moment, but at least knowing that it is a reserved
121
- # type is enough for now
122
- # We might want to revisit this in the future, maybe by postponing
123
- # this check to when the schema is actually being created
124
- evaled_annotation = resolve_parent_forward_arg(
125
- annotation.annotation
126
- )
124
+ # If we fail to evaluate, check if the raw annotation string
125
+ # matches this reserved type. This handles cases where types
126
+ # are imported under TYPE_CHECKING or use forward references
127
+ # like "strawberry.Info".
128
+ raw = annotation.annotation
129
+ if isinstance(raw, str):
130
+ evaled_annotation = raw
131
+ else:
132
+ # Try resolve_parent_forward_arg for Parent types
133
+ evaled_annotation = resolve_parent_forward_arg(raw)
127
134
 
128
135
  if self.is_reserved_type(evaled_annotation):
129
136
  type_parameters.append(parameter)
@@ -151,24 +158,56 @@ class ReservedType(NamedTuple):
151
158
  return reserved_name
152
159
  return None
153
160
 
154
- def is_reserved_type(self, other: builtins.type) -> bool:
161
+ def is_reserved_type(self, other: builtins.type | str | ForwardRef) -> bool:
162
+ # Handle string forward references (e.g., "strawberry.Info", "Info[Context, None]")
163
+ # This occurs when annotations can't be resolved at runtime, such as when
164
+ # the type is imported under TYPE_CHECKING or uses `from __future__ import annotations`
165
+ if isinstance(other, str):
166
+ return self._is_reserved_type_str(other)
167
+
168
+ if isinstance(other, ForwardRef):
169
+ return self._is_reserved_type_str(other.__forward_arg__)
170
+
171
+ # Handle TypeAliasType (Python 3.12+ `type X = ...` syntax)
172
+ # We need to unwrap the alias to get the actual type
173
+ if hasattr(other, "__value__"):
174
+ other = other.__value__
175
+
155
176
  origin = cast("type", get_origin(other)) or other
156
177
  if origin is Annotated:
157
178
  # Handle annotated arguments such as Private[str] and DirectiveValue[str]
158
179
  return type_has_annotation(other, self.type)
159
- # Handle both concrete and generic types (i.e Info, and Info)
180
+
181
+ # Handle both concrete and generic types (i.e. Info, and Info[X, Y])
160
182
  return (
161
183
  issubclass(origin, self.type)
162
184
  if isinstance(origin, type)
163
185
  else origin is self.type
164
186
  )
165
187
 
188
+ def _is_reserved_type_str(self, annotation: str) -> bool:
189
+ type_name = self.type.__name__
190
+ module = self.type.__module__
191
+
192
+ base_annotation = annotation.split("[")[0].strip()
193
+ # Only match qualified names (strawberry.X or full module path)
194
+ valid_names = {
195
+ f"strawberry.{type_name}", # e.g. "strawberry.Info"
196
+ f"{module}.{type_name}", # e.g. "strawberry.types.info.Info"
197
+ }
198
+
199
+ # Add alias if provided (e.g. "Parent" for StrawberryParent)
200
+ if self.alias:
201
+ valid_names.add(f"strawberry.{self.alias}")
202
+
203
+ return base_annotation in valid_names
204
+
166
205
 
167
206
  SELF_PARAMSPEC = ReservedNameBoundParameter("self")
168
207
  CLS_PARAMSPEC = ReservedNameBoundParameter("cls")
169
208
  ROOT_PARAMSPEC = ReservedName("root")
170
209
  INFO_PARAMSPEC = ReservedType("info", Info)
171
- PARENT_PARAMSPEC = ReservedType(name=None, type=StrawberryParent)
210
+ PARENT_PARAMSPEC = ReservedType(name=None, type=StrawberryParent, alias="Parent")
172
211
 
173
212
  T = TypeVar("T")
174
213
 
strawberry/types/maybe.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import re
2
2
  import typing
3
- from typing import TYPE_CHECKING, Any, Generic, TypeAlias, TypeVar
3
+ from typing import TYPE_CHECKING, Annotated, Any, Generic, TypeAlias, TypeVar
4
4
 
5
5
  T = TypeVar("T")
6
6
 
@@ -47,7 +47,10 @@ def _annotation_is_maybe(annotation: Any) -> bool:
47
47
  # Checking for the pattern should be good enough for now.
48
48
  return _maybe_re.match(annotation) is not None
49
49
 
50
- return (orig := typing.get_origin(annotation)) and orig is Maybe
50
+ orig = typing.get_origin(annotation)
51
+ if orig is Annotated:
52
+ return _annotation_is_maybe(typing.get_args(annotation)[0])
53
+ return orig is Maybe
51
54
 
52
55
 
53
56
  __all__ = [
@@ -109,8 +109,15 @@ def _inject_default_for_maybe_annotations(
109
109
  ) -> None:
110
110
  """Inject `= None` for fields with `Maybe` annotations and no default value."""
111
111
  for name, annotation in annotations.copy().items():
112
- if _annotation_is_maybe(annotation) and not hasattr(cls, name):
113
- setattr(cls, name, None)
112
+ if _annotation_is_maybe(annotation):
113
+ if not hasattr(cls, name):
114
+ setattr(cls, name, None)
115
+ elif (
116
+ isinstance(attr := getattr(cls, name), StrawberryField)
117
+ and attr.default is dataclasses.MISSING
118
+ and attr.default_factory is dataclasses.MISSING
119
+ ):
120
+ attr.default = None
114
121
 
115
122
 
116
123
  def _process_type(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: strawberry-graphql
3
- Version: 0.288.0
3
+ Version: 0.288.2
4
4
  Summary: A library for creating GraphQL APIs
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -132,7 +132,7 @@ strawberry/federation/types.py,sha256=_hZ9VEU72Q81OSX8z5cnvshl0WqpXHgYQMfbqrtaWJ
132
132
  strawberry/federation/union.py,sha256=JXkeDe1rwd6085YN7n-cjDHbo9Wdw6MppECku_f8V5I,1661
133
133
  strawberry/federation/versions.py,sha256=MrGG3GTbUVIRp0WbYjCZAfIwkhFGlDjcYoeYkT3aijA,807
134
134
  strawberry/field_extensions/__init__.py,sha256=0z6RG9jEO7jpAuyEaQhRI5A_30rdcvsBM0qMhLs8y2s,96
135
- strawberry/field_extensions/input_mutation.py,sha256=JAyZ-dAlNOIKQLuMbo9e9Rqo8wyvGBmYXYHHwuM9IcM,2691
135
+ strawberry/field_extensions/input_mutation.py,sha256=FLjv5kqcSga55hoeLuKICyUK28DK2-roUMQWBQNiuS0,2623
136
136
  strawberry/file_uploads/__init__.py,sha256=v2-6FGBqnTnMPSUTFOiXpIutDMl-ga0PFtw5tKlcagk,50
137
137
  strawberry/file_uploads/scalars.py,sha256=dvBFXrumw9nwEszJSTPiadttxTu3USM1hng6mII0_NA,84
138
138
  strawberry/file_uploads/utils.py,sha256=-c6TbqUI-Dkb96hWCrZabh6TL2OabBuQNkCarOqgDm4,1181
@@ -160,9 +160,9 @@ strawberry/quart/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
160
160
  strawberry/quart/views.py,sha256=g0rs3UwFmqxt1DDZpAUF8qHIpT_g-AYwO-t8K-V3AE4,6680
161
161
  strawberry/relay/__init__.py,sha256=Vi4btvA_g6Cj9Tk_F9GCSegapIf2WqkOWV8y3P0cTCs,553
162
162
  strawberry/relay/exceptions.py,sha256=Bk9pPFbb28tDjUiydHa-tFl-e01XukxmJeWoWT9L17M,4017
163
- strawberry/relay/fields.py,sha256=QTU6zw3RlskXR-_FTwRyuvH6Sa9satz4xqnWW8rxpvQ,18249
163
+ strawberry/relay/fields.py,sha256=QOf6miOo-6kyHvpBP1bGT_iey4d38wJ27kXAE0luI5g,18396
164
164
  strawberry/relay/types.py,sha256=-yJ_jpGKPH_CNycWPmXMyn7GjN3MbDcWYvb0dt2VD2Y,30340
165
- strawberry/relay/utils.py,sha256=y0orTN2JabDswl2VnVorBmLvVZ0lUrZmiBR0j2llhFk,5540
165
+ strawberry/relay/utils.py,sha256=ARuQfTNKiIFztaqUYHQs74Wfx-075udJ7NGDeTHUFB8,5541
166
166
  strawberry/resolvers.py,sha256=j2sIi-jI2PrnO3if202l8VBuwQQxblPgRupEaDUu-lA,287
167
167
  strawberry/sanic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
168
168
  strawberry/sanic/context.py,sha256=GSp92ROADlmEF_RMcvESxbY7gNZYRlv7HhUFgB-Tgsk,845
@@ -214,14 +214,14 @@ strawberry/types/enum.py,sha256=Dc1emdlBi1m9pK9h6rdyq8VRaBLafQO7MQdKhVgYXvs,7286
214
214
  strawberry/types/execution.py,sha256=z84AekAD_V_F4vGGHMPMGlAT0Htiw5JhEVvw1F9sGYQ,4019
215
215
  strawberry/types/field.py,sha256=-E5jfq7YXzI2CUepttfGzgmXFA1BTR2hmts44P-JpEk,20422
216
216
  strawberry/types/fields/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
217
- strawberry/types/fields/resolver.py,sha256=8r5CfT9JHCiNyP-RIaNDZIS96-iF8seQPYekG-78vUw,14586
217
+ strawberry/types/fields/resolver.py,sha256=sWG4nO8XpsvELna0uLU-rwKzUGiMgwHPzg8N7xRXqe4,16239
218
218
  strawberry/types/graphql.py,sha256=gXKzawwKiow7hvoJhq5ApNJOMUCnKmvTiHaKY5CK1Lw,867
219
219
  strawberry/types/info.py,sha256=1MTarr040KSsPPdrVx8sDHtKudEfH0LRgQ4adk_1FKA,4698
220
220
  strawberry/types/lazy_type.py,sha256=GYy4PnKtZ48ywW-_A-6Ul8sbHRlB0Tc39ui5DMIja4U,5077
221
- strawberry/types/maybe.py,sha256=hFx-fWvD9XWRK-2tMEzX16pf6Ix-YigzyRmxhmWpwC4,1508
221
+ strawberry/types/maybe.py,sha256=ZBNHGDMuVcorpErPAMjJku4W3I2ygPf_3ZLw-N2O_UU,1610
222
222
  strawberry/types/mutation.py,sha256=vcrKt1VpcS6SLl1WKfcR-NTAqfQ12LpzjwgT5Bx-U3Q,11549
223
223
  strawberry/types/nodes.py,sha256=bM88j05rMIQ5OTS4RqKeU3kjo38MM-hA3Hrmh3IreV0,5121
224
- strawberry/types/object_type.py,sha256=uv7nBxL1JF61i9XeZbU4NujUtAYmCu7cAingNRDkL28,15179
224
+ strawberry/types/object_type.py,sha256=CTBVBM7wD4y76lC_2mTFnpdTqADEA7nFIRrF93UhvII,15457
225
225
  strawberry/types/private.py,sha256=DhJs50XVGtOXlxWZFkRpMxQ5_6oki0-x_WQsV1bGUxk,518
226
226
  strawberry/types/scalar.py,sha256=OgWRFV5x-qTM4-FJC-sAKix-DhMtGRrJTxU7ry4VOlA,8651
227
227
  strawberry/types/type_resolver.py,sha256=fH2ZOK4dAGgu8AMPi-JAXe_kEAbvvw2MCYXqbpx-kTc,6529
@@ -238,8 +238,8 @@ strawberry/utils/logging.py,sha256=Dnivjd0ZhK_lAvjvuyCDkEWDhuURBoK9d3Kt_mIqbRg,7
238
238
  strawberry/utils/operation.py,sha256=Qs3ttbuC415xEVqmJ6YsWQpJNUo8CZJq9AoMB-yV65w,1215
239
239
  strawberry/utils/str_converters.py,sha256=-eH1Cl16IO_wrBlsGM-km4IY0IKsjhjnSNGRGOwQjVM,897
240
240
  strawberry/utils/typing.py,sha256=eE9NeMfASeXRstbjLnQFfOPymcSX8xwg3FGw_HCp95E,11828
241
- strawberry_graphql-0.288.0.dist-info/METADATA,sha256=1xNWgmEuARDM6JHPqtRww_Yue2cQ3twYrR06-cIai8o,7647
242
- strawberry_graphql-0.288.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
243
- strawberry_graphql-0.288.0.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
244
- strawberry_graphql-0.288.0.dist-info/licenses/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
245
- strawberry_graphql-0.288.0.dist-info/RECORD,,
241
+ strawberry_graphql-0.288.2.dist-info/METADATA,sha256=yTioGirWqAPKtjL_NPw6AGSKPTXkUe0dhTUQkNtR-Nk,7647
242
+ strawberry_graphql-0.288.2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
243
+ strawberry_graphql-0.288.2.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
244
+ strawberry_graphql-0.288.2.dist-info/licenses/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
245
+ strawberry_graphql-0.288.2.dist-info/RECORD,,