strawberry-graphql 0.276.1__py3-none-any.whl → 0.277.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 CHANGED
@@ -11,6 +11,7 @@ from .permission import BasePermission
11
11
  from .scalars import ID
12
12
  from .schema import Schema
13
13
  from .schema_directive import schema_directive
14
+ from .streamable import Streamable
14
15
  from .types.arguments import argument
15
16
  from .types.auto import auto
16
17
  from .types.cast import cast
@@ -37,6 +38,7 @@ __all__ = [
37
38
  "Private",
38
39
  "Schema",
39
40
  "Some",
41
+ "Streamable",
40
42
  "argument",
41
43
  "asdict",
42
44
  "auto",
strawberry/annotation.py CHANGED
@@ -17,6 +17,7 @@ from typing import (
17
17
  )
18
18
  from typing_extensions import Self, get_args, get_origin
19
19
 
20
+ from strawberry.streamable import StrawberryStreamable
20
21
  from strawberry.types.base import (
21
22
  StrawberryList,
22
23
  StrawberryMaybe,
@@ -143,6 +144,8 @@ class StrawberryAnnotation:
143
144
 
144
145
  if self._is_lazy_type(evaled_type):
145
146
  return evaled_type
147
+ if self._is_streamable(evaled_type, args):
148
+ return self.create_list(list[evaled_type]) # type: ignore[valid-type]
146
149
  if self._is_list(evaled_type):
147
150
  return self.create_list(evaled_type)
148
151
  if self._is_maybe(evaled_type):
@@ -332,6 +335,10 @@ class StrawberryAnnotation:
332
335
  def _is_maybe(cls, annotation: Any) -> bool:
333
336
  return _annotation_is_maybe(annotation)
334
337
 
338
+ @classmethod
339
+ def _is_streamable(cls, annotation: Any, args: list[Any]) -> bool:
340
+ return any(isinstance(arg, StrawberryStreamable) for arg in args)
341
+
335
342
  @classmethod
336
343
  def _is_strawberry_type(cls, evaled_type: Any) -> bool:
337
344
  # Prevent import cycles
@@ -116,7 +116,7 @@ if TYPE_CHECKING:
116
116
  )
117
117
 
118
118
 
119
- def type( # noqa: PLR0915
119
+ def type(
120
120
  model: builtins.type[PydanticModel],
121
121
  *,
122
122
  fields: Optional[list[str]] = None,
@@ -129,7 +129,7 @@ def type( # noqa: PLR0915
129
129
  include_computed: bool = False,
130
130
  use_pydantic_alias: bool = True,
131
131
  ) -> Callable[..., builtins.type[StrawberryTypeFromPydantic[PydanticModel]]]:
132
- def wrap(cls: Any) -> builtins.type[StrawberryTypeFromPydantic[PydanticModel]]: # noqa: PLR0915
132
+ def wrap(cls: Any) -> builtins.type[StrawberryTypeFromPydantic[PydanticModel]]:
133
133
  compat = PydanticCompat.from_model(model)
134
134
  model_fields = compat.get_model_fields(model, include_computed=include_computed)
135
135
  original_fields_set = set(fields) if fields else set()
@@ -29,7 +29,9 @@ class DirectivesExtension(SchemaExtension):
29
29
  ) -> AwaitableOrValue[Any]:
30
30
  value = await await_maybe(_next(root, info, *args, **kwargs))
31
31
 
32
- for directive in info.field_nodes[0].directives:
32
+ nodes = list(info.field_nodes)
33
+
34
+ for directive in nodes[0].directives:
33
35
  if directive.name.value in SPECIFIED_DIRECTIVES:
34
36
  continue
35
37
  strawberry_directive, arguments = process_directive(directive, value, info)
@@ -49,7 +51,9 @@ class DirectivesExtensionSync(SchemaExtension):
49
51
  ) -> AwaitableOrValue[Any]:
50
52
  value = _next(root, info, *args, **kwargs)
51
53
 
52
- for directive in info.field_nodes[0].directives:
54
+ nodes = list(info.field_nodes)
55
+
56
+ for directive in nodes[0].directives:
53
57
  if directive.name.value in SPECIFIED_DIRECTIVES:
54
58
  continue
55
59
  strawberry_directive, arguments = process_directive(directive, value, info)
@@ -1,7 +1,8 @@
1
1
  from collections.abc import Iterator
2
- from typing import Callable
2
+ from typing import Any, Callable
3
3
 
4
4
  from graphql.error import GraphQLError
5
+ from graphql.execution import ExecutionResult
5
6
 
6
7
  from strawberry.extensions.base_extension import SchemaExtension
7
8
 
@@ -33,18 +34,30 @@ class MaskErrors(SchemaExtension):
33
34
  original_error=None,
34
35
  )
35
36
 
37
+ # TODO: proper typing
38
+ def _process_result(self, result: Any) -> None:
39
+ if not result.errors:
40
+ return
41
+
42
+ processed_errors: list[GraphQLError] = []
43
+
44
+ for error in result.errors:
45
+ if self.should_mask_error(error):
46
+ processed_errors.append(self.anonymise_error(error))
47
+ else:
48
+ processed_errors.append(error)
49
+
50
+ result.errors = processed_errors
51
+
36
52
  def on_operation(self) -> Iterator[None]:
37
53
  yield
54
+
38
55
  result = self.execution_context.result
39
- if result and result.errors:
40
- processed_errors: list[GraphQLError] = []
41
- for error in result.errors:
42
- if self.should_mask_error(error):
43
- processed_errors.append(self.anonymise_error(error))
44
- else:
45
- processed_errors.append(error)
46
-
47
- result.errors = processed_errors
56
+
57
+ if isinstance(result, ExecutionResult):
58
+ self._process_result(result)
59
+ elif result:
60
+ self._process_result(result.initial_result)
48
61
 
49
62
 
50
63
  __all__ = ["MaskErrors"]
@@ -43,7 +43,7 @@ class ValidationCache(SchemaExtension):
43
43
  execution_context.graphql_document,
44
44
  execution_context.validation_rules,
45
45
  )
46
- execution_context.errors = errors
46
+ execution_context.pre_execution_errors = errors
47
47
  yield
48
48
 
49
49
 
@@ -1,26 +1,36 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import TYPE_CHECKING, Any, Optional
4
+ from typing import Any, Optional
5
5
  from typing_extensions import Literal, TypedDict
6
6
 
