strawberry-graphql 0.227.0.dev1713475585__py3-none-any.whl → 0.227.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.
Files changed (47) hide show
  1. strawberry/channels/handlers/base.py +7 -14
  2. strawberry/codegen/query_codegen.py +2 -4
  3. strawberry/custom_scalar.py +2 -4
  4. strawberry/dataloader.py +2 -4
  5. strawberry/directive.py +1 -2
  6. strawberry/django/views.py +1 -1
  7. strawberry/enum.py +2 -4
  8. strawberry/experimental/pydantic/conversion_types.py +5 -10
  9. strawberry/experimental/pydantic/error_type.py +1 -1
  10. strawberry/experimental/pydantic/object_type.py +1 -1
  11. strawberry/ext/mypy_plugin.py +24 -1
  12. strawberry/federation/enum.py +2 -4
  13. strawberry/federation/field.py +3 -6
  14. strawberry/federation/object_type.py +8 -25
  15. strawberry/federation/scalar.py +2 -4
  16. strawberry/federation/schema_directive.py +1 -1
  17. strawberry/field.py +3 -6
  18. strawberry/http/async_base_view.py +12 -24
  19. strawberry/http/base.py +3 -6
  20. strawberry/http/sync_base_view.py +13 -26
  21. strawberry/litestar/controller.py +2 -2
  22. strawberry/object_type.py +32 -23
  23. strawberry/parent.py +1 -2
  24. strawberry/printer/printer.py +3 -6
  25. strawberry/private.py +1 -2
  26. strawberry/relay/fields.py +2 -4
  27. strawberry/relay/types.py +12 -24
  28. strawberry/relay/utils.py +1 -1
  29. strawberry/schema/execute.py +0 -5
  30. strawberry/schema/schema.py +0 -11
  31. strawberry/schema/schema_converter.py +1 -35
  32. strawberry/schema_codegen/__init__.py +96 -87
  33. strawberry/schema_directive.py +1 -1
  34. strawberry/starlite/controller.py +2 -2
  35. strawberry/type.py +4 -12
  36. strawberry/types/type_resolver.py +9 -2
  37. strawberry/types/types.py +1 -13
  38. strawberry/utils/aio.py +1 -1
  39. strawberry/utils/typing.py +2 -4
  40. {strawberry_graphql-0.227.0.dev1713475585.dist-info → strawberry_graphql-0.227.2.dist-info}/METADATA +2 -1
  41. {strawberry_graphql-0.227.0.dev1713475585.dist-info → strawberry_graphql-0.227.2.dist-info}/RECORD +44 -47
  42. strawberry/schema/validation_rules/__init__.py +0 -0
  43. strawberry/schema/validation_rules/one_of.py +0 -80
  44. strawberry/schema_directives.py +0 -9
  45. {strawberry_graphql-0.227.0.dev1713475585.dist-info → strawberry_graphql-0.227.2.dist-info}/LICENSE +0 -0
  46. {strawberry_graphql-0.227.0.dev1713475585.dist-info → strawberry_graphql-0.227.2.dist-info}/WHEEL +0 -0
  47. {strawberry_graphql-0.227.0.dev1713475585.dist-info → strawberry_graphql-0.227.2.dist-info}/entry_points.txt +0 -0
strawberry/object_type.py CHANGED
@@ -67,7 +67,8 @@ def _check_field_annotations(cls: Type[Any]):
67
67
  # If the field has a type override then use that instead of using
68
68
  # the class annotations or resolver annotation
69
69
  if field_.type_annotation is not None:
70
- cls_annotations[field_name] = field_.type_annotation.annotation
70
+ if field_name not in cls_annotations:
71
+ cls_annotations[field_name] = field_.type_annotation.annotation
71
72
  continue
72
73
 
73
74
  # Make sure the cls has an annotation
@@ -85,7 +86,8 @@ def _check_field_annotations(cls: Type[Any]):
85
86
  field_name, resolver=field_.base_resolver
86
87
  )
87
88
 
88
- cls_annotations[field_name] = field_.base_resolver.type_annotation
89
+ if field_name not in cls_annotations:
90
+ cls_annotations[field_name] = field_.base_resolver.type_annotation
89
91
 
90
92
  # TODO: Make sure the cls annotation agrees with the field's type
