strawberry-graphql 0.258.1__py3-none-any.whl → 0.259.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/extensions/parser_cache.py +3 -2
- strawberry/extensions/validation_cache.py +2 -1
- strawberry/schema/schema.py +379 -23
- {strawberry_graphql-0.258.1.dist-info → strawberry_graphql-0.259.0.dist-info}/METADATA +1 -1
- {strawberry_graphql-0.258.1.dist-info → strawberry_graphql-0.259.0.dist-info}/RECORD +8 -10
- strawberry/schema/execute.py +0 -303
- strawberry/schema/subscribe.py +0 -155
- {strawberry_graphql-0.258.1.dist-info → strawberry_graphql-0.259.0.dist-info}/LICENSE +0 -0
- {strawberry_graphql-0.258.1.dist-info → strawberry_graphql-0.259.0.dist-info}/WHEEL +0 -0
- {strawberry_graphql-0.258.1.dist-info → strawberry_graphql-0.259.0.dist-info}/entry_points.txt +0 -0
@@ -2,8 +2,9 @@ from collections.abc import Iterator
|
|
2
2
|
from functools import lru_cache
|
3
3
|
from typing import Optional
|
4
4
|
|
5
|
+
from graphql.language.parser import parse
|
6
|
+
|
5
7
|
from strawberry.extensions.base_extension import SchemaExtension
|
6
|
-
from strawberry.schema.execute import parse_document
|
7
8
|
|
8
9
|
|
9
10
|
class ParserCache(SchemaExtension):
|
@@ -32,7 +33,7 @@ class ParserCache(SchemaExtension):
|
|
32
33
|
cache will grow without bound.
|
33
34
|
More info: https://docs.python.org/3/library/functools.html#functools.lru_cache
|
34
35
|
"""
|
35
|
-
self.cached_parse_document = lru_cache(maxsize=maxsize)(
|
36
|
+
self.cached_parse_document = lru_cache(maxsize=maxsize)(parse)
|
36
37
|
|
37
38
|
def on_parse(self) -> Iterator[None]:
|
38
39
|
execution_context = self.execution_context
|
@@ -3,7 +3,6 @@ from functools import lru_cache
|
|
3
3
|
from typing import Optional
|
4
4
|
|
5
5
|
from strawberry.extensions.base_extension import SchemaExtension
|
6
|
-
from strawberry.schema.execute import validate_document
|
7
6
|
|
8
7
|
|
9
8
|
class ValidationCache(SchemaExtension):
|
@@ -32,6 +31,8 @@ class ValidationCache(SchemaExtension):
|
|
32
31
|
|
33
32
|
More info: https://docs.python.org/3/library/functools.html#functools.lru_cache
|
34
33
|
"""
|
34
|
+
from strawberry.schema.schema import validate_document
|
35
|
+
|
35
36
|
self.cached_validate_document = lru_cache(maxsize=maxsize)(validate_document)
|
36
37
|
|
37
38
|
def on_validate(self) -> Iterator[None]:
|
strawberry/schema/schema.py
CHANGED
@@ -1,29 +1,43 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import warnings
|
4
|
+
from asyncio import ensure_future
|
5
|
+
from collections.abc import AsyncGenerator, AsyncIterator, Awaitable, Iterable
|
4
6
|
from functools import cached_property, lru_cache
|
7
|
+
from inspect import isawaitable
|
5
8
|
from typing import (
|
6
9
|
TYPE_CHECKING,
|
7
10
|
Any,
|
11
|
+
Callable,
|
8
12
|
Optional,
|
9
13
|
Union,
|
10
14
|
cast,
|
11
15
|
)
|
12
16
|
|
17
|
+
from graphql import ExecutionResult as GraphQLExecutionResult
|
18
|
+
from graphql import (
|
19
|
+
ExecutionResult as OriginalExecutionResult,
|
20
|
+
)
|
13
21
|
from graphql import (
|
14
22
|
GraphQLBoolean,
|
23
|
+
GraphQLError,
|
15
24
|
GraphQLField,
|
16
25
|
GraphQLNamedType,
|
17
26
|
GraphQLNonNull,
|
18
27
|
GraphQLSchema,
|
19
28
|
get_introspection_query,
|
29
|
+
parse,
|
20
30
|
validate_schema,
|
21
31
|
)
|
32
|
+
from graphql.execution import ExecutionContext as GraphQLExecutionContext
|
33
|
+
from graphql.execution import execute, subscribe
|
22
34
|
from graphql.execution.middleware import MiddlewareManager
|
23
35
|
from graphql.type.directives import specified_directives
|
36
|
+
from graphql.validation import validate
|
24
37
|
|
25
38
|
from strawberry import relay
|
26
39
|
from strawberry.annotation import StrawberryAnnotation
|
40
|
+
from strawberry.exceptions import MissingQueryError
|
27
41
|
from strawberry.extensions import SchemaExtension
|
28
42
|
from strawberry.extensions.directives import (
|
29
43
|
DirectivesExtension,
|
@@ -33,38 +47,93 @@ from strawberry.extensions.runner import SchemaExtensionsRunner
|
|
33
47
|
from strawberry.printer import print_schema
|
34
48
|
from strawberry.schema.schema_converter import GraphQLCoreConverter
|
35
49
|
from strawberry.schema.types.scalar import DEFAULT_SCALAR_REGISTRY
|
36
|
-
from strawberry.
|
50
|
+
from strawberry.schema.validation_rules.one_of import OneOfInputValidationRule
|
37
51
|
from strawberry.types.base import (
|
38
52
|
StrawberryObjectDefinition,
|
39
53
|
WithStrawberryObjectDefinition,
|
40
54
|
has_object_definition,
|
41
55
|
)
|
56
|
+
from strawberry.types.execution import (
|
57
|
+
ExecutionContext,
|
58
|
+
ExecutionResult,
|
59
|
+
PreExecutionError,
|
60
|
+
)
|
42
61
|
from strawberry.types.graphql import OperationType
|
62
|
+
from strawberry.utils import IS_GQL_32
|
63
|
+
from strawberry.utils.await_maybe import await_maybe
|
43
64
|
|
44
65
|
from . import compat
|
45
66
|
from .base import BaseSchema
|
46
67
|
from .config import StrawberryConfig
|
47
|
-
from .
|
48
|
-
from .subscribe import SubscriptionResult, subscribe
|
68
|
+
from .exceptions import InvalidOperationTypeError
|
49
69
|
|
50
70
|
if TYPE_CHECKING:
|
51
71
|
from collections.abc import Iterable
|
72
|
+
from typing_extensions import TypeAlias
|
52
73
|
|
53
74
|
from graphql import ExecutionContext as GraphQLExecutionContext
|
75
|
+
from graphql.language import DocumentNode
|
76
|
+
from graphql.validation import ASTValidationRule
|
54
77
|
|
55
78
|
from strawberry.directive import StrawberryDirective
|
56
|
-
from strawberry.types import ExecutionResult
|
57
79
|
from strawberry.types.base import StrawberryType
|
58
80
|
from strawberry.types.enum import EnumDefinition
|
59
81
|
from strawberry.types.field import StrawberryField
|
60
82
|
from strawberry.types.scalar import ScalarDefinition, ScalarWrapper
|
61
83
|
from strawberry.types.union import StrawberryUnion
|
62
84
|
|
85
|
+
SubscriptionResult: TypeAlias = Union[
|
86
|
+
PreExecutionError, AsyncGenerator[ExecutionResult, None]
|
87
|
+
]
|
88
|
+
|
89
|
+
OriginSubscriptionResult = Union[
|
90
|
+
OriginalExecutionResult,
|
91
|
+
AsyncIterator[OriginalExecutionResult],
|
92
|
+
]
|
93
|
+
|
63
94
|
DEFAULT_ALLOWED_OPERATION_TYPES = {
|
64
95
|
OperationType.QUERY,
|
65
96
|
OperationType.MUTATION,
|
66
97
|
OperationType.SUBSCRIPTION,
|
67
98
|
}
|
99
|
+
ProcessErrors: TypeAlias = (
|
100
|
+
"Callable[[list[GraphQLError], Optional[ExecutionContext]], None]"
|
101
|
+
)
|
102
|
+
|
103
|
+
|
104
|
+
# TODO: merge with below
|
105
|
+
def validate_document(
|
106
|
+
schema: GraphQLSchema,
|
107
|
+
document: DocumentNode,
|
108
|
+
validation_rules: tuple[type[ASTValidationRule], ...],
|
109
|
+
) -> list[GraphQLError]:
|
110
|
+
validation_rules = (
|
111
|
+
*validation_rules,
|
112
|
+
OneOfInputValidationRule,
|
113
|
+
)
|
114
|
+
return validate(
|
115
|
+
schema,
|
116
|
+
document,
|
117
|
+
validation_rules,
|
118
|
+
)
|
119
|
+
|
120
|
+
|
121
|
+
def _run_validation(execution_context: ExecutionContext) -> None:
|
122
|
+
# Check if there are any validation rules or if validation has
|
123
|
+
# already been run by an extension
|
124
|
+
if len(execution_context.validation_rules) > 0 and execution_context.errors is None:
|
125
|
+
assert execution_context.graphql_document
|
126
|
+
execution_context.errors = validate_document(
|
127
|
+
execution_context.schema._schema,
|
128
|
+
execution_context.graphql_document,
|
129
|
+
execution_context.validation_rules,
|
130
|
+
)
|
131
|
+
|
132
|
+
|
133
|
+
def _coerce_error(error: Union[GraphQLError, Exception]) -> GraphQLError:
|
134
|
+
if isinstance(error, GraphQLError):
|
135
|
+
return error
|
136
|
+
return GraphQLError(str(error), original_error=error)
|
68
137
|
|
69
138
|
|
70
139
|
class Schema(BaseSchema):
|
@@ -337,6 +406,60 @@ class Schema(BaseSchema):
|
|
337
406
|
) -> list[StrawberryField]:
|
338
407
|
return type_definition.fields
|
339
408
|
|
409
|
+
async def _parse_and_validate_async(
|
410
|
+
self, context: ExecutionContext, extensions_runner: SchemaExtensionsRunner
|
411
|
+
) -> Optional[PreExecutionError]:
|
412
|
+
if not context.query:
|
413
|
+
raise MissingQueryError
|
414
|
+
|
415
|
+
async with extensions_runner.parsing():
|
416
|
+
try:
|
417
|
+
if not context.graphql_document:
|
418
|
+
context.graphql_document = parse(context.query)
|
419
|
+
|
420
|
+
except GraphQLError as error:
|
421
|
+
context.errors = [error]
|
422
|
+
return PreExecutionError(data=None, errors=[error])
|
423
|
+
|
424
|
+
except Exception as error: # noqa: BLE001
|
425
|
+
error = GraphQLError(str(error), original_error=error)
|
426
|
+
context.errors = [error]
|
427
|
+
return PreExecutionError(data=None, errors=[error])
|
428
|
+
|
429
|
+
if context.operation_type not in context.allowed_operations:
|
430
|
+
raise InvalidOperationTypeError(context.operation_type)
|
431
|
+
|
432
|
+
async with extensions_runner.validation():
|
433
|
+
_run_validation(context)
|
434
|
+
if context.errors:
|
435
|
+
return PreExecutionError(
|
436
|
+
data=None,
|
437
|
+
errors=context.errors,
|
438
|
+
)
|
439
|
+
|
440
|
+
return None
|
441
|
+
|
442
|
+
async def _handle_execution_result(
|
443
|
+
self,
|
444
|
+
context: ExecutionContext,
|
445
|
+
result: Union[GraphQLExecutionResult, ExecutionResult],
|
446
|
+
extensions_runner: SchemaExtensionsRunner,
|
447
|
+
*,
|
448
|
+
# TODO: can we remove this somehow, see comment in execute
|
449
|
+
skip_process_errors: bool = False,
|
450
|
+
) -> ExecutionResult:
|
451
|
+
# Set errors on the context so that it's easier
|
452
|
+
# to access in extensions
|
453
|
+
if result.errors:
|
454
|
+
context.errors = result.errors
|
455
|
+
if not skip_process_errors:
|
456
|
+
self._process_errors(result.errors, context)
|
457
|
+
if isinstance(result, GraphQLExecutionResult):
|
458
|
+
result = ExecutionResult(data=result.data, errors=result.errors)
|
459
|
+
result.extensions = await extensions_runner.get_extensions_results(context)
|
460
|
+
context.result = result # type: ignore # mypy failed to deduce correct type.
|
461
|
+
return result
|
462
|
+
|
340
463
|
async def execute(
|
341
464
|
self,
|
342
465
|
query: Optional[str],
|
@@ -361,15 +484,64 @@ class Schema(BaseSchema):
|
|
361
484
|
# TODO (#3571): remove this when we implement execution context as parameter.
|
362
485
|
for extension in extensions:
|
363
486
|
extension.execution_context = execution_context
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
)
|
370
|
-
|
371
|
-
|
372
|
-
|
487
|
+
|
488
|
+
extensions_runner = self.create_extensions_runner(execution_context, extensions)
|
489
|
+
middleware_manager = self._get_middleware_manager(extensions)
|
490
|
+
|
491
|
+
try:
|
492
|
+
async with extensions_runner.operation():
|
493
|
+
# Note: In graphql-core the schema would be validated here but in
|
494
|
+
# Strawberry we are validating it at initialisation time instead
|
495
|
+
|
496
|
+
if errors := await self._parse_and_validate_async(
|
497
|
+
execution_context, extensions_runner
|
498
|
+
):
|
499
|
+
return await self._handle_execution_result(
|
500
|
+
execution_context,
|
501
|
+
errors,
|
502
|
+
extensions_runner,
|
503
|
+
)
|
504
|
+
|
505
|
+
assert execution_context.graphql_document
|
506
|
+
async with extensions_runner.executing():
|
507
|
+
if not execution_context.result:
|
508
|
+
result = await await_maybe(
|
509
|
+
execute(
|
510
|
+
self._schema,
|
511
|
+
execution_context.graphql_document,
|
512
|
+
root_value=execution_context.root_value,
|
513
|
+
middleware=middleware_manager,
|
514
|
+
variable_values=execution_context.variables,
|
515
|
+
operation_name=execution_context.operation_name,
|
516
|
+
context_value=execution_context.context,
|
517
|
+
execution_context_class=self.execution_context_class,
|
518
|
+
)
|
519
|
+
)
|
520
|
+
execution_context.result = result
|
521
|
+
else:
|
522
|
+
result = execution_context.result
|
523
|
+
# Also set errors on the execution_context so that it's easier
|
524
|
+
# to access in extensions
|
525
|
+
if result.errors:
|
526
|
+
execution_context.errors = result.errors
|
527
|
+
|
528
|
+
# Run the `Schema.process_errors` function here before
|
529
|
+
# extensions have a chance to modify them (see the MaskErrors
|
530
|
+
# extension). That way we can log the original errors but
|
531
|
+
# only return a sanitised version to the client.
|
532
|
+
self._process_errors(result.errors, execution_context)
|
533
|
+
|
534
|
+
except (MissingQueryError, InvalidOperationTypeError):
|
535
|
+
raise
|
536
|
+
except Exception as exc: # noqa: BLE001
|
537
|
+
return await self._handle_execution_result(
|
538
|
+
execution_context,
|
539
|
+
PreExecutionError(data=None, errors=[_coerce_error(exc)]),
|
540
|
+
extensions_runner,
|
541
|
+
)
|
542
|
+
# return results after all the operation completed.
|
543
|
+
return await self._handle_execution_result(
|
544
|
+
execution_context, result, extensions_runner, skip_process_errors=True
|
373
545
|
)
|
374
546
|
|
375
547
|
def execute_sync(
|
@@ -396,18 +568,178 @@ class Schema(BaseSchema):
|
|
396
568
|
# TODO (#3571): remove this when we implement execution context as parameter.
|
397
569
|
for extension in extensions:
|
398
570
|
extension.execution_context = execution_context
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
)
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
571
|
+
|
572
|
+
extensions_runner = self.create_extensions_runner(execution_context, extensions)
|
573
|
+
middleware_manager = self._get_middleware_manager(extensions)
|
574
|
+
|
575
|
+
try:
|
576
|
+
with extensions_runner.operation():
|
577
|
+
# Note: In graphql-core the schema would be validated here but in
|
578
|
+
# Strawberry we are validating it at initialisation time instead
|
579
|
+
if not execution_context.query:
|
580
|
+
raise MissingQueryError # noqa: TRY301
|
581
|
+
|
582
|
+
with extensions_runner.parsing():
|
583
|
+
try:
|
584
|
+
if not execution_context.graphql_document:
|
585
|
+
execution_context.graphql_document = parse(
|
586
|
+
execution_context.query,
|
587
|
+
**execution_context.parse_options,
|
588
|
+
)
|
589
|
+
|
590
|
+
except GraphQLError as error:
|
591
|
+
execution_context.errors = [error]
|
592
|
+
self._process_errors([error], execution_context)
|
593
|
+
return ExecutionResult(
|
594
|
+
data=None,
|
595
|
+
errors=[error],
|
596
|
+
extensions=extensions_runner.get_extensions_results_sync(),
|
597
|
+
)
|
598
|
+
|
599
|
+
if execution_context.operation_type not in allowed_operation_types:
|
600
|
+
raise InvalidOperationTypeError(execution_context.operation_type) # noqa: TRY301
|
601
|
+
|
602
|
+
with extensions_runner.validation():
|
603
|
+
_run_validation(execution_context)
|
604
|
+
if execution_context.errors:
|
605
|
+
self._process_errors(
|
606
|
+
execution_context.errors, execution_context
|
607
|
+
)
|
608
|
+
return ExecutionResult(
|
609
|
+
data=None,
|
610
|
+
errors=execution_context.errors,
|
611
|
+
extensions=extensions_runner.get_extensions_results_sync(),
|
612
|
+
)
|
613
|
+
|
614
|
+
with extensions_runner.executing():
|
615
|
+
if not execution_context.result:
|
616
|
+
result = execute(
|
617
|
+
self._schema,
|
618
|
+
execution_context.graphql_document,
|
619
|
+
root_value=execution_context.root_value,
|
620
|
+
middleware=middleware_manager,
|
621
|
+
variable_values=execution_context.variables,
|
622
|
+
operation_name=execution_context.operation_name,
|
623
|
+
context_value=execution_context.context,
|
624
|
+
execution_context_class=self.execution_context_class,
|
625
|
+
)
|
626
|
+
|
627
|
+
if isawaitable(result):
|
628
|
+
result = cast(Awaitable[GraphQLExecutionResult], result) # type: ignore[redundant-cast]
|
629
|
+
ensure_future(result).cancel()
|
630
|
+
raise RuntimeError( # noqa: TRY301
|
631
|
+
"GraphQL execution failed to complete synchronously."
|
632
|
+
)
|
633
|
+
|
634
|
+
result = cast(GraphQLExecutionResult, result) # type: ignore[redundant-cast]
|
635
|
+
execution_context.result = result
|
636
|
+
# Also set errors on the context so that it's easier
|
637
|
+
# to access in extensions
|
638
|
+
if result.errors:
|
639
|
+
execution_context.errors = result.errors
|
640
|
+
|
641
|
+
# Run the `Schema.process_errors` function here before
|
642
|
+
# extensions have a chance to modify them (see the MaskErrors
|
643
|
+
# extension). That way we can log the original errors but
|
644
|
+
# only return a sanitised version to the client.
|
645
|
+
self._process_errors(result.errors, execution_context)
|
646
|
+
except (MissingQueryError, InvalidOperationTypeError):
|
647
|
+
raise
|
648
|
+
except Exception as exc: # noqa: BLE001
|
649
|
+
errors = [_coerce_error(exc)]
|
650
|
+
execution_context.errors = errors
|
651
|
+
self._process_errors(errors, execution_context)
|
652
|
+
return ExecutionResult(
|
653
|
+
data=None,
|
654
|
+
errors=errors,
|
655
|
+
extensions=extensions_runner.get_extensions_results_sync(),
|
656
|
+
)
|
657
|
+
return ExecutionResult(
|
658
|
+
data=execution_context.result.data,
|
659
|
+
errors=execution_context.result.errors,
|
660
|
+
extensions=extensions_runner.get_extensions_results_sync(),
|
409
661
|
)
|
410
662
|
|
663
|
+
async def _subscribe(
|
664
|
+
self,
|
665
|
+
execution_context: ExecutionContext,
|
666
|
+
extensions_runner: SchemaExtensionsRunner,
|
667
|
+
middleware_manager: MiddlewareManager,
|
668
|
+
execution_context_class: type[GraphQLExecutionContext] | None = None,
|
669
|
+
) -> AsyncGenerator[ExecutionResult, None]:
|
670
|
+
async with extensions_runner.operation():
|
671
|
+
if initial_error := await self._parse_and_validate_async(
|
672
|
+
context=execution_context,
|
673
|
+
extensions_runner=extensions_runner,
|
674
|
+
):
|
675
|
+
initial_error.extensions = (
|
676
|
+
await extensions_runner.get_extensions_results(execution_context)
|
677
|
+
)
|
678
|
+
yield await self._handle_execution_result(
|
679
|
+
execution_context, initial_error, extensions_runner
|
680
|
+
)
|
681
|
+
try:
|
682
|
+
async with extensions_runner.executing():
|
683
|
+
assert execution_context.graphql_document is not None
|
684
|
+
gql_33_kwargs = {
|
685
|
+
"middleware": middleware_manager,
|
686
|
+
"execution_context_class": execution_context_class,
|
687
|
+
}
|
688
|
+
try:
|
689
|
+
# Might not be awaitable for pre-execution errors.
|
690
|
+
aiter_or_result: OriginSubscriptionResult = await await_maybe(
|
691
|
+
subscribe(
|
692
|
+
self._schema,
|
693
|
+
execution_context.graphql_document,
|
694
|
+
root_value=execution_context.root_value,
|
695
|
+
variable_values=execution_context.variables,
|
696
|
+
operation_name=execution_context.operation_name,
|
697
|
+
context_value=execution_context.context,
|
698
|
+
**{} if IS_GQL_32 else gql_33_kwargs, # type: ignore[arg-type]
|
699
|
+
)
|
700
|
+
)
|
701
|
+
# graphql-core 3.2 doesn't handle some of the pre-execution errors.
|
702
|
+
# see `test_subscription_immediate_error`
|
703
|
+
except Exception as exc: # noqa: BLE001
|
704
|
+
aiter_or_result = OriginalExecutionResult(
|
705
|
+
data=None, errors=[_coerce_error(exc)]
|
706
|
+
)
|
707
|
+
|
708
|
+
# Handle pre-execution errors.
|
709
|
+
if isinstance(aiter_or_result, OriginalExecutionResult):
|
710
|
+
yield await self._handle_execution_result(
|
711
|
+
execution_context,
|
712
|
+
PreExecutionError(data=None, errors=aiter_or_result.errors),
|
713
|
+
extensions_runner,
|
714
|
+
)
|
715
|
+
else:
|
716
|
+
try:
|
717
|
+
async for result in aiter_or_result:
|
718
|
+
yield await self._handle_execution_result(
|
719
|
+
execution_context,
|
720
|
+
result,
|
721
|
+
extensions_runner,
|
722
|
+
)
|
723
|
+
# graphql-core doesn't handle exceptions raised while executing.
|
724
|
+
except Exception as exc: # noqa: BLE001
|
725
|
+
yield await self._handle_execution_result(
|
726
|
+
execution_context,
|
727
|
+
OriginalExecutionResult(
|
728
|
+
data=None, errors=[_coerce_error(exc)]
|
729
|
+
),
|
730
|
+
extensions_runner,
|
731
|
+
)
|
732
|
+
# catch exceptions raised in `on_execute` hook.
|
733
|
+
except Exception as exc: # noqa: BLE001
|
734
|
+
origin_result = OriginalExecutionResult(
|
735
|
+
data=None, errors=[_coerce_error(exc)]
|
736
|
+
)
|
737
|
+
yield await self._handle_execution_result(
|
738
|
+
execution_context,
|
739
|
+
origin_result,
|
740
|
+
extensions_runner,
|
741
|
+
)
|
742
|
+
|
411
743
|
async def subscribe(
|
412
744
|
self,
|
413
745
|
query: Optional[str],
|
@@ -428,6 +760,30 @@ class Schema(BaseSchema):
|
|
428
760
|
# TODO (#3571): remove this when we implement execution context as parameter.
|
429
761
|
for extension in extensions:
|
430
762
|
extension.execution_context = execution_context
|
763
|
+
|
764
|
+
asyncgen = self._subscribe(
|
765
|
+
execution_context,
|
766
|
+
extensions_runner=self.create_extensions_runner(
|
767
|
+
execution_context, extensions
|
768
|
+
),
|
769
|
+
middleware_manager=self._get_middleware_manager(extensions),
|
770
|
+
execution_context_class=self.execution_context_class,
|
771
|
+
)
|
772
|
+
# GraphQL-core might return an initial error result instead of an async iterator.
|
773
|
+
# This happens when "there was an immediate error" i.e resolver is not an async iterator.
|
774
|
+
# To overcome this while maintaining the extension contexts we do this trick.
|
775
|
+
first = await asyncgen.__anext__()
|
776
|
+
if isinstance(first, PreExecutionError):
|
777
|
+
await asyncgen.aclose()
|
778
|
+
return first
|
779
|
+
|
780
|
+
async def _wrapper() -> AsyncGenerator[ExecutionResult, None]:
|
781
|
+
yield first
|
782
|
+
async for result in asyncgen:
|
783
|
+
yield result
|
784
|
+
|
785
|
+
return _wrapper()
|
786
|
+
|
431
787
|
return await subscribe(
|
432
788
|
self._schema,
|
433
789
|
execution_context=execution_context,
|
@@ -97,7 +97,7 @@ strawberry/extensions/field_extension.py,sha256=VUwUBbf57Vp_Ukc3Rh9eZDRuF2ubzRRi
|
|
97
97
|
strawberry/extensions/mask_errors.py,sha256=xPGN24l6C_zZ174jHQbOhSShTqqAB58ithhuTZjBXGQ,1481
|
98
98
|
strawberry/extensions/max_aliases.py,sha256=qaV9rqHTqfhh7YdFnXVvjf14wmAiXBtKHGAxb1Yv4DQ,2547
|
99
99
|
strawberry/extensions/max_tokens.py,sha256=53Gb0tSj-G7so_vLokdmtUal4KCXQBYLJi1LSIvdkXE,1045
|
100
|
-
strawberry/extensions/parser_cache.py,sha256=
|
100
|
+
strawberry/extensions/parser_cache.py,sha256=oi6Svpy21_YP-d9G3nv_5HzJPw5FyBhWplCYnzcKwO8,1291
|
101
101
|
strawberry/extensions/pyinstrument.py,sha256=c5qmVQMmvA2Wtivvlgkvx1C2EMexoG-XFxMenaItGYU,753
|
102
102
|
strawberry/extensions/query_depth_limiter.py,sha256=qhVLfZTpp1gpx4O6Qe6bpNBWO7tI39vcH3FLbkpdosk,9727
|
103
103
|
strawberry/extensions/runner.py,sha256=LCUSzKUrwTYhoIr1nS8uFDN15_YEQ_3BFK1zpPfOfsA,1873
|
@@ -107,7 +107,7 @@ strawberry/extensions/tracing/datadog.py,sha256=9hICpmLWKj7dWNRECGHc3TVX69SI9arb
|
|
107
107
|
strawberry/extensions/tracing/opentelemetry.py,sha256=4czsWhJnwXbFii3vs4kqKD7r0iOakvnlGr2dlsQ7OwI,7207
|
108
108
|
strawberry/extensions/tracing/utils.py,sha256=tXZNyqfct6YNSWi3GRj4GU1fKQGvSce8ZESfoVeys7U,654
|
109
109
|
strawberry/extensions/utils.py,sha256=sjhxItHzbDhqHtnR63WbE35qzHhTyf9NSffidet79Hc,995
|
110
|
-
strawberry/extensions/validation_cache.py,sha256=
|
110
|
+
strawberry/extensions/validation_cache.py,sha256=D4Jyj7WoUkgp_UH6bo9ytRZbPwJnencbti5Z1GszGhM,1433
|
111
111
|
strawberry/fastapi/__init__.py,sha256=p5qg9AlkYjNOWKcT4uRiebIpR6pIb1HqDMiDfF5O3tg,147
|
112
112
|
strawberry/fastapi/context.py,sha256=O_cDNppfUJJecM0ZU_RJ-dhdF0o1x39JfYvYg-7uob4,684
|
113
113
|
strawberry/fastapi/router.py,sha256=cgcZBqmb3srRChr0QM6tz7f3tP57x7vOVPz7iH2M8pk,11957
|
@@ -166,11 +166,9 @@ strawberry/schema/base.py,sha256=CxVxEDk2U3aaOuABEkGhqNyFDs_xf2FF60yfnGT144g,385
|
|
166
166
|
strawberry/schema/compat.py,sha256=9qJ0lhYJeaN43ayFgVz708ZMvedBhofiTSw9kpFqmjU,1830
|
167
167
|
strawberry/schema/config.py,sha256=6BpCbNNCuekGgiKEPt2mliMqLH_wIjJmSW0tLbnJwk4,924
|
168
168
|
strawberry/schema/exceptions.py,sha256=rqVNb_oYrKM0dHPgvAemqCG6Um282LPPu4zwQ5cZqs4,584
|
169
|
-
strawberry/schema/execute.py,sha256=JgjtMCSCOuvHqAqI-dwmMV7bzpNEpiB9hVWTPS-GrFo,11979
|
170
169
|
strawberry/schema/name_converter.py,sha256=1rrpch-wBidlWfZ7hVouvIIhJpdxWfB5tWnO6PqYug8,6544
|
171
|
-
strawberry/schema/schema.py,sha256=
|
170
|
+
strawberry/schema/schema.py,sha256=Co4vJ7dsSvtXuAy9AO1OquEGTDjDoBPN4AhYJl07bIo,35431
|
172
171
|
strawberry/schema/schema_converter.py,sha256=-_QZCcmHWIEjRPqEChtPMPbFtgz6YmLn8V6KXvZJMOk,37192
|
173
|
-
strawberry/schema/subscribe.py,sha256=UPXkmfudZjkf-quCZ6ZixPqrPz9wQDhHBChbjjYFJeY,6086
|
174
172
|
strawberry/schema/types/__init__.py,sha256=oHO3COWhL3L1KLYCJNY1XFf5xt2GGtHiMC-UaYbFfnA,68
|
175
173
|
strawberry/schema/types/base_scalars.py,sha256=JRUq0WjEkR9dFewstZnqnZKp0uOEipo4UXNF5dzRf4M,1971
|
176
174
|
strawberry/schema/types/concrete_type.py,sha256=axIyFZgdwNv-XYkiqX67464wuFX6Vp0jYATwnBZSUvM,750
|
@@ -230,8 +228,8 @@ strawberry/utils/logging.py,sha256=U1cseHGquN09YFhFmRkiphfASKCyK0HUZREImPgVb0c,7
|
|
230
228
|
strawberry/utils/operation.py,sha256=SSXxN-vMqdHO6W2OZtip-1z7y4_A-eTVFdhDvhKeLCk,1193
|
231
229
|
strawberry/utils/str_converters.py,sha256=-eH1Cl16IO_wrBlsGM-km4IY0IKsjhjnSNGRGOwQjVM,897
|
232
230
|
strawberry/utils/typing.py,sha256=Ux0Hl46lhuXvOKK-C5hj6nlz3zDn8P4CUGH2nUVD2vU,13373
|
233
|
-
strawberry_graphql-0.
|
234
|
-
strawberry_graphql-0.
|
235
|
-
strawberry_graphql-0.
|
236
|
-
strawberry_graphql-0.
|
237
|
-
strawberry_graphql-0.
|
231
|
+
strawberry_graphql-0.259.0.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
|
232
|
+
strawberry_graphql-0.259.0.dist-info/METADATA,sha256=mH3HSrnOeJWwtq5hQ0kkfJEy21W9V9nQTmm9rpSqEBU,7539
|
233
|
+
strawberry_graphql-0.259.0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
234
|
+
strawberry_graphql-0.259.0.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
|
235
|
+
strawberry_graphql-0.259.0.dist-info/RECORD,,
|
strawberry/schema/execute.py
DELETED
@@ -1,303 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from asyncio import ensure_future
|
4
|
-
from collections.abc import Awaitable, Iterable
|
5
|
-
from inspect import isawaitable
|
6
|
-
from typing import (
|
7
|
-
TYPE_CHECKING,
|
8
|
-
Callable,
|
9
|
-
Optional,
|
10
|
-
TypedDict,
|
11
|
-
Union,
|
12
|
-
cast,
|
13
|
-
)
|
14
|
-
|
15
|
-
from graphql import ExecutionResult as GraphQLExecutionResult
|
16
|
-
from graphql import GraphQLError, parse
|
17
|
-
from graphql import execute as original_execute
|
18
|
-
from graphql.validation import validate
|
19
|
-
|
20
|
-
from strawberry.exceptions import MissingQueryError
|
21
|
-
from strawberry.schema.validation_rules.one_of import OneOfInputValidationRule
|
22
|
-
from strawberry.types import ExecutionResult
|
23
|
-
from strawberry.types.execution import PreExecutionError
|
24
|
-
from strawberry.utils.await_maybe import await_maybe
|
25
|
-
|
26
|
-
from .exceptions import InvalidOperationTypeError
|
27
|
-
|
28
|
-
if TYPE_CHECKING:
|
29
|
-
from typing_extensions import NotRequired, TypeAlias, Unpack
|
30
|
-
|
31
|
-
from graphql import ExecutionContext as GraphQLExecutionContext
|
32
|
-
from graphql import GraphQLSchema
|
33
|
-
from graphql.execution.middleware import MiddlewareManager
|
34
|
-
from graphql.language import DocumentNode
|
35
|
-
from graphql.validation import ASTValidationRule
|
36
|
-
|
37
|
-
from strawberry.extensions.runner import SchemaExtensionsRunner
|
38
|
-
from strawberry.types import ExecutionContext
|
39
|
-
from strawberry.types.graphql import OperationType
|
40
|
-
|
41
|
-
|
42
|
-
# duplicated because of https://github.com/mkdocstrings/griffe-typingdoc/issues/7
|
43
|
-
class ParseOptions(TypedDict):
|
44
|
-
max_tokens: NotRequired[int]
|
45
|
-
|
46
|
-
|
47
|
-
ProcessErrors: TypeAlias = (
|
48
|
-
"Callable[[list[GraphQLError], Optional[ExecutionContext]], None]"
|
49
|
-
)
|
50
|
-
|
51
|
-
|
52
|
-
def parse_document(query: str, **kwargs: Unpack[ParseOptions]) -> DocumentNode:
|
53
|
-
return parse(query, **kwargs)
|
54
|
-
|
55
|
-
|
56
|
-
def validate_document(
|
57
|
-
schema: GraphQLSchema,
|
58
|
-
document: DocumentNode,
|
59
|
-
validation_rules: tuple[type[ASTValidationRule], ...],
|
60
|
-
) -> list[GraphQLError]:
|
61
|
-
validation_rules = (
|
62
|
-
*validation_rules,
|
63
|
-
OneOfInputValidationRule,
|
64
|
-
)
|
65
|
-
return validate(
|
66
|
-
schema,
|
67
|
-
document,
|
68
|
-
validation_rules,
|
69
|
-
)
|
70
|
-
|
71
|
-
|
72
|
-
def _run_validation(execution_context: ExecutionContext) -> None:
|
73
|
-
# Check if there are any validation rules or if validation has
|
74
|
-
# already been run by an extension
|
75
|
-
if len(execution_context.validation_rules) > 0 and execution_context.errors is None:
|
76
|
-
assert execution_context.graphql_document
|
77
|
-
execution_context.errors = validate_document(
|
78
|
-
execution_context.schema._schema,
|
79
|
-
execution_context.graphql_document,
|
80
|
-
execution_context.validation_rules,
|
81
|
-
)
|
82
|
-
|
83
|
-
|
84
|
-
async def _parse_and_validate_async(
|
85
|
-
context: ExecutionContext, extensions_runner: SchemaExtensionsRunner
|
86
|
-
) -> Optional[PreExecutionError]:
|
87
|
-
if not context.query:
|
88
|
-
raise MissingQueryError
|
89
|
-
|
90
|
-
async with extensions_runner.parsing():
|
91
|
-
try:
|
92
|
-
if not context.graphql_document:
|
93
|
-
context.graphql_document = parse_document(context.query)
|
94
|
-
|
95
|
-
except GraphQLError as error:
|
96
|
-
context.errors = [error]
|
97
|
-
return PreExecutionError(data=None, errors=[error])
|
98
|
-
|
99
|
-
except Exception as error: # noqa: BLE001
|
100
|
-
error = GraphQLError(str(error), original_error=error)
|
101
|
-
context.errors = [error]
|
102
|
-
return PreExecutionError(data=None, errors=[error])
|
103
|
-
|
104
|
-
if context.operation_type not in context.allowed_operations:
|
105
|
-
raise InvalidOperationTypeError(context.operation_type)
|
106
|
-
|
107
|
-
async with extensions_runner.validation():
|
108
|
-
_run_validation(context)
|
109
|
-
if context.errors:
|
110
|
-
return PreExecutionError(
|
111
|
-
data=None,
|
112
|
-
errors=context.errors,
|
113
|
-
)
|
114
|
-
|
115
|
-
return None
|
116
|
-
|
117
|
-
|
118
|
-
async def _handle_execution_result(
|
119
|
-
context: ExecutionContext,
|
120
|
-
result: Union[GraphQLExecutionResult, ExecutionResult],
|
121
|
-
extensions_runner: SchemaExtensionsRunner,
|
122
|
-
process_errors: ProcessErrors | None,
|
123
|
-
) -> ExecutionResult:
|
124
|
-
# Set errors on the context so that it's easier
|
125
|
-
# to access in extensions
|
126
|
-
if result.errors:
|
127
|
-
context.errors = result.errors
|
128
|
-
if process_errors:
|
129
|
-
process_errors(result.errors, context)
|
130
|
-
if isinstance(result, GraphQLExecutionResult):
|
131
|
-
result = ExecutionResult(data=result.data, errors=result.errors)
|
132
|
-
result.extensions = await extensions_runner.get_extensions_results(context)
|
133
|
-
context.result = result # type: ignore # mypy failed to deduce correct type.
|
134
|
-
return result
|
135
|
-
|
136
|
-
|
137
|
-
def _coerce_error(error: Union[GraphQLError, Exception]) -> GraphQLError:
|
138
|
-
if isinstance(error, GraphQLError):
|
139
|
-
return error
|
140
|
-
return GraphQLError(str(error), original_error=error)
|
141
|
-
|
142
|
-
|
143
|
-
async def execute(
|
144
|
-
schema: GraphQLSchema,
|
145
|
-
execution_context: ExecutionContext,
|
146
|
-
extensions_runner: SchemaExtensionsRunner,
|
147
|
-
process_errors: ProcessErrors,
|
148
|
-
middleware_manager: MiddlewareManager,
|
149
|
-
execution_context_class: Optional[type[GraphQLExecutionContext]] = None,
|
150
|
-
) -> ExecutionResult | PreExecutionError:
|
151
|
-
try:
|
152
|
-
async with extensions_runner.operation():
|
153
|
-
# Note: In graphql-core the schema would be validated here but in
|
154
|
-
# Strawberry we are validating it at initialisation time instead
|
155
|
-
|
156
|
-
if errors := await _parse_and_validate_async(
|
157
|
-
execution_context, extensions_runner
|
158
|
-
):
|
159
|
-
return await _handle_execution_result(
|
160
|
-
execution_context, errors, extensions_runner, process_errors
|
161
|
-
)
|
162
|
-
|
163
|
-
assert execution_context.graphql_document
|
164
|
-
async with extensions_runner.executing():
|
165
|
-
if not execution_context.result:
|
166
|
-
result = await await_maybe(
|
167
|
-
original_execute(
|
168
|
-
schema,
|
169
|
-
execution_context.graphql_document,
|
170
|
-
root_value=execution_context.root_value,
|
171
|
-
middleware=middleware_manager,
|
172
|
-
variable_values=execution_context.variables,
|
173
|
-
operation_name=execution_context.operation_name,
|
174
|
-
context_value=execution_context.context,
|
175
|
-
execution_context_class=execution_context_class,
|
176
|
-
)
|
177
|
-
)
|
178
|
-
execution_context.result = result
|
179
|
-
else:
|
180
|
-
result = execution_context.result
|
181
|
-
# Also set errors on the execution_context so that it's easier
|
182
|
-
# to access in extensions
|
183
|
-
if result.errors:
|
184
|
-
execution_context.errors = result.errors
|
185
|
-
|
186
|
-
# Run the `Schema.process_errors` function here before
|
187
|
-
# extensions have a chance to modify them (see the MaskErrors
|
188
|
-
# extension). That way we can log the original errors but
|
189
|
-
# only return a sanitised version to the client.
|
190
|
-
process_errors(result.errors, execution_context)
|
191
|
-
|
192
|
-
except (MissingQueryError, InvalidOperationTypeError):
|
193
|
-
raise
|
194
|
-
except Exception as exc: # noqa: BLE001
|
195
|
-
return await _handle_execution_result(
|
196
|
-
execution_context,
|
197
|
-
PreExecutionError(data=None, errors=[_coerce_error(exc)]),
|
198
|
-
extensions_runner,
|
199
|
-
process_errors,
|
200
|
-
)
|
201
|
-
# return results after all the operation completed.
|
202
|
-
return await _handle_execution_result(
|
203
|
-
execution_context, result, extensions_runner, None
|
204
|
-
)
|
205
|
-
|
206
|
-
|
207
|
-
def execute_sync(
|
208
|
-
schema: GraphQLSchema,
|
209
|
-
*,
|
210
|
-
allowed_operation_types: Iterable[OperationType],
|
211
|
-
extensions_runner: SchemaExtensionsRunner,
|
212
|
-
execution_context: ExecutionContext,
|
213
|
-
execution_context_class: Optional[type[GraphQLExecutionContext]] = None,
|
214
|
-
process_errors: ProcessErrors,
|
215
|
-
middleware_manager: MiddlewareManager,
|
216
|
-
) -> ExecutionResult:
|
217
|
-
try:
|
218
|
-
with extensions_runner.operation():
|
219
|
-
# Note: In graphql-core the schema would be validated here but in
|
220
|
-
# Strawberry we are validating it at initialisation time instead
|
221
|
-
if not execution_context.query:
|
222
|
-
raise MissingQueryError # noqa: TRY301
|
223
|
-
|
224
|
-
with extensions_runner.parsing():
|
225
|
-
try:
|
226
|
-
if not execution_context.graphql_document:
|
227
|
-
execution_context.graphql_document = parse_document(
|
228
|
-
execution_context.query, **execution_context.parse_options
|
229
|
-
)
|
230
|
-
|
231
|
-
except GraphQLError as error:
|
232
|
-
execution_context.errors = [error]
|
233
|
-
process_errors([error], execution_context)
|
234
|
-
return ExecutionResult(
|
235
|
-
data=None,
|
236
|
-
errors=[error],
|
237
|
-
extensions=extensions_runner.get_extensions_results_sync(),
|
238
|
-
)
|
239
|
-
|
240
|
-
if execution_context.operation_type not in allowed_operation_types:
|
241
|
-
raise InvalidOperationTypeError(execution_context.operation_type) # noqa: TRY301
|
242
|
-
|
243
|
-
with extensions_runner.validation():
|
244
|
-
_run_validation(execution_context)
|
245
|
-
if execution_context.errors:
|
246
|
-
process_errors(execution_context.errors, execution_context)
|
247
|
-
return ExecutionResult(
|
248
|
-
data=None,
|
249
|
-
errors=execution_context.errors,
|
250
|
-
extensions=extensions_runner.get_extensions_results_sync(),
|
251
|
-
)
|
252
|
-
|
253
|
-
with extensions_runner.executing():
|
254
|
-
if not execution_context.result:
|
255
|
-
result = original_execute(
|
256
|
-
schema,
|
257
|
-
execution_context.graphql_document,
|
258
|
-
root_value=execution_context.root_value,
|
259
|
-
middleware=middleware_manager,
|
260
|
-
variable_values=execution_context.variables,
|
261
|
-
operation_name=execution_context.operation_name,
|
262
|
-
context_value=execution_context.context,
|
263
|
-
execution_context_class=execution_context_class,
|
264
|
-
)
|
265
|
-
|
266
|
-
if isawaitable(result):
|
267
|
-
result = cast(Awaitable[GraphQLExecutionResult], result) # type: ignore[redundant-cast]
|
268
|
-
ensure_future(result).cancel()
|
269
|
-
raise RuntimeError( # noqa: TRY301
|
270
|
-
"GraphQL execution failed to complete synchronously."
|
271
|
-
)
|
272
|
-
|
273
|
-
result = cast(GraphQLExecutionResult, result) # type: ignore[redundant-cast]
|
274
|
-
execution_context.result = result
|
275
|
-
# Also set errors on the context so that it's easier
|
276
|
-
# to access in extensions
|
277
|
-
if result.errors:
|
278
|
-
execution_context.errors = result.errors
|
279
|
-
|
280
|
-
# Run the `Schema.process_errors` function here before
|
281
|
-
# extensions have a chance to modify them (see the MaskErrors
|
282
|
-
# extension). That way we can log the original errors but
|
283
|
-
# only return a sanitised version to the client.
|
284
|
-
process_errors(result.errors, execution_context)
|
285
|
-
except (MissingQueryError, InvalidOperationTypeError):
|
286
|
-
raise
|
287
|
-
except Exception as exc: # noqa: BLE001
|
288
|
-
errors = [_coerce_error(exc)]
|
289
|
-
execution_context.errors = errors
|
290
|
-
process_errors(errors, execution_context)
|
291
|
-
return ExecutionResult(
|
292
|
-
data=None,
|
293
|
-
errors=errors,
|
294
|
-
extensions=extensions_runner.get_extensions_results_sync(),
|
295
|
-
)
|
296
|
-
return ExecutionResult(
|
297
|
-
data=execution_context.result.data,
|
298
|
-
errors=execution_context.result.errors,
|
299
|
-
extensions=extensions_runner.get_extensions_results_sync(),
|
300
|
-
)
|
301
|
-
|
302
|
-
|
303
|
-
__all__ = ["execute", "execute_sync"]
|
strawberry/schema/subscribe.py
DELETED
@@ -1,155 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from collections.abc import AsyncGenerator, AsyncIterator
|
4
|
-
from typing import TYPE_CHECKING, Optional, Union
|
5
|
-
|
6
|
-
from graphql import (
|
7
|
-
ExecutionResult as OriginalExecutionResult,
|
8
|
-
)
|
9
|
-
from graphql.execution import ExecutionContext as GraphQLExecutionContext
|
10
|
-
from graphql.execution import subscribe as original_subscribe
|
11
|
-
|
12
|
-
from strawberry.types import ExecutionResult
|
13
|
-
from strawberry.types.execution import ExecutionContext, PreExecutionError
|
14
|
-
from strawberry.utils import IS_GQL_32
|
15
|
-
from strawberry.utils.await_maybe import await_maybe
|
16
|
-
|
17
|
-
from .execute import (
|
18
|
-
ProcessErrors,
|
19
|
-
_coerce_error,
|
20
|
-
_handle_execution_result,
|
21
|
-
_parse_and_validate_async,
|
22
|
-
)
|
23
|
-
|
24
|
-
if TYPE_CHECKING:
|
25
|
-
from typing_extensions import TypeAlias
|
26
|
-
|
27
|
-
from graphql.execution.middleware import MiddlewareManager
|
28
|
-
from graphql.type.schema import GraphQLSchema
|
29
|
-
|
30
|
-
from strawberry.extensions.runner import SchemaExtensionsRunner
|
31
|
-
|
32
|
-
SubscriptionResult: TypeAlias = Union[
|
33
|
-
PreExecutionError, AsyncGenerator[ExecutionResult, None]
|
34
|
-
]
|
35
|
-
|
36
|
-
OriginSubscriptionResult = Union[
|
37
|
-
OriginalExecutionResult,
|
38
|
-
AsyncIterator[OriginalExecutionResult],
|
39
|
-
]
|
40
|
-
|
41
|
-
|
42
|
-
async def _subscribe(
|
43
|
-
schema: GraphQLSchema,
|
44
|
-
execution_context: ExecutionContext,
|
45
|
-
extensions_runner: SchemaExtensionsRunner,
|
46
|
-
process_errors: ProcessErrors,
|
47
|
-
middleware_manager: MiddlewareManager,
|
48
|
-
execution_context_class: Optional[type[GraphQLExecutionContext]] = None,
|
49
|
-
) -> AsyncGenerator[Union[PreExecutionError, ExecutionResult], None]:
|
50
|
-
async with extensions_runner.operation():
|
51
|
-
if initial_error := await _parse_and_validate_async(
|
52
|
-
context=execution_context,
|
53
|
-
extensions_runner=extensions_runner,
|
54
|
-
):
|
55
|
-
initial_error.extensions = await extensions_runner.get_extensions_results(
|
56
|
-
execution_context
|
57
|
-
)
|
58
|
-
yield await _handle_execution_result(
|
59
|
-
execution_context, initial_error, extensions_runner, process_errors
|
60
|
-
)
|
61
|
-
try:
|
62
|
-
async with extensions_runner.executing():
|
63
|
-
assert execution_context.graphql_document is not None
|
64
|
-
gql_33_kwargs = {
|
65
|
-
"middleware": middleware_manager,
|
66
|
-
"execution_context_class": execution_context_class,
|
67
|
-
}
|
68
|
-
try:
|
69
|
-
# Might not be awaitable for pre-execution errors.
|
70
|
-
aiter_or_result: OriginSubscriptionResult = await await_maybe(
|
71
|
-
original_subscribe(
|
72
|
-
schema,
|
73
|
-
execution_context.graphql_document,
|
74
|
-
root_value=execution_context.root_value,
|
75
|
-
variable_values=execution_context.variables,
|
76
|
-
operation_name=execution_context.operation_name,
|
77
|
-
context_value=execution_context.context,
|
78
|
-
**{} if IS_GQL_32 else gql_33_kwargs, # type: ignore[arg-type]
|
79
|
-
)
|
80
|
-
)
|
81
|
-
# graphql-core 3.2 doesn't handle some of the pre-execution errors.
|
82
|
-
# see `test_subscription_immediate_error`
|
83
|
-
except Exception as exc: # noqa: BLE001
|
84
|
-
aiter_or_result = OriginalExecutionResult(
|
85
|
-
data=None, errors=[_coerce_error(exc)]
|
86
|
-
)
|
87
|
-
|
88
|
-
# Handle pre-execution errors.
|
89
|
-
if isinstance(aiter_or_result, OriginalExecutionResult):
|
90
|
-
yield await _handle_execution_result(
|
91
|
-
execution_context,
|
92
|
-
PreExecutionError(data=None, errors=aiter_or_result.errors),
|
93
|
-
extensions_runner,
|
94
|
-
process_errors,
|
95
|
-
)
|
96
|
-
else:
|
97
|
-
try:
|
98
|
-
async for result in aiter_or_result:
|
99
|
-
yield await _handle_execution_result(
|
100
|
-
execution_context,
|
101
|
-
result,
|
102
|
-
extensions_runner,
|
103
|
-
process_errors,
|
104
|
-
)
|
105
|
-
# graphql-core doesn't handle exceptions raised while executing.
|
106
|
-
except Exception as exc: # noqa: BLE001
|
107
|
-
yield await _handle_execution_result(
|
108
|
-
execution_context,
|
109
|
-
OriginalExecutionResult(data=None, errors=[_coerce_error(exc)]),
|
110
|
-
extensions_runner,
|
111
|
-
process_errors,
|
112
|
-
)
|
113
|
-
# catch exceptions raised in `on_execute` hook.
|
114
|
-
except Exception as exc: # noqa: BLE001
|
115
|
-
origin_result = OriginalExecutionResult(
|
116
|
-
data=None, errors=[_coerce_error(exc)]
|
117
|
-
)
|
118
|
-
yield await _handle_execution_result(
|
119
|
-
execution_context,
|
120
|
-
origin_result,
|
121
|
-
extensions_runner,
|
122
|
-
process_errors,
|
123
|
-
)
|
124
|
-
|
125
|
-
|
126
|
-
async def subscribe(
|
127
|
-
schema: GraphQLSchema,
|
128
|
-
execution_context: ExecutionContext,
|
129
|
-
extensions_runner: SchemaExtensionsRunner,
|
130
|
-
process_errors: ProcessErrors,
|
131
|
-
middleware_manager: MiddlewareManager,
|
132
|
-
execution_context_class: Optional[type[GraphQLExecutionContext]] = None,
|
133
|
-
) -> SubscriptionResult:
|
134
|
-
asyncgen = _subscribe(
|
135
|
-
schema,
|
136
|
-
execution_context,
|
137
|
-
extensions_runner,
|
138
|
-
process_errors,
|
139
|
-
middleware_manager,
|
140
|
-
execution_context_class,
|
141
|
-
)
|
142
|
-
# GraphQL-core might return an initial error result instead of an async iterator.
|
143
|
-
# This happens when "there was an immediate error" i.e resolver is not an async iterator.
|
144
|
-
# To overcome this while maintaining the extension contexts we do this trick.
|
145
|
-
first = await asyncgen.__anext__()
|
146
|
-
if isinstance(first, PreExecutionError):
|
147
|
-
await asyncgen.aclose()
|
148
|
-
return first
|
149
|
-
|
150
|
-
async def _wrapper() -> AsyncGenerator[ExecutionResult, None]:
|
151
|
-
yield first
|
152
|
-
async for result in asyncgen:
|
153
|
-
yield result
|
154
|
-
|
155
|
-
return _wrapper()
|
File without changes
|
File without changes
|
{strawberry_graphql-0.258.1.dist-info → strawberry_graphql-0.259.0.dist-info}/entry_points.txt
RENAMED
File without changes
|