7
- if TYPE_CHECKING:
8
- from strawberry.types import ExecutionResult
7
+ from strawberry.schema._graphql_core import (
8
+ GraphQLIncrementalExecutionResults,
9
+ ResultType,
10
+ )
9
11
 
10
12
 
11
13
  class GraphQLHTTPResponse(TypedDict, total=False):
12
14
  data: Optional[dict[str, object]]
13
15
  errors: Optional[list[object]]
14
16
  extensions: Optional[dict[str, object]]
15
-
16
-
17
- def process_result(result: ExecutionResult) -> GraphQLHTTPResponse:
18
- data: GraphQLHTTPResponse = {"data": result.data}
19
-
20
- if result.errors:
21
- data["errors"] = [err.formatted for err in result.errors]
22
- if result.extensions:
23
- data["extensions"] = result.extensions
17
+ hasNext: Optional[bool]
18
+ completed: Optional[list[Any]]
19
+ pending: Optional[list[Any]]
20
+ initial: Optional[list[Any]]
21
+ incremental: Optional[list[Any]]
22
+
23
+
24
+ def process_result(result: ResultType) -> GraphQLHTTPResponse:
25
+ if isinstance(result, GraphQLIncrementalExecutionResults):
26
+ return result
27
+
28
+ errors, extensions = result.errors, result.extensions
29
+ data: GraphQLHTTPResponse = {
30
+ "data": result.data,
31
+ **({"errors": [err.formatted for err in errors]} if errors else {}),
32
+ **({"extensions": extensions} if extensions else {}),
33
+ }
24
34
 
25
35
  return data
26
36
 
@@ -25,6 +25,9 @@ from strawberry.http import (
25
25
  process_result,
26
26
  )
27
27
  from strawberry.http.ides import GraphQL_IDE
28
+ from strawberry.schema._graphql_core import (
29
+ GraphQLIncrementalExecutionResults,
30
+ )
28
31
  from strawberry.schema.base import BaseSchema
29
32
  from strawberry.schema.exceptions import (
30
33
  CannotGetOperationTypeError,
@@ -352,6 +355,75 @@ class AsyncBaseHTTPView(
352
355
  "Content-Type": "multipart/mixed;boundary=graphql;subscriptionSpec=1.0,application/json",
353
356
  },
354
357
  )
358
+ if isinstance(result, GraphQLIncrementalExecutionResults):
359
+
360
+ async def stream() -> AsyncGenerator[str, None]:
361
+ yield "---"
362
+
363
+ response = await self.process_result(request, result.initial_result)
364
+
365
+ response["hasNext"] = result.initial_result.has_next
366
+ response["pending"] = [
367
+ p.formatted for p in result.initial_result.pending
368
+ ]
369
+ response["extensions"] = result.initial_result.extensions
370
+
371
+ yield self.encode_multipart_data(response, "-")
372
+
373
+ all_pending = result.initial_result.pending
374
+
375
+ async for value in result.subsequent_results:
376
+ response = {
377
+ "hasNext": value.has_next,
378
+ "extensions": value.extensions,
379
+ }
380
+
381
+ if value.pending:
382
+ response["pending"] = [p.formatted for p in value.pending]
383
+
384
+ if value.completed:
385
+ response["completed"] = [p.formatted for p in value.completed]
386
+
387
+ if value.incremental:
388
+ incremental = []
389
+
390
+ all_pending.extend(value.pending)
391
+
392
+ for incremental_value in value.incremental:
393
+ pending_value = next(
394
+ (
395
+ v
396
+ for v in all_pending
397
+ if v.id == incremental_value.id
398
+ ),
399
+ None,
400
+ )
401
+
402
+ assert pending_value
403
+
404
+ incremental.append(
405
+ {
406
+ **incremental_value.formatted,
407
+ "path": pending_value.path,
408
+ "label": pending_value.label,
409
+ }
410
+ )
411
+
412
+ response["incremental"] = incremental
413
+
414
+ yield self.encode_multipart_data(response, "-")
415
+
416
+ yield "--\r\n"
417
+
418
+ return await self.create_streaming_response(
419
+ request,
420
+ stream,
421
+ sub_response,
422
+ headers={
423
+ "Transfer-Encoding": "chunked",
424
+ "Content-Type": 'multipart/mixed; boundary="-"',
425
+ },
426
+ )
355
427
 
356
428
  response_data = await self.process_result(request=request, result=result)
357
429
 
@@ -363,12 +435,16 @@ class AsyncBaseHTTPView(
363
435
  )
364
436
 
365
437
  def encode_multipart_data(self, data: Any, separator: str) -> str:
438
+ encoded_data = self.encode_json(data)
439
+
366
440
  return "".join(
367
441
  [
368
- f"\r\n--{separator}\r\n",
369
- "Content-Type: application/json\r\n\r\n",
370
- self.encode_json(data),
371
- "\n",
442
+ "\r\n",
443
+ "Content-Type: application/json; charset=utf-8\r\n",
444
+ "Content-Length: " + str(len(encoded_data)) + "\r\n",
445
+ "\r\n",
446
+ encoded_data,
447
+ f"\r\n--{separator}",
372
448
  ]
373
449
  )
374
450
 
@@ -561,9 +561,9 @@ def print_schema_definition(
561
561
  def print_directive(
562
562
  directive: GraphQLDirective, *, schema: BaseSchema
563
563
  ) -> Optional[str]:
564
- strawberry_directive = directive.extensions["strawberry-definition"]
564
+ strawberry_directive = directive.extensions.get("strawberry-definition")
565
565
 
566
- if (
566
+ if strawberry_directive is None or (
567
567
  isinstance(strawberry_directive, StrawberrySchemaDirective)
568
568
  and not strawberry_directive.print_definition
569
569
  ):
@@ -621,6 +621,14 @@ def print_schema(schema: BaseSchema) -> str:
621
621
  if (printed_directive := print_directive(directive, schema=schema)) is not None
622
622
  ]
623
623
 
624
+ if schema.config.enable_experimental_incremental_execution:
625
+ directives.append(
626
+ "directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT"
627
+ )
628
+ directives.append(
629
+ "directive @stream(if: Boolean, label: String, initialCount: Int = 0) on FIELD"
630
+ )
631
+
624
632
  def _name_getter(type_: Any) -> str:
625
633
  if hasattr(type_, "name"):
626
634
  return type_.name
strawberry/relay/types.py CHANGED
@@ -762,7 +762,7 @@ class ListConnection(Connection[NodeType]):
762
762
  )