91
93
  # >>> if cls_annotations[field_name] != field.base_resolver.type:
@@ -133,11 +135,13 @@ def _process_type(
133
135
  description: Optional[str] = None,
134
136
  directives: Optional[Sequence[object]] = (),
135
137
  extend: bool = False,
138
+ original_type_annotations: Optional[Dict[str, Any]] = None,
136
139
  ) -> T:
137
140
  name = name or to_camel_case(cls.__name__)
141
+ original_type_annotations = original_type_annotations or {}
138
142
 
139
143
  interfaces = _get_interfaces(cls)
140
- fields = _get_fields(cls)
144
+ fields = _get_fields(cls, original_type_annotations)
141
145
  is_type_of = getattr(cls, "is_type_of", None)
142
146
  resolve_type = getattr(cls, "resolve_type", None)
143
147
 
@@ -198,8 +202,7 @@ def type(
198
202
  description: Optional[str] = None,
199
203
  directives: Optional[Sequence[object]] = (),
200
204
  extend: bool = False,
201
- ) -> T:
202
- ...
205
+ ) -> T: ...
203
206
 
204
207
 
205
208
  @overload
@@ -214,8 +217,7 @@ def type(
214
217
  description: Optional[str] = None,
215
218
  directives: Optional[Sequence[object]] = (),
216
219
  extend: bool = False,
217
- ) -> Callable[[T], T]:
218
- ...
220
+ ) -> Callable[[T], T]: ...
219
221
 
220
222
 
