@@ -331,8 +331,6 @@ def execute_operation(
331331 # Errors from sub-fields of a NonNull type may propagate to the top level, at
332332 # which point we still log the error and null the parent field, which in this
333333 # case is the entire response.
334- #
335- # Similar to complete_value_catching_error.
336334 try :
337335 # noinspection PyArgumentList
338336 result = (
@@ -595,6 +593,7 @@ def resolve_field(
595593 if not field_def :
596594 return Undefined
597595
596+ return_type = field_def .type
598597 resolve_fn = field_def .resolve or self .field_resolver
599598
600599 if self .middleware_manager :
@@ -604,29 +603,6 @@ def resolve_field(
604603
605604 # Get the resolve function, regardless of if its result is normal or abrupt
606605 # (error).
607- result = self .resolve_field_value_or_error (
608- field_def , field_nodes , resolve_fn , source , info
609- )
610-
611- return self .complete_value_catching_error (
612- field_def .type , field_nodes , info , path , result
613- )
614-
615- def resolve_field_value_or_error (
616- self ,
617- field_def : GraphQLField ,
618- field_nodes : List [FieldNode ],
619- resolve_fn : GraphQLFieldResolver ,
620- source : Any ,
621- info : GraphQLResolveInfo ,
622- ) -> Union [Exception , Any ]:
623- """Resolve field to a value or an error.
624-
625- Isolates the "ReturnOrAbrupt" behavior to not de-opt the resolve_field()
626- method. Returns the result of resolveFn or the abrupt-return Error object.
627-
628- For internal use only.
629- """
630606 try :
631607 # Build a dictionary of arguments from the field.arguments AST, using the
632608 # variables scope to fulfill any variable references.
@@ -635,58 +611,38 @@ def resolve_field_value_or_error(
635611 # Note that contrary to the JavaScript implementation, we pass the context
636612 # value as part of the resolve info.
637613 result = resolve_fn (source , info , ** args )
614+
615+ completed : AwaitableOrValue [Any ]
638616 if self .is_awaitable (result ):
639617 # noinspection PyShadowingNames
640618 async def await_result () -> Any :
641619 try :
642- return await result
620+ completed = self .complete_value (
621+ return_type , field_nodes , info , path , await result
622+ )
623+ if self .is_awaitable (completed ):
624+ return await completed
625+ return completed
643626 except Exception as error :
644- return error
627+ self .handle_field_error (error , field_nodes , path , return_type )
628+ return None
645629
646630 return await_result ()
647- return result
648- except Exception as error :
649- return error
650631
651- def complete_value_catching_error (
652- self ,
653- return_type : GraphQLOutputType ,
654- field_nodes : List [FieldNode ],
655- info : GraphQLResolveInfo ,
656- path : Path ,
657- result : Any ,
658- ) -> AwaitableOrValue [Any ]:
659- """Complete a value while catching an error.
660-
661- This is a small wrapper around completeValue which detects and logs errors in
662- the execution context.
663- """
664- completed : AwaitableOrValue [Any ]
665- try :
666- if self .is_awaitable (result ):
667-
668- async def await_result () -> Any :
669- value = self .complete_value (
670- return_type , field_nodes , info , path , await result
671- )
672- if self .is_awaitable (value ):
673- return await value
674- return value
675-
676- completed = await_result ()
677- else :
678- completed = self .complete_value (
679- return_type , field_nodes , info , path , result
680- )
632+ completed = self .complete_value (
633+ return_type , field_nodes , info , path , result
634+ )
681635 if self .is_awaitable (completed ):
682636 # noinspection PyShadowingNames
683637 async def await_completed () -> Any :
684638 try :
685639 return await completed
686640 except Exception as error :
687641 self .handle_field_error (error , field_nodes , path , return_type )
642+ return None
688643
689644 return await_completed ()
645+
690646 return completed
691647 except Exception as error :
692648 self .handle_field_error (error , field_nodes , path , return_type )
@@ -825,10 +781,45 @@ def complete_list_value(
825781 for index , item in enumerate (result ):
826782 # No need to modify the info object containing the path, since from here on
827783 # it is not ever accessed by resolver functions.
828- field_path = path .add_key (index , None )
829- completed_item = self .complete_value_catching_error (
830- item_type , field_nodes , info , field_path , item
831- )
784+ item_path = path .add_key (index , None )
785+ completed_item : AwaitableOrValue [Any ]
786+ if is_awaitable (item ):
787+ # noinspection PyShadowingNames
788+ async def await_completed (item : Any , item_path : Path ) -> Any :
789+ try :
790+ completed = self .complete_value (
791+ item_type , field_nodes , info , item_path , await item
792+ )
793+ if is_awaitable (completed ):
794+ return await completed
795+ return completed
796+ except Exception as error :
797+ self .handle_field_error (
798+ error , field_nodes , item_path , item_type
799+ )
800+ return None
801+
802+ completed_item = await_completed (item , item_path )
803+ else :
804+ try :
805+ completed_item = self .complete_value (
806+ item_type , field_nodes , info , item_path , item
807+ )
808+ if is_awaitable (completed_item ):
809+ # noinspection PyShadowingNames
810+ async def await_completed (item : Any , item_path : Path ) -> Any :
811+ try :
812+ return await item
813+ except Exception as error :
814+ self .handle_field_error (
815+ error , field_nodes , item_path , item_type
816+ )
817+ return None
818+
819+ completed_item = await_completed (completed_item , item_path )
820+ except Exception as error :
821+ self .handle_field_error (error , field_nodes , item_path , item_type )
822+ completed_item = None
832823
833824 if is_awaitable (completed_item ):
834825 append_awaitable (index )
0 commit comments