763
763
 
764
764
  @classmethod
765
- def resolve_connection( # noqa: PLR0915
765
+ def resolve_connection(
766
766
  cls,
767
767
  nodes: NodeIterableType[NodeType],
768
768
  *,
@@ -0,0 +1,55 @@
1
+ from typing import Union
2
+
3
+ from graphql.execution import ExecutionContext as GraphQLExecutionContext
4
+ from graphql.execution import ExecutionResult as OriginalGraphQLExecutionResult
5
+ from graphql.execution import execute, subscribe
6
+
7
+ from strawberry.types import ExecutionResult
8
+
9
+ try:
10
+ from graphql import ( # type: ignore[attr-defined]
11
+ ExperimentalIncrementalExecutionResults as GraphQLIncrementalExecutionResults,
12
+ )
13
+ from graphql.execution import ( # type: ignore[attr-defined]
14
+ InitialIncrementalExecutionResult,
15
+ experimental_execute_incrementally,
16
+ )
17
+ from graphql.type.directives import ( # type: ignore[attr-defined]
18
+ GraphQLDeferDirective,
19
+ GraphQLStreamDirective,
20
+ )
21
+
22
+ incremental_execution_directives = (
23
+ GraphQLDeferDirective,
24
+ GraphQLStreamDirective,
25
+ )
26
+
27
+ GraphQLExecutionResult = Union[
28
+ OriginalGraphQLExecutionResult, InitialIncrementalExecutionResult
29
+ ]
30
+
31
+ except ImportError:
32
+ GraphQLIncrementalExecutionResults = type(None)
33
+ GraphQLExecutionResult = OriginalGraphQLExecutionResult # type: ignore
34
+
35
+ incremental_execution_directives = () # type: ignore
36
+ experimental_execute_incrementally = None
37
+
38
+
39
+ # TODO: give this a better name, maybe also a better place
40
+ ResultType = Union[
41
+ OriginalGraphQLExecutionResult,
42
+ GraphQLIncrementalExecutionResults,
43
+ ExecutionResult,
44
+ ]
45
+
46
+ __all__ = [
47
+ "GraphQLExecutionContext",
48
+ "GraphQLExecutionResult",
49
+ "GraphQLIncrementalExecutionResults",
50
+ "ResultType",
51
+ "execute",
52
+ "experimental_execute_incrementally",
53
+ "incremental_execution_directives",
54
+ "subscribe",
55
+ ]
@@ -17,6 +17,7 @@ class StrawberryConfig:
17
17
  relay_use_legacy_global_id: bool = False
18
18
  disable_field_suggestions: bool = False
19
19
  info_class: type[Info] = Info
20
+ enable_experimental_incremental_execution: bool = False
20
21
  _unsafe_disable_same_type_validation: bool = False
21
22
 
22
23
  def __post_init__(
@@ -15,7 +15,6 @@ from typing import (
15
15
  cast,
16
16
  )
17
17
 
18
- from graphql import ExecutionContext as GraphQLExecutionContext
19
18
  from graphql import ExecutionResult as GraphQLExecutionResult
20
19
  from graphql import (
21
20
  ExecutionResult as OriginalExecutionResult,
@@ -36,7 +35,6 @@ from graphql import (
36
35
  parse,
37
36
  validate_schema,
38
37
  )
39
- from graphql.execution import execute, subscribe
40
38
  from graphql.execution.middleware import MiddlewareManager
41
39
  from graphql.type.directives import specified_directives
42
40
  from graphql.validation import validate
@@ -69,6 +67,15 @@ from strawberry.utils.aio import aclosing
69
67
  from strawberry.utils.await_maybe import await_maybe
70
68
 
71
69
  from . import compat
70
+ from ._graphql_core import (
71
+ GraphQLExecutionContext,
72
+ GraphQLIncrementalExecutionResults,
73
+ ResultType,
74
+ execute,
75
+ experimental_execute_incrementally,
76
+ incremental_execution_directives,
77
+ subscribe,
78
+ )
72
79
  from .base import BaseSchema
73
80
  from .config import StrawberryConfig
74
81
  from .exceptions import CannotGetOperationTypeError, InvalidOperationTypeError
@@ -77,7 +84,6 @@ if TYPE_CHECKING:
77
84
  from collections.abc import Iterable, Mapping
78
85
  from typing_extensions import TypeAlias
79
86
 
80
- from graphql.execution.collect_fields import FieldGroup # type: ignore
81
87
  from graphql.language import DocumentNode
82
88
  from graphql.pyutils import Path
83
89
  from graphql.type import GraphQLResolveInfo
@@ -99,6 +105,7 @@ OriginSubscriptionResult = Union[
99
105
  AsyncIterator[OriginalExecutionResult],
100
106
  ]
101
107
 
108
+
102
109
  DEFAULT_ALLOWED_OPERATION_TYPES = {
103
110
  OperationType.QUERY,
104
111
  OperationType.MUTATION,
@@ -129,9 +136,12 @@ def validate_document(
129
136
  def _run_validation(execution_context: ExecutionContext) -> None:
130
137
  # Check if there are any validation rules or if validation has
131
138
  # already been run by an extension
132
- if len(execution_context.validation_rules) > 0 and execution_context.errors is None:
139
+ if (
140
+ len(execution_context.validation_rules) > 0
141
+ and execution_context.pre_execution_errors is None
142
+ ):
133
143
  assert execution_context.graphql_document
134
- execution_context.errors = validate_document(
144
+ execution_context.pre_execution_errors = validate_document(
135
145
  execution_context.schema._schema,
136
146
  execution_context.graphql_document,
137
147
  execution_context.validation_rules,
@@ -168,17 +178,18 @@ class StrawberryGraphQLCoreExecutionContext(GraphQLExecutionContext):
168
178
 
169
179
  self.operation_extensions = operation_extensions
170
180
 
171
- def build_resolve_info(
172
- self,
173
- field_def: GraphQLField,
174
- field_group: FieldGroup,
175
- parent_type: GraphQLObjectType,
176
- path: Path,
177
- ) -> GraphQLResolveInfo:
178
- if IS_GQL_33:
181
+ if IS_GQL_33:
182
+
183
+ def build_resolve_info(
184
+ self,
185
+ field_def: GraphQLField,
186
+ field_nodes: list[FieldNode],
187
+ parent_type: GraphQLObjectType,
188
+ path: Path,
189
+ ) -> GraphQLResolveInfo:
179
190
  return _OperationContextAwareGraphQLResolveInfo( # type: ignore
180
- field_group.fields[0].node.name.value,
181
- field_group.to_nodes(),
191
+ field_nodes[0].name.value,
192
+ field_nodes,
182
193
  field_def.type,
183
194
  parent_type,
184
195
  path,
@@ -192,13 +203,6 @@ class StrawberryGraphQLCoreExecutionContext(GraphQLExecutionContext):
192
203
  self.operation_extensions,
193
204
  )
194
205
 
195
- return super().build_resolve_info(
196
- field_def,
197
- field_group,
198
- parent_type,
199
- path,
200
- )
201
-
202
206
 
203
207
  class Schema(BaseSchema):
204
208
  def __init__(
@@ -321,11 +325,16 @@ class Schema(BaseSchema):
321
325
  graphql_types.append(graphql_type)
322
326
 
323
327
  try:
328
+ directives = specified_directives + tuple(graphql_directives) # type: ignore
329
+
330
+ if self.config.enable_experimental_incremental_execution:
331
+ directives = tuple(directives) + tuple(incremental_execution_directives)
332
+
324
333
  self._schema = GraphQLSchema(
325
334
  query=query_type,
326
335
  mutation=mutation_type,
327
336
  subscription=subscription_type if subscription else None,
328
- directives=specified_directives + tuple(graphql_directives),
337
+ directives=directives, # type: ignore
329
338
  types=graphql_types,
330
339
  extensions={
331
340
  GraphQLCoreConverter.DEFINITION_BACKREF: self,
@@ -489,12 +498,12 @@ class Schema(BaseSchema):
489
498
  context.graphql_document = parse(context.query)
490
499
 
491
500
  except GraphQLError as error:
492
- context.errors = [error]
501
+ context.pre_execution_errors = [error]
493
502
  return PreExecutionError(data=None, errors=[error])
494
503
 
495
504
  except Exception as error: # noqa: BLE001
496
505
  error = GraphQLError(str(error), original_error=error)
497
- context.errors = [error]
506
+ context.pre_execution_errors = [error]
498
507
  return PreExecutionError(data=None, errors=[error])
499
508
 
500
509
  try:
@@ -507,10 +516,10 @@ class Schema(BaseSchema):
507
516
 
508
517
  async with extensions_runner.validation():
509
518
  _run_validation(context)
510
- if context.errors:
519
+ if context.pre_execution_errors:
511
520
  return PreExecutionError(
512
521
  data=None,
513
- errors=context.errors,
522
+ errors=context.pre_execution_errors,
514
523
  )
515
524
 
516
525
  return None
@@ -518,22 +527,26 @@ class Schema(BaseSchema):
518
527
  async def _handle_execution_result(
519
528
  self,
520
529
  context: ExecutionContext,
521
- result: Union[GraphQLExecutionResult, ExecutionResult],
530
+ result: ResultType,
522
531
  extensions_runner: SchemaExtensionsRunner,
523
532
  *,
524
533
  # TODO: can we remove this somehow, see comment in execute
525
534
  skip_process_errors: bool = False,
526
535
  ) -> ExecutionResult:
536
+ # TODO: handle this, also, why do we have both GraphQLExecutionResult and ExecutionResult?
537
+ if isinstance(result, GraphQLIncrementalExecutionResults):
538
+ return result
539
+
527
540
  # Set errors on the context so that it's easier
528
541
  # to access in extensions
529
542
  if result.errors:
530
- context.errors = result.errors
543
+ context.pre_execution_errors = result.errors
531
544
  if not skip_process_errors:
532
545
  self._process_errors(result.errors, context)
533
546
  if isinstance(result, GraphQLExecutionResult):
534
547
  result = ExecutionResult(data=result.data, errors=result.errors)
535
548
  result.extensions = await extensions_runner.get_extensions_results(context)
536
- context.result = result # type: ignore # mypy failed to deduce correct type.
549
+ context.result = result
537
550
  return result
538
551
 
539
552
  async def execute(
@@ -566,6 +579,17 @@ class Schema(BaseSchema):
566
579
  extensions_runner = self.create_extensions_runner(execution_context, extensions)
567
580
  middleware_manager = self._get_middleware_manager(extensions)
568
581
 
582
+ execute_function = execute
583
+
584
+ if self.config.enable_experimental_incremental_execution:
585
+ execute_function = experimental_execute_incrementally
586
+
587
+ if execute_function is None:
588
+ raise RuntimeError(
589
+ "Incremental execution is enabled but experimental_execute_incrementally is not available, "
590
+ "please install graphql-core>=3.3.0"
591
+ )
592
+
569
593
  custom_context_kwargs = self._get_custom_context_kwargs(operation_extensions)
570
594
 
571
595
  try:
@@ -586,7 +610,7 @@ class Schema(BaseSchema):
586
610
  async with extensions_runner.executing():
587
611
  if not execution_context.result:
588
612
  result = await await_maybe(
589
- execute(
613
+ execute_function(
590
614
  self._schema,
591
615
  execution_context.graphql_document,
592
616
  root_value=execution_context.root_value,
@@ -603,8 +627,10 @@ class Schema(BaseSchema):
603
627
  result = execution_context.result
604
628
  # Also set errors on the execution_context so that it's easier
605
629
  # to access in extensions
606
- if result.errors:
607
- execution_context.errors = result.errors
630
+
631
+ # TODO: maybe here use the first result from incremental execution if it exists
632
+ if isinstance(result, GraphQLExecutionResult) and result.errors:
633
+ execution_context.pre_execution_errors = result.errors
608
634
 
609
635
  # Run the `Schema.process_errors` function here before
610
636
  # extensions have a chance to modify them (see the MaskErrors
@@ -659,6 +685,16 @@ class Schema(BaseSchema):
659
685
  extensions_runner = self.create_extensions_runner(execution_context, extensions)
660
686
  middleware_manager = self._get_middleware_manager(extensions)
661
687
 
688
+ execute_function = execute
689
+
690
+ if self.config.enable_experimental_incremental_execution:
691
+ execute_function = experimental_execute_incrementally
692
+
693
+ if execute_function is None:
694
+ raise RuntimeError(
695
+ "Incremental execution is enabled but experimental_execute_incrementally is not available, "
696
+ "please install graphql-core>=3.3.0"
697
+ )
662
698
  custom_context_kwargs = self._get_custom_context_kwargs(operation_extensions)
663
699
 
664
700
  try:
@@ -677,7 +713,7 @@ class Schema(BaseSchema):
677
713
  )
678
714
 
679
715
  except GraphQLError as error:
680
- execution_context.errors = [error]
716
+ execution_context.pre_execution_errors = [error]
681
717
  self._process_errors([error], execution_context)
682
718
  return ExecutionResult(
683
719
  data=None,
@@ -697,19 +733,19 @@ class Schema(BaseSchema):
697
733
 
698
734
  with extensions_runner.validation():
699
735
  _run_validation(execution_context)
700
- if execution_context.errors:
736
+ if execution_context.pre_execution_errors:
701
737
  self._process_errors(
702
- execution_context.errors, execution_context
738
+ execution_context.pre_execution_errors, execution_context
703
739
  )
704
740
  return ExecutionResult(
705
741
  data=None,
706
- errors=execution_context.errors,
742
+ errors=execution_context.pre_execution_errors,
707
743
  extensions=extensions_runner.get_extensions_results_sync(),
708
744
  )
709
745
 
710
746
  with extensions_runner.executing():
711
747
  if not execution_context.result:
712
- result = execute(
748
+ result = execute_function(
713
749
  self._schema,
714
750
  execution_context.graphql_document,
715
751
  root_value=execution_context.root_value,
@@ -733,7 +769,7 @@ class Schema(BaseSchema):
733
769
  # Also set errors on the context so that it's easier
734
770
  # to access in extensions
735
771
  if result.errors:
736
- execution_context.errors = result.errors
772
+ execution_context.pre_execution_errors = result.errors
737
773
 
738
774
  # Run the `Schema.process_errors` function here before
739
775
  # extensions have a chance to modify them (see the MaskErrors
@@ -748,7 +784,7 @@ class Schema(BaseSchema):
748
784
  raise
749
785
  except Exception as exc: # noqa: BLE001
750
786
  errors = [_coerce_error(exc)]
751
- execution_context.errors = errors
787
+ execution_context.pre_execution_errors = errors
752
788
  self._process_errors(errors, execution_context)
753
789
  return ExecutionResult(
754
790
  data=None,
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html>
3
3
  <head>
4
4
  <title>Strawberry GraphiQL</title>
@@ -61,8 +61,8 @@
61
61
  <link
62
62
  crossorigin
63
63
  rel="stylesheet"
64
- href="https://unpkg.com/graphiql@3.0.9/graphiql.min.css"
65
- integrity="sha384-yz3/sqpuplkA7msMo0FE4ekg0xdwdvZ8JX9MVZREsxipqjU4h8IRfmAMRcb1QpUy"
64
+ href="https://unpkg.com/graphiql@3.8.3/graphiql.min.css"
65
+ integrity="sha384-Mq3vbRBY71jfjQAt/DcjxUIYY33ksal4cgdRt9U/hNPvHBCaT2JfJ/PTRiPKf0aM"
66
66
  />
67
67
 
68
68
  <link
@@ -77,8 +77,8 @@
77
77
  <div id="graphiql" class="graphiql-container">Loading...</div>
78
78
  <script
79
79
  crossorigin
80
- src="https://unpkg.com/graphiql@3.0.9/graphiql.min.js"
81
- integrity="sha384-Mjte+vxCWz1ZYCzszGHiJqJa5eAxiqI4mc3BErq7eDXnt+UGLXSEW7+i0wmfPiji"
80
+ src="https://unpkg.com/graphiql@3.8.3/graphiql.min.js"
81
+ integrity="sha384-HbRVEFG0JGJZeAHCJ9Xm2+tpknBQ7QZmNlO/DgZtkZ0aJSypT96YYGRNod99l9Ie"
82
82
  ></script>
83
83
  <script
84
84
  crossorigin
@@ -0,0 +1,35 @@
1
+ from collections.abc import AsyncGenerator
2
+ from typing import Annotated, TypeVar
3
+
4
+
5
+ class StrawberryStreamable: ...
6
+
7
+
8
+ T = TypeVar("T")
9
+
10
+ Streamable = Annotated[AsyncGenerator[T, None], StrawberryStreamable()]
11
+ """Represents a list that can be streamed using @stream.
12
+
13
+ Example:
14
+
15
+ ```python
16
+ import strawberry
17
+
18
+
19
+ @strawberry.type
20
+ class Comment:
21
+ id: strawberry.ID
22
+ content: str
23
+
24
+
25
+ @strawberry.type
26
+ class Article:
27
+ @strawberry.field
28
+ @staticmethod
29
+ async def comments() -> strawberry.Streamable[Comment]:
30
+ for comment in fetch_comments():
31
+ yield comment
32
+ ```
33
+ """
34
+
35
+ __all__ = ["Streamable"]
@@ -7,7 +7,7 @@ from typing import (
7
7
  Optional,
8
8
  runtime_checkable,
9
9
  )
10
- from typing_extensions import Protocol, TypedDict
10
+ from typing_extensions import Protocol, TypedDict, deprecated
11
11
 
12
12
  from graphql import specified_rules
13
13
 
@@ -18,11 +18,11 @@ if TYPE_CHECKING:
18
18
  from typing_extensions import NotRequired
19
19
 
20
20
  from graphql import ASTValidationRule
21
- from graphql import ExecutionResult as GraphQLExecutionResult
22
21
  from graphql.error.graphql_error import GraphQLError
23
22
  from graphql.language import DocumentNode, OperationDefinitionNode
24
23
 
25
24
  from strawberry.schema import Schema
25
+ from strawberry.schema._graphql_core import GraphQLExecutionResult
26
26
 
27
27
  from .graphql import OperationType
28
28
 
@@ -48,7 +48,7 @@ class ExecutionContext:
48
48
  # Values that get populated during the GraphQL execution so that they can be
49
49
  # accessed by extensions
50
50
  graphql_document: Optional[DocumentNode] = None
51
- errors: Optional[list[GraphQLError]] = None
51
+ pre_execution_errors: Optional[list[GraphQLError]] = None
52
52
  result: Optional[GraphQLExecutionResult] = None
53
53
  extensions_results: dict[str, Any] = dataclasses.field(default_factory=dict)
54
54
 
@@ -86,6 +86,12 @@ class ExecutionContext:
86
86
 
87
87
  return get_first_operation(graphql_document)
88
88
 
89
+ @property
90
+ @deprecated("Use 'pre_execution_errors' instead")
91
+ def errors(self) -> Optional[list[GraphQLError]]:
92
+ """Deprecated: Use pre_execution_errors instead."""
93
+ return self.pre_execution_errors
94
+
89
95
 
90
96
  @dataclasses.dataclass
91
97
  class ExecutionResult:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: strawberry-graphql
3
- Version: 0.276.1
3
+ Version: 0.277.0
4
4
  Summary: A library for creating GraphQL APIs
5
5
  License: MIT
6
6
  Keywords: graphql,api,rest,starlette,async
@@ -1,10 +1,10 @@
1
- strawberry/__init__.py,sha256=-K---AYIgHvBVYF_9oovgEPNBbymXH673bntlV9sOeU,1491
1
+ strawberry/__init__.py,sha256=tavG4mNFBNHhGBoFR2T7fhiCQ7P-ITHify10nkKBOJE,1544
2
2
  strawberry/__main__.py,sha256=3U77Eu21mJ-LY27RG-JEnpbh6Z63wGOom4i-EoLtUcY,59
3
3
  strawberry/aiohttp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  strawberry/aiohttp/test/__init__.py,sha256=4xxdUZtIISSOwjrcnmox7AvT4WWjowCm5bUuPdQneMg,71
5
5
  strawberry/aiohttp/test/client.py,sha256=8FKZTnvawxYpgEICOri-34O3wHRHLhRpjH_Ktp2EupQ,1801
6
6
  strawberry/aiohttp/views.py,sha256=EhsaD0Ms7qhHxGyS0qDbRPKxz3VUaSdsbEZKTniIjaM,7962
7
- strawberry/annotation.py,sha256=FS-5IIEhFit79QIQyWebaScO9kFZYY_jKOLKCXBhXrw,13828
7
+ strawberry/annotation.py,sha256=D_12gZSdyges7DMpzsqjGsAbex0M-zffyPa3NWt42bw,14180
8
8
  strawberry/asgi/__init__.py,sha256=psdKl_52LGkxKKbzZlmwNGZ9jz2FLyLSC7fUhys4FqY,8169
9
9
  strawberry/asgi/test/__init__.py,sha256=4xxdUZtIISSOwjrcnmox7AvT4WWjowCm5bUuPdQneMg,71
10
10
  strawberry/asgi/test/client.py,sha256=kp2O5znHWuAB5VVYO8p4XPSTEDDXBSjNz5WHqW0r6GM,1473
@@ -81,7 +81,7 @@ strawberry/experimental/pydantic/conversion_types.py,sha256=jf7PR5Q7hgo4J_AuxBK-
81
81
  strawberry/experimental/pydantic/error_type.py,sha256=RdmiUY4V0baXCAk80ST-XtCiZbndZaaUSEajQplDAzw,4557
82
82
  strawberry/experimental/pydantic/exceptions.py,sha256=pDMPL94ojuSGHxk8H8mI2pfWReG8BhqZ5T2eSxfOi9w,1486
83
83
  strawberry/experimental/pydantic/fields.py,sha256=NcB38JYk29fPwJWtoHkIvwTfqD2Ekf7fJ57GjvvK6mQ,2265
84
- strawberry/experimental/pydantic/object_type.py,sha256=lcQgmWLulegTlGWmj_9GhPv1d2L_DdPpimVgMEr9aT0,12897
84
+ strawberry/experimental/pydantic/object_type.py,sha256=qoTQXO4qdno0M2oQv0sll7lqeyul_WDNmoSZpm5V14s,12863
85
85
  strawberry/experimental/pydantic/utils.py,sha256=URSzmcK2KzNGsLv4RyFdFfJnr-ARNLkkM0D4CjijVQU,4035
86
86
  strawberry/ext/LICENSE,sha256=_oY0TZg0b_sW0--0T44aMTpy2e2zF1Kiyn8E1qDiivo,1249
87
87
  strawberry/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -94,11 +94,11 @@ strawberry/extensions/__init__.py,sha256=2TXnEVXumViXzBe-9ppb0CX90Wbc6644IE7aJQA
94
94
  strawberry/extensions/add_validation_rules.py,sha256=YwC_27jUpQ6DWcCB1RsuE1JD8R5rV7LAu5fVjdLchYs,1358
95
95
  strawberry/extensions/base_extension.py,sha256=ihsbUrhYt-x4X1j5a34FASmNF661Xev-3w4Qc5gUbHw,2351
96
96
  strawberry/extensions/context.py,sha256=9hTWNjxk-Kyr4RkpKE3BY05dkgS4WLRjJKj4tq28Lj8,7185
97
- strawberry/extensions/directives.py,sha256=F-ayBAImKHFap61WUJ_XO02COOFn3nWyN7cLkV9Dph0,3032
97
+ strawberry/extensions/directives.py,sha256=MYAA6lhlmWZM5q8In6Os53LWAUVuVa7AuLtTXQaERgQ,3090
98
98
  strawberry/extensions/disable_introspection.py,sha256=7FmktNvc9CzOJG9xf_nYG3LThs0cv-g2P-Kzlerna7w,717
99
99
  strawberry/extensions/disable_validation.py,sha256=WaA7x6Q-K4IMnvx35OQ1UtokIKaxkWvO_OJO9fFM_vA,750
100
100
  strawberry/extensions/field_extension.py,sha256=VUwUBbf57Vp_Ukc3Rh9eZDRuF2ubzRRipzsU-w5bAFc,5561
101
- strawberry/extensions/mask_errors.py,sha256=xPGN24l6C_zZ174jHQbOhSShTqqAB58ithhuTZjBXGQ,1481
101
+ strawberry/extensions/mask_errors.py,sha256=bKTdL4zWnY56QLZHqRjzZ39rHe4DDz2zPDinS3H-sIw,1765
102
102
  strawberry/extensions/max_aliases.py,sha256=qaV9rqHTqfhh7YdFnXVvjf14wmAiXBtKHGAxb1Yv4DQ,2547
103
103
  strawberry/extensions/max_tokens.py,sha256=53Gb0tSj-G7so_vLokdmtUal4KCXQBYLJi1LSIvdkXE,1045
104
104
  strawberry/extensions/parser_cache.py,sha256=oi6Svpy21_YP-d9G3nv_5HzJPw5FyBhWplCYnzcKwO8,1291
@@ -111,7 +111,7 @@ strawberry/extensions/tracing/datadog.py,sha256=-5zVf5JSjujzNJQvpu7EANumhL1qeMET
111
111
  strawberry/extensions/tracing/opentelemetry.py,sha256=Bre5HkUwZwRawSvS8Zlix67g46AaR4_XWA49LArm6UI,7304
112
112
  strawberry/extensions/tracing/utils.py,sha256=tXZNyqfct6YNSWi3GRj4GU1fKQGvSce8ZESfoVeys7U,654
113
113
  strawberry/extensions/utils.py,sha256=sjhxItHzbDhqHtnR63WbE35qzHhTyf9NSffidet79Hc,995
114
- strawberry/extensions/validation_cache.py,sha256=D4Jyj7WoUkgp_UH6bo9ytRZbPwJnencbti5Z1GszGhM,1433
114
+ strawberry/extensions/validation_cache.py,sha256=Fp0bz0HfbMVjaOVfTyetR7Knhic0tthkzB_0kOOyJY0,1447
115
115
  strawberry/fastapi/__init__.py,sha256=p5qg9AlkYjNOWKcT4uRiebIpR6pIb1HqDMiDfF5O3tg,147
116
116
  strawberry/fastapi/context.py,sha256=O_cDNppfUJJecM0ZU_RJ-dhdF0o1x39JfYvYg-7uob4,684
117
117
  strawberry/fastapi/router.py,sha256=cfRGP1SL_QaSNjCk3Zi7YDQte1EsIljvqTDB1J0O4fQ,12018
@@ -134,8 +134,8 @@ strawberry/file_uploads/scalars.py,sha256=NRDeB7j8aotqIkz9r62ISTf4DrxQxEZYUuHsX5
134
134
  strawberry/file_uploads/utils.py,sha256=-c6TbqUI-Dkb96hWCrZabh6TL2OabBuQNkCarOqgDm4,1181
135
135
  strawberry/flask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
136
  strawberry/flask/views.py,sha256=MCvAsNgTZLU8RvTYKWfnLU2w7Wv1ZZpxW9W3TyTZuPY,6355
137
- strawberry/http/__init__.py,sha256=ytAirKk7K7D5knY21tpCGeZ-sCPgwMsijL5AxmOy-94,1163
138
- strawberry/http/async_base_view.py,sha256=N72Ym9b1z8VbzrgrMDehoKSLFUdObK4fJ1aRZRjZQ1U,20806
137
+ strawberry/http/__init__.py,sha256=8UWXKZ2IG6_nInp9liUj0qMquDNRR-9o--0EMBL-gnQ,1482
138
+ strawberry/http/async_base_view.py,sha256=-9VuOw1dwUSItLbStOSkyjX-nO_ThFh-Rm0fiRCGhQk,23588
139
139
  strawberry/http/base.py,sha256=MiX0-RqOkhRvlfpmuvgTHp4tygbUmG8fnLc0uCrOllU,2550
140
140
  strawberry/http/exceptions.py,sha256=9E2dreS1crRoJVUEPuHyx23NcDELDHNzkAOa-rGv-8I,348
141
141
  strawberry/http/ides.py,sha256=WjU0nsMDgr3Bd1ebWkUEkO2d1hk0dI16mLqXyCHqklA,613
@@ -150,14 +150,14 @@ strawberry/parent.py,sha256=JYFp-HGCgwbH2oB4uLSiIO4cVsoPaxX6lfYmxOKPkSg,1362
150
150
  strawberry/permission.py,sha256=dSRJMjSCmTlXfvfC24kCSrAk0txTjYKTJ5ZVU5IW91Y,7537
151
151
  strawberry/printer/__init__.py,sha256=DmepjmgtkdF5RxK_7yC6qUyRWn56U-9qeZMbkztYB9w,62
152
152
  strawberry/printer/ast_from_value.py,sha256=Tkme60qlykbN2m3dNPNMOe65X-wj6EmcDQwgQv7gUkc,4987
153
- strawberry/printer/printer.py,sha256=49u3QwttTGvh13HXZtbTnkZzBwL1k5SLf8rXQLiTpl4,18814
153
+ strawberry/printer/printer.py,sha256=5E9w0wDsUv1hvkeXof12277NLMiCVy5MgJ6gSo_NJhQ,19177
154
154
  strawberry/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
155
155
  strawberry/quart/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
156
156
  strawberry/quart/views.py,sha256=f41HWnkGPuhs1NkjwHOZ0DEVnlr5nMSMr9GCxNsBxCs,7461
157
157
  strawberry/relay/__init__.py,sha256=Vi4btvA_g6Cj9Tk_F9GCSegapIf2WqkOWV8y3P0cTCs,553
158
158
  strawberry/relay/exceptions.py,sha256=Za0iXLBGZtd1HkesGm4xTr3QOeuyiCAe1hiCCQ2HHvE,4036
159
159
  strawberry/relay/fields.py,sha256=eqQOH8JAWZUP52nwaYCZ_z5Jvp69_T_gx1pxjrdgV1k,18284
160
- strawberry/relay/types.py,sha256=u3-V7LPe_CniEmREMJyvXH9L9Ecc2CWQC5hRfUvL_Q4,30477
160
+ strawberry/relay/types.py,sha256=rndxONPRkBZUE6u6aTDynL9Lm7Ahkr7jOPT6IIQSrVE,30460
161
161
  strawberry/relay/utils.py,sha256=-QxroxkSYtFnMYsJyTyfIi0I1fLtjnt6siW0kLNiyfs,5908
162
162
  strawberry/resolvers.py,sha256=Vdidc3YFc4-olSQZD_xQ1icyAFbyzqs_8I3eSpMFlA4,260
163
163
  strawberry/sanic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -166,12 +166,13 @@ strawberry/sanic/utils.py,sha256=XjUVBFuBWfECBCZbx_YtrjQnFTUyIGTo7aISIeB22Gc,100
166
166
  strawberry/sanic/views.py,sha256=F5ZrKt-R3135evKLfhQuPd1isOexI0Lrzevm_6Te4Eg,7069
167
167
  strawberry/scalars.py,sha256=CGkG8CIfurXiYhidmW3qwy6M5BF_Mhih3wAEcWx_iBU,2278
168
168
  strawberry/schema/__init__.py,sha256=u1QCyDVQExUVDA20kyosKPz3TS5HMCN2NrXclhiFAL4,92
169
+ strawberry/schema/_graphql_core.py,sha256=_ubCP_4ZZ1KwZGLlHTPPcUVPk_hDh6EOp2FxjCfyKxM,1642
169
170
  strawberry/schema/base.py,sha256=wqvEOQ_aVkfebk9SlG9zg1YXl3MlwxGZhxFRoIkAxu0,4053
170
171
  strawberry/schema/compat.py,sha256=xNpOEDfi-MODpplMGaKuKeQIVcr-tcAaKaU3TlBc1Zs,1873
171
- strawberry/schema/config.py,sha256=6d2MPrAgq97-7aze555dRcB3yw-aeUexYMP3KVN22c0,1024
172
+ strawberry/schema/config.py,sha256=EQhyuKcQTOga_1Uw3nhu5SlS6lVbgsG1YZ3LOKqeztQ,1084
172
173
  strawberry/schema/exceptions.py,sha256=8gsMxxFDynMvRkUDuVL9Wwxk_zsmo6QoJ2l4NPxd64M,1137
173
174
  strawberry/schema/name_converter.py,sha256=JG5JKLr9wp8BMJIvG3_bVkwFdoLGbknNR1Bt75urXN0,6950
174
- strawberry/schema/schema.py,sha256=-dVGJfOAyq-w2lpEbzCaiRNPMH68nirv-Q6gZ4aW0UU,37951
175
+ strawberry/schema/schema.py,sha256=EZ6YLV5wqHrjxi3rVJ0HvbGeIlZrbSOZqEomKlu4-OY,39433
175
176
  strawberry/schema/schema_converter.py,sha256=ZGkZjLsqjZ-0y5NItsECHZbOOhjJioYRT6YROwmo4Gg,40125
176
177
  strawberry/schema/types/__init__.py,sha256=oHO3COWhL3L1KLYCJNY1XFf5xt2GGtHiMC-UaYbFfnA,68
177
178
  strawberry/schema/types/base_scalars.py,sha256=JRUq0WjEkR9dFewstZnqnZKp0uOEipo4UXNF5dzRf4M,1971
@@ -183,8 +184,9 @@ strawberry/schema_codegen/__init__.py,sha256=mN4Qmu5Iakht6nHpRpt9hCs8e--oTPlVtDJ
183
184
  strawberry/schema_directive.py,sha256=CbjdX54EIeWGkJu4SgiLR8mph5_8wyNsgJk2oLoQK_0,2023
184
185
  strawberry/schema_directives.py,sha256=KGKFWCODjm1Ah9qNV_bBwbic7Mld4qLWnWQkev-PG8A,175
185
186
  strawberry/static/apollo-sandbox.html,sha256=2XzkbE0dqsFHqehE-jul9_J9TFOpwA6Ylrlo0Kdx_9w,973
186
- strawberry/static/graphiql.html,sha256=BkiqZlC63f1sHBDs_UpMzcibcNrHKh7K41Sp23yttfo,4257
187
+ strawberry/static/graphiql.html,sha256=0e3pvTnAet-lNEqA_pgJ8Ak2CdMt34zPKMMMzpAkEVU,4257
187
188
  strawberry/static/pathfinder.html,sha256=0DPx9AmJ2C_sJstFXnWOz9k5tVQHeHaK7qdVY4lAlmk,1547
189
+ strawberry/streamable.py,sha256=8dqvKAv_Nhp8vEi4PUYyziCt3SUyCr6ZuqCNZ46Mqno,611
188
190
  strawberry/subscriptions/__init__.py,sha256=1VGmiCzFepqRFyCikagkUoHHdoTG3XYlFu9GafoQMws,170
189
191
  strawberry/subscriptions/protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
190
192
  strawberry/subscriptions/protocols/graphql_transport_ws/__init__.py,sha256=wN6dkMu6WiaIZTE19PGoN9xXpIN_RdDE_q7F7ZgjCxk,138
@@ -204,7 +206,7 @@ strawberry/types/auto.py,sha256=WZ2cQAI8nREUigBzpzFqIKGjJ_C2VqpAPNe8vPjTciM,3007
204
206
  strawberry/types/base.py,sha256=Bfa-5Wen8qR7m6tlSMRRGlGE-chRGMHjQMopfNdbbrk,15197
205
207
  strawberry/types/cast.py,sha256=fx86MkLW77GIximBAwUk5vZxSGwDqUA6XicXvz8EXwQ,916
206
208
  strawberry/types/enum.py,sha256=7bK7YUzlG117_V9x-f9hx5vogcCRF6UBUFteeKhjDHg,6306
207
- strawberry/types/execution.py,sha256=kW5rgkWP98oysJWNc_fcxyO1PZ36NJpPTPZpZP2ZXYk,3820
209
+ strawberry/types/execution.py,sha256=_Rl4akU174P_2mq3x1N1QTj0LgJn3CQ43hPFzN3rs_s,4075
208
210
  strawberry/types/field.py,sha256=vxb7JvkHfRmDCYsjhDmVnO2lMbtSOteQm3jQUeSFu6g,21605
209
211
  strawberry/types/fields/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
210
212
  strawberry/types/fields/resolver.py,sha256=b6lxfw6AMOUFWm7vs7a9KzNkpR8b_S110DoIosrrWDQ,14679
@@ -234,8 +236,8 @@ strawberry/utils/logging.py,sha256=U1cseHGquN09YFhFmRkiphfASKCyK0HUZREImPgVb0c,7
234
236
  strawberry/utils/operation.py,sha256=ZgVOw3K2jQuLjNOYUHauF7itJD0QDNoPw9PBi0IYf6k,1234
235
237
  strawberry/utils/str_converters.py,sha256=-eH1Cl16IO_wrBlsGM-km4IY0IKsjhjnSNGRGOwQjVM,897
236
238
  strawberry/utils/typing.py,sha256=SDvX-Du-9HAV3-XXjqi7Q5f5qPDDFd_gASIITiwBQT4,14073
237
- strawberry_graphql-0.276.1.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
238
- strawberry_graphql-0.276.1.dist-info/METADATA,sha256=zuUBSbNn5fSZbEJCLzZiEOUou-FA16hqmJQSiAE5ywI,7393
239
- strawberry_graphql-0.276.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
240
- strawberry_graphql-0.276.1.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
241
- strawberry_graphql-0.276.1.dist-info/RECORD,,
239
+ strawberry_graphql-0.277.0.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
240
+ strawberry_graphql-0.277.0.dist-info/METADATA,sha256=JPt-IK9XsRJrGkO3N4EtmnHqo5HO_ctGLdEYVW8nKlU,7393
241
+ strawberry_graphql-0.277.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
242
+ strawberry_graphql-0.277.0.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
243
+ strawberry_graphql-0.277.0.dist-info/RECORD,,