221
223
  def type(
@@ -247,7 +249,25 @@ def type(
247
249
  exc = ObjectIsNotClassError.type
248
250
  raise exc(cls)
249
251
 
252
+ # when running `_wrap_dataclass` we lose some of the information about the
253
+ # the passed types, especially the type_annotation inside the StrawberryField
254
+ # this makes it impossible to customise the field type, like this:
255
+ # >>> @strawberry.type
256
+ # >>> class Query:
257
+ # >>> a: int = strawberry.field(graphql_type=str)
258
+ # so we need to extract the information before running `_wrap_dataclass`
259
+ original_type_annotations: Dict[str, Any] = {}
260
+
261
+ annotations = getattr(cls, "__annotations__", {})
262
+
263
+ for field_name in annotations:
264
+ field = getattr(cls, field_name, None)
265
+
266
+ if field and isinstance(field, StrawberryField) and field.type_annotation:
267
+ original_type_annotations[field_name] = field.type_annotation.annotation
268
+
250
269
  wrapped = _wrap_dataclass(cls)
270
+
251
271
  return _process_type(
252
272
  wrapped,
253
273
  name=name,
@@ -256,6 +276,7 @@ def type(
256
276
  description=description,
257
277
  directives=directives,
258
278
  extend=extend,
279
+ original_type_annotations=original_type_annotations,
259
280
  )
260
281
 
261
282
  if cls is None:
@@ -272,11 +293,9 @@ def input(
272
293
  cls: T,
273
294
  *,
274
295
  name: Optional[str] = None,
275
- one_of: Optional[bool] = None,
276
296
  description: Optional[str] = None,
277
297
  directives: Optional[Sequence[object]] = (),
278
- ) -> T:
279
- ...
298
+ ) -> T: ...
280
299
 
281
300
 
282
301
  @overload
@@ -286,18 +305,15 @@ def input(
286
305
  def input(
287
306
  *,
288
307
  name: Optional[str] = None,
289
- one_of: Optional[bool] = None,
290
308
  description: Optional[str] = None,
291
309
  directives: Optional[Sequence[object]] = (),
292
- ) -> Callable[[T], T]:
293
- ...
310
+ ) -> Callable[[T], T]: ...
294
311
 
295
312
 
296
313
  def input(
297
314
  cls: Optional[T] = None,
298
315
  *,
299
316
  name: Optional[str] = None,
300
- one_of: Optional[bool] = None,
301
317
  description: Optional[str] = None,
302
318
  directives: Optional[Sequence[object]] = (),
303
319
  ):
@@ -308,11 +324,6 @@ def input(
308
324
  >>> field_abc: str = "ABC"
309
325
  """
310
326
 
311
- from strawberry.schema_directives import OneOf
312
-
313
- if one_of:
314
- directives = (*(directives or ()), OneOf())
315
-
316
327
  return type( # type: ignore # not sure why mypy complains here
317
328
  cls,
318
329
  name=name,
@@ -332,8 +343,7 @@ def interface(
332
343
  name: Optional[str] = None,
333
344
  description: Optional[str] = None,
334
345
  directives: Optional[Sequence[object]] = (),
335
- ) -> T:
336
- ...
346
+ ) -> T: ...
337
347
 
338
348
 
339
349
  @overload
@@ -345,8 +355,7 @@ def interface(
345
355
  name: Optional[str] = None,
346
356
  description: Optional[str] = None,
347
357
  directives: Optional[Sequence[object]] = (),
348
- ) -> Callable[[T], T]:
349
- ...
358
+ ) -> Callable[[T], T]: ...
350
359
 
351
360
 
352
361
  @dataclass_transform(
strawberry/parent.py CHANGED
@@ -2,8 +2,7 @@ from typing import TypeVar
2
2
  from typing_extensions import Annotated
3
3
 
4
4
 
5
- class StrawberryParent:
6
- ...
5
+ class StrawberryParent: ...
7
6
 
8
7
 
9
8
  T = TypeVar("T")
@@ -69,20 +69,17 @@ class PrintExtras:
69
69
 
70
70
 
71
71
  @overload
72
- def _serialize_dataclasses(value: Dict[_T, object]) -> Dict[_T, object]:
73
- ...
72
+ def _serialize_dataclasses(value: Dict[_T, object]) -> Dict[_T, object]: ...
74
73
 
75
74
 
76
75
  @overload
77
76
  def _serialize_dataclasses(
78
77
  value: Union[List[object], Tuple[object]],
79
- ) -> List[object]:
80
- ...
78
+ ) -> List[object]: ...
81
79
 
82
80
 
83
81
  @overload
84
- def _serialize_dataclasses(value: object) -> object:
85
- ...
82
+ def _serialize_dataclasses(value: object) -> object: ...
86
83
 
87
84
 
88
85
  def _serialize_dataclasses(value):
strawberry/private.py CHANGED
@@ -4,8 +4,7 @@ from typing_extensions import Annotated
4
4
  from strawberry.utils.typing import type_has_annotation
5
5
 
6
6
 
7
- class StrawberryPrivate:
8
- ...
7
+ class StrawberryPrivate: ...
9
8
 
10
9
 
11
10
  T = TypeVar("T")
@@ -331,8 +331,7 @@ def connection(
331
331
  metadata: Optional[Mapping[Any, Any]] = None,
332
332
  directives: Optional[Sequence[object]] = (),
333
333
  extensions: List[FieldExtension] = (), # type: ignore
334
- ) -> Any:
335
- ...
334
+ ) -> Any: ...
336
335
 
337
336
 
338
337
  @overload
@@ -349,8 +348,7 @@ def connection(
349
348
  metadata: Optional[Mapping[Any, Any]] = None,
350
349
  directives: Optional[Sequence[object]] = (),
351
350
  extensions: List[FieldExtension] = (), # type: ignore
352
- ) -> StrawberryField:
353
- ...
351
+ ) -> StrawberryField: ...
354
352
 
355
353
 
356
354
  def connection(
strawberry/relay/types.py CHANGED
@@ -130,8 +130,7 @@ class GlobalID:
130
130
  *,
131
131
  required: Literal[True] = ...,
132
132
  ensure_type: Type[_T],
133
- ) -> _T:
134
- ...
133
+ ) -> _T: ...
135
134
 
136
135
  @overload
137
136
  async def resolve_node(
@@ -140,8 +139,7 @@ class GlobalID:
140
139
  *,
141
140
  required: Literal[True],
142
141
  ensure_type: None = ...,
143
- ) -> Node:
144
- ...
142
+ ) -> Node: ...
145
143
 
146
144
  @overload
147
145
  async def resolve_node(
@@ -150,8 +148,7 @@ class GlobalID:
150
148
  *,
151
149
  required: bool = ...,
152
150
  ensure_type: None = ...,
153
- ) -> Optional[Node]:
154
- ...
151
+ ) -> Optional[Node]: ...
155
152
 
156
153
  async def resolve_node(self, info, *, required=False, ensure_type=None) -> Any:
157
154
  """Resolve the type name and node id info to the node itself.
@@ -235,8 +232,7 @@ class GlobalID:
235
232
  *,
236
233
  required: Literal[True] = ...,
237
234
  ensure_type: Type[_T],
238
- ) -> _T:
239
- ...
235
+ ) -> _T: ...
240
236
 
241
237
  @overload
242
238
  def resolve_node_sync(
@@ -245,8 +241,7 @@ class GlobalID:
245
241
  *,
246
242
  required: Literal[True],
247
243
  ensure_type: None = ...,
248
- ) -> Node:
249
- ...
244
+ ) -> Node: ...
250
245
 
