strawberry-graphql 0.289.8__py3-none-any.whl → 0.291.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.
@@ -1,4 +1,5 @@
1
1
  from collections.abc import Iterable
2
+ from typing import Any
2
3
 
3
4
  from strawberry.types.arguments import StrawberryArgumentAnnotation
4
5
 
@@ -10,6 +11,7 @@ def argument(
10
11
  directives: Iterable[object] = (),
11
12
  inaccessible: bool = False,
12
13
  tags: Iterable[str] | None = (),
14
+ graphql_type: Any | None = None,
13
15
  ) -> StrawberryArgumentAnnotation:
14
16
  from strawberry.federation.schema_directives import Inaccessible, Tag
15
17
 
@@ -26,6 +28,7 @@ def argument(
26
28
  name=name,
27
29
  deprecation_reason=deprecation_reason,
28
30
  directives=directives,
31
+ graphql_type=graphql_type,
29
32
  )
30
33
 
31
34
 
@@ -32,7 +32,11 @@ from graphql import (
32
32
  from graphql.language.ast import (
33
33
  BooleanValueNode,
34
34
  ConstValueNode,
35
+ EnumValueNode,
36
+ FloatValueNode,
37
+ IntValueNode,
35
38
  ListValueNode,
39
+ NullValueNode,
36
40
  )
37
41
 
38
42
  from strawberry.utils.str_converters import to_snake_case
@@ -108,13 +112,23 @@ def _is_federation_link_directive(directive: ConstDirectiveNode) -> bool:
108
112
  ).startswith("https://specs.apollo.dev/federation")
109
113
 
110
114
 
115
+ def _is_nullable(field_type: TypeNode) -> bool:
116
+ """Check if a field type is nullable (not wrapped in NonNullTypeNode)."""
117
+ return not isinstance(field_type, NonNullTypeNode)
118
+
119
+
111
120
  def _get_field_type(
112
- field_type: TypeNode, was_non_nullable: bool = False
121
+ field_type: TypeNode,
122
+ was_non_nullable: bool = False,
123
+ *,
124
+ wrap_in_maybe: bool = False,
113
125
  ) -> cst.BaseExpression:
114
126
  expr: cst.BaseExpression | None
115
127
 
116
128
  if isinstance(field_type, NonNullTypeNode):
117
- return _get_field_type(field_type.type, was_non_nullable=True)
129
+ return _get_field_type(
130
+ field_type.type, was_non_nullable=True, wrap_in_maybe=wrap_in_maybe
131
+ )
118
132
  if isinstance(field_type, ListTypeNode):
