|
31 | 31 | Any, |
32 | 32 | Generic, |
33 | 33 | NamedTuple, |
34 | | - NoReturn, |
35 | 34 | TypeVar, |
36 | 35 | cast, |
37 | 36 | ) |
|
71 | 70 | GraphQLObjectType, |
72 | 71 | GraphQLOutputType, |
73 | 72 | GraphQLResolveInfo, |
| 73 | + GraphQLResolveInfoHelpers, |
74 | 74 | GraphQLSchema, |
75 | 75 | GraphQLStreamDirective, |
76 | 76 | GraphQLTypeResolver, |
@@ -218,6 +218,7 @@ class Executor(IncrementalPublisherContext): |
218 | 218 | enable_early_execution: bool |
219 | 219 | hide_suggestions: bool |
220 | 220 | abort_signal: AbortSignal | None |
| 221 | + async_helpers: GraphQLResolveInfoHelpers |
221 | 222 | errors: list[GraphQLError] | None |
222 | 223 | cancellable_streams: set[CancellableStreamRecord] | None |
223 | 224 | pending_incremental_futures: set[Future[Any]] |
@@ -267,6 +268,7 @@ def __init__( # noqa: PLR0913 |
267 | 268 | self.enable_early_execution = enable_early_execution |
268 | 269 | self.hide_suggestions = hide_suggestions |
269 | 270 | self.abort_signal = abort_signal |
| 271 | + self.async_helpers = GraphQLResolveInfoHelpers(track=self.track_async_work) |
270 | 272 | self.middleware_manager = middleware_manager |
271 | 273 | self.error_propagation = not any( |
272 | 274 | directive.name.value == GraphQLDisableErrorPropagationDirective.name |
@@ -817,6 +819,7 @@ def build_resolve_info( |
817 | 819 | self.context_value, |
818 | 820 | self.is_awaitable, |
819 | 821 | self.abort_signal, |
| 822 | + self.async_helpers, |
820 | 823 | ) |
821 | 824 |
|
822 | 825 | def handle_field_error( |
@@ -1061,6 +1064,20 @@ def settle_in_background(self, awaitables: list[Awaitable[Any]]) -> None: |
1061 | 1064 | background_futures.add(future) |
1062 | 1065 | future.add_done_callback(background_futures.discard) |
1063 | 1066 |
|
| 1067 | + def track_async_work(self, values: Sequence[Any]) -> None: |
| 1068 | + """Track possibly awaitable values as pending asynchronous work. |
| 1069 | +
|
| 1070 | + Awaitables among the given values are settled in the background, so that |
| 1071 | + they are still settled and their errors observed when they would otherwise |
| 1072 | + be abandoned. Non-awaitable values are ignored. |
| 1073 | + """ |
| 1074 | + is_awaitable = self.is_awaitable |
| 1075 | + awaitables: list[Awaitable[Any]] = [ |
| 1076 | + value for value in values if is_awaitable(value) |
| 1077 | + ] |
| 1078 | + if awaitables: |
| 1079 | + self.settle_in_background(awaitables) |
| 1080 | + |
1064 | 1081 | def cancellable_iterable(self, iterable: AsyncIterable[T]) -> AsyncIterable[T]: |
1065 | 1082 | """Wrap an async iterable so pending iteration is cancelled on abort. |
1066 | 1083 |
|
@@ -2709,25 +2726,13 @@ def default_type_resolver( |
2709 | 2726 | append_awaitable_type(type_) |
2710 | 2727 | elif is_type_of_result: |
2711 | 2728 | if awaitable_is_type_of_results: |
2712 | | - |
2713 | | - async def await_is_type_of_and_return_type( |
2714 | | - resolved_type_name: str = type_.name, |
2715 | | - ) -> str: |
2716 | | - with suppress(Exception): |
2717 | | - await gather_with_cancel(*awaitable_is_type_of_results) |
2718 | | - return resolved_type_name |
2719 | | - |
2720 | | - return await_is_type_of_and_return_type() |
| 2729 | + info.async_helpers.track(awaitable_is_type_of_results) |
2721 | 2730 | return type_.name |
2722 | | - except Exception as error: |
| 2731 | + except Exception: |
2723 | 2732 | if awaitable_is_type_of_results: |
2724 | | - # Settle the pending isTypeOf results so that their errors can be |
2725 | | - # observed before they would be orphaned. |
2726 | | - async def settle_and_raise(error: Exception = error) -> NoReturn: |
2727 | | - await gather(*awaitable_is_type_of_results, return_exceptions=True) |
2728 | | - raise error # noqa: TRY201 |
2729 | | - |
2730 | | - return settle_and_raise() |
| 2733 | + # Settle the pending isTypeOf results in the background so that |
| 2734 | + # their errors can be observed before they would be orphaned. |
| 2735 | + info.async_helpers.track(awaitable_is_type_of_results) |
2731 | 2736 | raise |
2732 | 2737 |
|
2733 | 2738 | if awaitable_is_type_of_results: |
|
0 commit comments