251
246
  @overload
252
247
  def resolve_node_sync(
@@ -255,8 +250,7 @@ class GlobalID:
255
250
  *,
256
251
  required: bool = ...,
257
252
  ensure_type: None = ...,
258
- ) -> Optional[Node]:
259
- ...
253
+ ) -> Optional[Node]: ...
260
254
 
261
255
  def resolve_node_sync(self, info, *, required=False, ensure_type=None) -> Any:
262
256
  """Resolve the type name and node id info to the node itself.
@@ -485,8 +479,7 @@ class Node:
485
479
  info: Info,
486
480
  node_ids: Iterable[str],
487
481
  required: Literal[True],
488
- ) -> AwaitableOrValue[Iterable[Self]]:
489
- ...
482
+ ) -> AwaitableOrValue[Iterable[Self]]: ...
490
483
 
491
484
  @overload
492
485
  @classmethod
@@ -496,8 +489,7 @@ class Node:
496
489
  info: Info,
497
490
  node_ids: Iterable[str],
498
491
  required: Literal[False] = ...,
499
- ) -> AwaitableOrValue[Iterable[Optional[Self]]]:
500
- ...
492
+ ) -> AwaitableOrValue[Iterable[Optional[Self]]]: ...
501
493
 
502
494
  @overload
503
495
  @classmethod
@@ -510,8 +502,7 @@ class Node:
510
502
  ) -> Union[
511
503
  AwaitableOrValue[Iterable[Self]],
512
504
  AwaitableOrValue[Iterable[Optional[Self]]],
513
- ]:
514
- ...
505
+ ]: ...
515
506
 
516
507
  @classmethod
517
508
  def resolve_nodes(
@@ -555,8 +546,7 @@ class Node:
555
546
  *,
556
547
  info: Info,
557
548
  required: Literal[True],
558
- ) -> AwaitableOrValue[Self]:
559
- ...
549
+ ) -> AwaitableOrValue[Self]: ...
560
550
 
561
551
  @overload
562
552
  @classmethod
@@ -566,8 +556,7 @@ class Node:
566
556
  *,
567
557
  info: Info,
568
558
  required: Literal[False] = ...,
569
- ) -> AwaitableOrValue[Optional[Self]]:
570
- ...
559
+ ) -> AwaitableOrValue[Optional[Self]]: ...
571
560
 
572
561
  @overload
573
562
  @classmethod
@@ -577,8 +566,7 @@ class Node:
577
566
  *,
578
567
  info: Info,
579
568
  required: bool,
580
- ) -> AwaitableOrValue[Optional[Self]]:
581
- ...
569
+ ) -> AwaitableOrValue[Optional[Self]]: ...
582
570
 
583
571
  @classmethod
584
572
  def resolve_node(
strawberry/relay/utils.py CHANGED
@@ -41,7 +41,7 @@ def to_base64(type_: Union[str, type, StrawberryObjectDefinition], node_id: Any)
41
41
  The node id itself
42
42
 
43
43
  Returns:
44
- A tuple of (TypeName, NodeID).
44
+ A GlobalID, which is a string resulting from base64 encoding <TypeName>:<NodeID>.
45
45
 
46
46
  Raises:
47
47
  ValueError:
@@ -23,7 +23,6 @@ from graphql.validation import validate
23
23
 
24
24
  from strawberry.exceptions import MissingQueryError
25
25
  from strawberry.extensions.runner import SchemaExtensionsRunner
26
- from strawberry.schema.validation_rules.one_of import OneOfInputValidationRule
27
26
  from strawberry.types import ExecutionResult
28
27
 
29
28
  from .exceptions import InvalidOperationTypeError
@@ -56,10 +55,6 @@ def validate_document(
56
55
  document: DocumentNode,
57
56
  validation_rules: Tuple[Type[ASTValidationRule], ...],
58
57
  ) -> List[GraphQLError]:
59
- validation_rules = (
60
- *validation_rules,
61
- OneOfInputValidationRule,
62
- )
63
58
  return validate(
64
59
  schema,
65
60
  document,
@@ -16,8 +16,6 @@ from typing import (
16
16
  )
17
17
 
18
18
  from graphql import (
19
- GraphQLBoolean,
20
- GraphQLField,
21
19
  GraphQLNamedType,
22
20
  GraphQLNonNull,
23
21
  GraphQLSchema,
@@ -170,7 +168,6 @@ class Schema(BaseSchema):
170
168
 
171
169
  self._warn_for_federation_directives()
172
170
  self._resolve_node_ids()
173
- self._extend_introspection()
174
171
 
175
172
  # Validate schema early because we want developers to know about
176
173
  # possible issues as soon as possible
@@ -378,14 +375,6 @@ class Schema(BaseSchema):
378
375
  stacklevel=3,
379
376
  )
380
377
 
381
- def _extend_introspection(self):
382
- def _resolve_is_one_of(obj: Any, info: Any) -> bool:
383
- return obj.extensions["strawberry-definition"].is_one_of
384
-
385
- instrospection_type = self._schema.type_map["__Type"]
386
- instrospection_type.fields["isOneOf"] = GraphQLField(GraphQLBoolean) # type: ignore[attr-defined]
387
- instrospection_type.fields["isOneOf"].resolve = _resolve_is_one_of # type: ignore[attr-defined]
388
-
389
378
  def as_str(self) -> str:
390
379
  return print_schema(self)
391
380
 
@@ -26,7 +26,6 @@ from graphql import (
26
26
  GraphQLDirective,
27
27
  GraphQLEnumType,
28
28
  GraphQLEnumValue,
29
- GraphQLError,
30
29
  GraphQLField,
31
30
  GraphQLInputField,
32
31
  GraphQLInputObjectType,
@@ -102,8 +101,7 @@ class FieldConverterProtocol(Generic[FieldType], Protocol):
102
101
  field: StrawberryField,
103
102
  *,
104
103
  type_definition: Optional[StrawberryObjectDefinition] = None,
105
- ) -> FieldType:
106
- ...
104
+ ) -> FieldType: ...
107
105
 
108
106
 
109
107
  def _get_thunk_mapping(
@@ -411,37 +409,6 @@ class GraphQLCoreConverter:
411
409
  assert isinstance(graphql_object_type, GraphQLInputObjectType) # For mypy
412
410
  return graphql_object_type
413
411
 
414
- def check_one_of(value: dict[str, Any]) -> dict[str, Any]:
415
- if len(value) != 1:
416
- raise GraphQLError(
417
- f"OneOf Input Object '{type_name}' must specify exactly one key."
418
- )
419
-
420
- first_key, first_value = next(iter(value.items()))
421
-
422
- if first_value is None or first_value is UNSET:
423
- raise GraphQLError(
424
- f"Value for member field '{first_key}' must be non-null"
425
- )
426
-
427
- # We are populating all missing keys with `None`, so users
428
- # don't have to set an explicit default for the input type
429
- # The alternative is to tell them to use `UNSET`, but it looks
430
- # a bit unfriendly to use
431
-
432
- for field in type_definition.fields:
433
- name = self.config.name_converter.from_field(field)
434
- if name not in value:
435
- value[name] = None
436
-
437
- return value
438
-
439
- out_type = (
440
- check_one_of
441
- if type_definition.is_input and type_definition.is_one_of
442
- else None
443
- )
444
-
445
412
  graphql_object_type = GraphQLInputObjectType(
446
413
  name=type_name,
447
414
  fields=lambda: self.get_graphql_input_fields(type_definition),
@@ -449,7 +416,6 @@ class GraphQLCoreConverter:
449
416
  extensions={
450
417
  GraphQLCoreConverter.DEFINITION_BACKREF: type_definition,
451
418
  },
452
- out_type=out_type,
453
419
  )
454
420
 
455
421
  self.type_map[type_name] = ConcreteType(