11from asyncio import sleep
2- from typing import Any , Dict , List , NamedTuple
2+ from typing import Any , AsyncGenerator , Dict , List , NamedTuple
33
44import pytest
55from graphql .error import GraphQLError
1515)
1616from graphql .execution .execute import DeferredFragmentRecord
1717from graphql .language import DocumentNode , parse
18- from graphql .pyutils import Path
18+ from graphql .pyutils import Path , is_awaitable
1919from graphql .type import (
2020 GraphQLField ,
2121 GraphQLID ,
2626 GraphQLString ,
2727)
2828
29+
30+ def resolve_null_sync (_obj , _info ) -> None :
31+ """A resolver returning a null value synchronously."""
32+ return
33+
34+
35+ async def resolve_null_async (_obj , _info ) -> None :
36+ """A resolver returning a null value asynchronously."""
37+ return
38+
39+
2940friend_type = GraphQLObjectType (
30- "Friend" , {"id" : GraphQLField (GraphQLID ), "name" : GraphQLField (GraphQLString )}
41+ "Friend" ,
42+ {
43+ "id" : GraphQLField (GraphQLID ),
44+ "name" : GraphQLField (GraphQLString ),
45+ "asyncNonNullErrorField" : GraphQLField (
46+ GraphQLNonNull (GraphQLString ), resolve = resolve_null_async
47+ ),
48+ },
3149)
3250
3351
3452class Friend (NamedTuple ):
35- name : str
3653 id : int
54+ name : str
3755
3856
39- friends = [Friend ("Han" , 2 ), Friend ("Leia" , 3 ), Friend ("C-3PO" , 4 )]
57+ friends = [Friend (2 , "Han" ), Friend (3 , "Leia" ), Friend (4 , "C-3PO" )]
4058
4159
4260async def resolve_slow (_obj , _info ) -> str :
@@ -50,14 +68,10 @@ async def resolve_bad(_obj, _info) -> str:
5068 raise RuntimeError ("bad" )
5169
5270
53- def resolve_null_sync (_obj , _info ) -> None :
54- """Simulate a resolver returning a null value synchronously."""
55- return
56-
57-
58- async def resolve_null_async (_obj , _info ) -> None :
59- """Simulate a resolver returning a null value asynchronously."""
60- return
71+ async def resolve_friends_async (_obj , _info ) -> AsyncGenerator [Friend , None ]:
72+ """A slow async generator yielding the first friend."""
73+ await sleep (0 )
74+ yield friends [0 ]
6175
6276
6377hero_type = GraphQLObjectType (
@@ -76,10 +90,13 @@ async def resolve_null_async(_obj, _info) -> None:
7690 "friends" : GraphQLField (
7791 GraphQLList (friend_type ), resolve = lambda _obj , _info : friends
7892 ),
93+ "asyncFriends" : GraphQLField (
94+ GraphQLList (friend_type ), resolve = resolve_friends_async
95+ ),
7996 },
8097)
8198
82- hero = Friend ("Luke" , 1 )
99+ hero = Friend (1 , "Luke" )
83100
84101query = GraphQLObjectType (
85102 "Query" , {"hero" : GraphQLField (hero_type , resolve = lambda _obj , _info : hero )}
@@ -90,6 +107,8 @@ async def resolve_null_async(_obj, _info) -> None:
90107
91108async def complete (document : DocumentNode , root_value : Any = None ) -> Any :
92109 result = experimental_execute_incrementally (schema , document , root_value )
110+ if is_awaitable (result ):
111+ result = await result
93112
94113 if isinstance (result , ExperimentalIncrementalExecutionResults ):
95114 results : List [Any ] = [result .initial_result .formatted ]
@@ -882,6 +901,38 @@ async def returns_payloads_from_synchronous_data_in_correct_order():
882901 },
883902 ]
884903
904+ @pytest .mark .asyncio ()
905+ async def filters_deferred_payloads_when_list_item_from_async_iterable_nulled ():
906+ document = parse (
907+ """
908+ query {
909+ hero {
910+ asyncFriends {
911+ asyncNonNullErrorField
912+ ...NameFragment @defer
913+ }
914+ }
915+ }
916+ fragment NameFragment on Friend {
917+ name
918+ }
919+ """
920+ )
921+
922+ result = await complete (document )
923+
924+ assert result == {
925+ "data" : {"hero" : {"asyncFriends" : [None ]}},
926+ "errors" : [
927+ {
928+ "message" : "Cannot return null for non-nullable field"
929+ " Friend.asyncNonNullErrorField." ,
930+ "locations" : [{"line" : 5 , "column" : 19 }],
931+ "path" : ["hero" , "asyncFriends" , 0 , "asyncNonNullErrorField" ],
932+ }
933+ ],
934+ }
935+
885936 @pytest .mark .asyncio ()
886937 async def original_execute_function_throws_error_if_deferred_and_all_is_sync ():
887938 document = parse (
@@ -918,7 +969,8 @@ async def original_execute_function_throws_error_if_deferred_and_not_all_is_sync
918969 [
919970 {
920971 "message" : "Executing this GraphQL operation would unexpectedly"
921- " produce multiple payloads (due to @defer or @stream directive)"
972+ " produce multiple payloads"
973+ " (due to @defer or @stream directive)"
922974 }
923975 ],
924976 )
0 commit comments