119
133
  expr = cst.Subscript(
120
134
  value=cst.Name("list"),
@@ -138,12 +152,84 @@ def _get_field_type(
138
152
  if was_non_nullable:
139
153
  return expr
140
154
 
141
- return cst.BinaryOperation(
155
+ nullable_expr = cst.BinaryOperation(
142
156
  left=expr,
143
157
  operator=cst.BitOr(),
144
158
  right=cst.Name("None"),
145
159
  )
146
160
 
161
+ if wrap_in_maybe:
162
+ return cst.Subscript(
163
+ value=cst.Attribute(
164
+ value=cst.Name("strawberry"),
165
+ attr=cst.Name("Maybe"),
166
+ ),
167
+ slice=[
168
+ cst.SubscriptElement(
169
+ cst.Index(value=nullable_expr),
170
+ )
171
+ ],
172
+ )
173
+
174
+ return nullable_expr
175
+
176
+
177
+ def _get_base_type_name(type_node: TypeNode) -> str:
178
+ """Extract the base named type from a possibly wrapped type node."""
179
+ if isinstance(type_node, (NonNullTypeNode, ListTypeNode)):
180
+ return _get_base_type_name(type_node.type)
181
+
182
+ if isinstance(type_node, NamedTypeNode):
183
+ return type_node.name.value
184
+
185
+ raise NotImplementedError(f"Unknown type node {type_node}")
186
+
187
+
188
+ def _get_default_value_expr(
189
+ node: ConstValueNode,
190
+ *,
191
+ enum_type_name: str | None = None,
192
+ ) -> cst.BaseExpression:
193
+ """Convert a GraphQL default value AST node to a libcst expression."""
194
+ if isinstance(node, IntValueNode):
195
+ return cst.Integer(node.value)
196
+
197
+ if isinstance(node, FloatValueNode):
198
+ return cst.Float(node.value)
199
+
200
+ if isinstance(node, StringValueNode):
201
+ if '"' in node.value:
202
+ return cst.SimpleString(f"'{node.value}'")
203
+
204
+ return cst.SimpleString(f'"{node.value}"')
205
+
206
+ if isinstance(node, BooleanValueNode):
207
+ return cst.Name("True" if node.value else "False")
208
+
209
+ if isinstance(node, NullValueNode):
210
+ return cst.Name("None")
211
+
212
+ if isinstance(node, EnumValueNode):
213
+ if enum_type_name is None:
214
+ raise ValueError("enum_type_name is required for EnumValueNode")
215
+
216
+ return cst.Attribute(
217
+ value=cst.Name(enum_type_name),
218
+ attr=cst.Name(node.value),
219
+ )
220
+
221
+ if isinstance(node, ListValueNode):
222
+ return cst.List(
223
+ elements=[
224
+ cst.Element(
225
+ value=_get_default_value_expr(v, enum_type_name=enum_type_name)
226
+ )
227
+ for v in node.values
228
+ ]
229
+ )
230
+
231
+ raise NotImplementedError(f"Unknown default value node {node}")
232
+
147
233
 
148
234
  def _sanitize_argument(value: ArgumentValue) -> cst.SimpleString | cst.Name | cst.List:
149
235
  if isinstance(value, bool):
@@ -183,7 +269,9 @@ def _get_field_value(
183
269
  alias: str | None,
184
270
  is_apollo_federation: bool,
185
271
  imports: set[Import],
186
- ) -> cst.Call | None:
272
+ *,
273
+ default_value: cst.BaseExpression | None = None,
274
+ ) -> cst.Call | cst.BaseExpression | None:
187
275
  description = field.description.value if field.description else None
188
276
 
189
277
  args = list(
@@ -200,7 +288,19 @@ def _get_field_value(
200
288
 
201
289
  apollo_federation_args = _get_federation_arguments(directives, imports)
202
290
 
291
+ default_arg = (
292
+ cst.Arg(
293
+ value=default_value,
294
+ keyword=cst.Name("default"),
295
+ equal=cst.AssignEqual(cst.SimpleWhitespace(""), cst.SimpleWhitespace("")),
296
+ )
297
+ if default_value is not None
298
+ else None
299
+ )
300
+
203
301
  if is_apollo_federation and apollo_federation_args:
302
+ if default_arg is not None:
303
+ args.append(default_arg)
204
304
  args.extend(apollo_federation_args)
205
305
 
206
306
  return cst.Call(
@@ -215,6 +315,8 @@ def _get_field_value(
215
315
  )
216
316
 
217
317
  if args:
318
+ if default_arg is not None:
319
+ args.append(default_arg)
218
320
  return cst.Call(
219
321
  func=cst.Attribute(
220
322
  value=cst.Name("strawberry"),
@@ -223,6 +325,9 @@ def _get_field_value(
223
325
  args=args,
224
326
  )
225
327
 
328
+ if default_value is not None:
329
+ return default_value
330
+
226
331
  return None
227
332
 
228
333
 
@@ -230,6 +335,8 @@ def _get_field(
230
335
  field: FieldDefinitionNode | InputValueDefinitionNode,
231
336
  is_apollo_federation: bool,
232
337
  imports: set[Import],
338
+ *,
339
+ is_input_field: bool = False,
233
340
  ) -> cst.SimpleStatementLine:
234
341
  name = to_snake_case(field.name.value)
235
342
  alias: str | None = None
@@ -238,18 +345,35 @@ def _get_field(
238
345
  name = f"{name}_"
239
346
  alias = field.name.value
240
347
 
348
+ # For input types, wrap nullable fields in strawberry.Maybe[...]
349
+ wrap_in_maybe = is_input_field and _is_nullable(field.type)
350
+
351
+ # Extract default value for input fields
352
+ default_value: cst.BaseExpression | None = None
353
+ if isinstance(field, InputValueDefinitionNode) and field.default_value is not None:
354
+ enum_type_name = (
355
+ _get_base_type_name(field.type)
356
+ if isinstance(field.default_value, EnumValueNode)
357
+ else None
358
+ )
359
+
360
+ default_value = _get_default_value_expr(
361
+ field.default_value, enum_type_name=enum_type_name
362
+ )
363
+
241
364
  return cst.SimpleStatementLine(
242
365
  body=[
243
366
  cst.AnnAssign(
244
367
  target=cst.Name(name),
245
368
  annotation=cst.Annotation(
246
- _get_field_type(field.type),
369
+ _get_field_type(field.type, wrap_in_maybe=wrap_in_maybe),
247
370
  ),
248
371
  value=_get_field_value(
249
372
  field,
250
373
  alias=alias,
251
374
  is_apollo_federation=is_apollo_federation,
252
375
  imports=imports,
376
+ default_value=default_value,
253
377
  ),
254
378
  )
255
379
  ]
@@ -262,12 +386,16 @@ ArgumentValue: TypeAlias = str | bool | list["ArgumentValue"]
262
386
  def _get_argument_value(argument_value: ConstValueNode) -> ArgumentValue:
263
387
  if isinstance(argument_value, StringValueNode):
264
388
  return argument_value.value
389
+
265
390
  if isinstance(argument_value, EnumValueDefinitionNode):
266
391
  return argument_value.name.value
392
+
267
393
  if isinstance(argument_value, ListValueNode):
268
394
  return [_get_argument_value(arg) for arg in argument_value.values]
395
+
269
396
  if isinstance(argument_value, BooleanValueNode):
270
397
  return argument_value.value
398
+
271
399
  raise NotImplementedError(f"Unknown argument value {argument_value}")
272
400
 
273
401
 
@@ -440,11 +568,18 @@ def _get_class_definition(
440
568
  else []
441
569
  )
442
570
 
571
+ is_input_type = isinstance(definition, InputObjectTypeDefinitionNode)
572
+
443
573
  class_definition = cst.ClassDef(
444
574
  name=cst.Name(definition.name.value),
445
575
  body=cst.IndentedBlock(
446
576
  body=[
447
- _get_field(field, is_apollo_federation, imports)
577
+ _get_field(
578
+ field,
579
+ is_apollo_federation,
580
+ imports,
581
+ is_input_field=is_input_type,
582
+ )
448
583
  for field in definition.fields
449
584
  ]
450
585
  ),
@@ -51,6 +51,7 @@ class StrawberryArgumentAnnotation:
51
51
  deprecation_reason: str | None
52
52
  directives: Iterable[object]
53
53
  metadata: Mapping[Any, Any]
54
+ graphql_type: Any | None
54
55
 
55
56
  def __init__(
56
57
  self,
@@ -59,12 +60,14 @@ class StrawberryArgumentAnnotation:
59
60
  deprecation_reason: str | None = None,
60
61
  directives: Iterable[object] = (),
61
62
  metadata: Mapping[Any, Any] | None = None,
63
+ graphql_type: Any | None = None,
62
64
  ) -> None:
63
65
  self.description = description
64
66
  self.name = name
65
67
  self.deprecation_reason = deprecation_reason
66
68
  self.directives = directives
67
69
  self.metadata = metadata or {}
70
+ self.graphql_type = graphql_type
68
71
 
69
72
 
70
73
  class StrawberryArgument:
@@ -122,6 +125,10 @@ class StrawberryArgument:
122
125
  self.deprecation_reason = arg.deprecation_reason
123
126
  self.directives = arg.directives
124
127
  self.metadata = arg.metadata
128
+ if arg.graphql_type is not None:
129
+ self.type_annotation = StrawberryAnnotation(
130
+ arg.graphql_type
131
+ )
125
132
 
126
133
  if isinstance(arg, StrawberryLazyReference):
127
134
  self.type_annotation = StrawberryAnnotation(
@@ -313,6 +320,7 @@ def argument(
313
320
  deprecation_reason: str | None = None,
314
321
  directives: Iterable[object] = (),
315
322
  metadata: Mapping[Any, Any] | None = None,
323
+ graphql_type: Any | None = None,
316
324
  ) -> StrawberryArgumentAnnotation:
317
325
  """Function to add metadata to an argument, like a description or deprecation reason.
318
326
 
@@ -324,6 +332,8 @@ def argument(
324
332
  directives: The directives to attach to the argument
325
333
  metadata: Metadata to attach to the argument, this can be used
326
334
  to store custom data that can be used by custom logic or plugins
335
+ graphql_type: The GraphQL type for the argument, useful when you want to use a
336
+ different type than the one in the schema.
327
337
 
328
338
  Returns:
329
339
  A StrawberryArgumentAnnotation object that can be used to customise an argument
@@ -348,6 +358,7 @@ def argument(
348
358
  deprecation_reason=deprecation_reason,
349
359
  directives=directives,
350
360
  metadata=metadata,
361
+ graphql_type=graphql_type,
351
362
  )
352
363
 
353
364
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: strawberry-graphql
3
- Version: 0.289.8
3
+ Version: 0.291.0
4
4
  Summary: A library for creating GraphQL APIs
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -121,7 +121,7 @@ strawberry/fastapi/__init__.py,sha256=p5qg9AlkYjNOWKcT4uRiebIpR6pIb1HqDMiDfF5O3t
121
121
  strawberry/fastapi/context.py,sha256=HXOpOwOpPMYbNgf7sQYvfNrqL7SQMNvtVvd6fiC2jKM,653
122
122
  strawberry/fastapi/router.py,sha256=sXovpiJUQapHdzBnQ71I4hqRGixSs7mYeLunkJYTeoU,11866
123
123
  strawberry/federation/__init__.py,sha256=Pw01N0rG9o0NaUxXLMNGeW5oLENeWVx_d8Kuef1ES4s,549
124
- strawberry/federation/argument.py,sha256=fFIoUZwEA8f4edmhzzIF_ytckiSrVkORU9vsQSMCSSo,820
124
+ strawberry/federation/argument.py,sha256=nvhaZCHlpZrKa7vtWMOc1zJybJxxqRK-a3k6CIJRnhE,915
125
125
  strawberry/federation/enum.py,sha256=RTGlUtwrDw0Iu_5yq3y_EmGlY6IqHRhepy9OPSHRbD4,3068
126
126
  strawberry/federation/field.py,sha256=xLnbTUoI1-a361Jte_mjp6LD_uD_sJWvZl3l6FBWNWo,8597
127
127
  strawberry/federation/mutation.py,sha256=5t2E419m4K2W6LoWEOzWgMdL2J0PwHnsffYkpChqqDQ,67
@@ -187,7 +187,7 @@ strawberry/schema/types/scalar.py,sha256=1MKFyE7_S0Mb5TafYLhRituidGrPGrmVgR548WR
187
187
  strawberry/schema/validation_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
188
188
  strawberry/schema/validation_rules/maybe_null.py,sha256=RrIq1yV5_2YxIYN7jx8AaY6O_pqxKtylbM1IygFz5z4,5624
189
189
  strawberry/schema/validation_rules/one_of.py,sha256=fPuYzCyLT7p9y7dHF_sWTImArTQaEhyF664lZijB1Gw,2629
190
- strawberry/schema_codegen/__init__.py,sha256=HzgwI-rudoloXqJa5R9zyxXNTKLhdSXgSn7wfjvVDwI,24161
190
+ strawberry/schema_codegen/__init__.py,sha256=HMJUPi-lPYoxAaQlfcCrqmtM_ynZtEqDbVHCO8aNWPM,28119
191
191
  strawberry/schema_directive.py,sha256=H5tv1npCkEa-mUkzQ9nilNI3zTGEAhyagRcDwj5Rujw,2025
192
192
  strawberry/schema_directives.py,sha256=KGKFWCODjm1Ah9qNV_bBwbic7Mld4qLWnWQkev-PG8A,175
193
193
  strawberry/static/apollo-sandbox.html,sha256=2XzkbE0dqsFHqehE-jul9_J9TFOpwA6Ylrlo0Kdx_9w,973
@@ -208,7 +208,7 @@ strawberry/tools/__init__.py,sha256=pdGpZx8wpq03VfUZJyF9JtYxZhGqzzxCiipsalWxJX4,
208
208
  strawberry/tools/create_type.py,sha256=lYnqXMaecEWc0CtC2lGhX2mE--6S22q_V8GiIkHlGqw,2295
209
209
  strawberry/tools/merge_types.py,sha256=hUMRRNM28FyPp70jRA3d4svv9WoEBjaNpihBt3DaY0I,1023
210
210
  strawberry/types/__init__.py,sha256=baWEdDkkmCcITOhkg2hNUOenrNV1OYdxGE5qgvIRwwU,351
211
- strawberry/types/arguments.py,sha256=3Rt1WlVDMc0KKYmJOnMUckeTB0egJv96Uw7RMopM4DM,11996
211
+ strawberry/types/arguments.py,sha256=K3Pk1YO7LNJV7E8waVB_BSG-ACDsfTed_Txku1hyccQ,12530
212
212
  strawberry/types/auto.py,sha256=4sDflIg-Kz-QpK7Qo7bCSFblw7VE-0752rgayukFznU,2954
213
213
  strawberry/types/base.py,sha256=Hubo7u6OsU1v1v-w-vBCwlNVTqHaNn4zPOJuX93WR5U,15699
214
214
  strawberry/types/cast.py,sha256=fx86MkLW77GIximBAwUk5vZxSGwDqUA6XicXvz8EXwQ,916
@@ -240,8 +240,8 @@ strawberry/utils/logging.py,sha256=Dnivjd0ZhK_lAvjvuyCDkEWDhuURBoK9d3Kt_mIqbRg,7
240
240
  strawberry/utils/operation.py,sha256=Qs3ttbuC415xEVqmJ6YsWQpJNUo8CZJq9AoMB-yV65w,1215
241
241
  strawberry/utils/str_converters.py,sha256=-eH1Cl16IO_wrBlsGM-km4IY0IKsjhjnSNGRGOwQjVM,897
242
242
  strawberry/utils/typing.py,sha256=eE9NeMfASeXRstbjLnQFfOPymcSX8xwg3FGw_HCp95E,11828
243
- strawberry_graphql-0.289.8.dist-info/METADATA,sha256=ChUTmdnOxdsdIjJtD6zO1zmdM0tcKhtQ8qh59X1WGNA,7394
244
- strawberry_graphql-0.289.8.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
245
- strawberry_graphql-0.289.8.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
246
- strawberry_graphql-0.289.8.dist-info/licenses/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
247
- strawberry_graphql-0.289.8.dist-info/RECORD,,
243
+ strawberry_graphql-0.291.0.dist-info/METADATA,sha256=ZOmFcNGucuN7oKDbKb1EcO_tdFlgyb49xnMD2XEqQOk,7394
244
+ strawberry_graphql-0.291.0.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
245
+ strawberry_graphql-0.291.0.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
246
+ strawberry_graphql-0.291.0.dist-info/licenses/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
247
+ strawberry_graphql-0.291.0.dist-info/RECORD,,