Skip to content

Commit 5feaeeb

Browse files
committed
polish: do not repeat is_awaitable check
Replicates graphql/graphql-js@7fd1ddb
1 parent 7987576 commit 5feaeeb

File tree

3 files changed

+133
-70
lines changed

3 files changed

+133
-70
lines changed

src/graphql/execution/execute.py

+82-70
Original file line numberDiff line numberDiff line change
@@ -1359,11 +1359,11 @@ def complete_list_item_value(
13591359
Returns True if the value is awaitable.
13601360
"""
13611361
is_awaitable = self.is_awaitable
1362-
try:
1363-
if is_awaitable(item):
1364-
completed_item: Any
13651362

1366-
async def await_completed() -> Any:
1363+
if is_awaitable(item):
1364+
# noinspection PyShadowingNames
1365+
async def await_completed() -> Any:
1366+
try:
13671367
completed = self.complete_value(
13681368
item_type,
13691369
field_nodes,
@@ -1373,21 +1373,28 @@ async def await_completed() -> Any:
13731373
async_payload_record,
13741374
)
13751375
return await completed if is_awaitable(completed) else completed
1376+
except Exception as raw_error:
1377+
error = located_error(raw_error, field_nodes, item_path.as_list())
1378+
handle_field_error(error, item_type, errors)
1379+
self.filter_subsequent_payloads(item_path, async_payload_record)
1380+
return None
13761381

1377-
completed_item = await_completed()
1378-
else:
1379-
completed_item = self.complete_value(
1380-
item_type,
1381-
field_nodes,
1382-
info,
1383-
item_path,
1384-
item,
1385-
async_payload_record,
1386-
)
1382+
complete_results.append(await_completed())
1383+
return True
1384+
1385+
try:
1386+
completed_item = self.complete_value(
1387+
item_type,
1388+
field_nodes,
1389+
info,
1390+
item_path,
1391+
item,
1392+
async_payload_record,
1393+
)
13871394

13881395
if is_awaitable(completed_item):
13891396
# noinspection PyShadowingNames
1390-
async def catch_error() -> Any:
1397+
async def await_completed() -> Any:
13911398
try:
13921399
return await completed_item
13931400
except Exception as raw_error:
@@ -1398,7 +1405,7 @@ async def catch_error() -> Any:
13981405
self.filter_subsequent_payloads(item_path, async_payload_record)
13991406
return None
14001407

1401-
complete_results.append(catch_error())
1408+
complete_results.append(await_completed())
14021409
return True
14031410

14041411
complete_results.append(completed_item)
@@ -1728,15 +1735,17 @@ def execute_stream_field(
17281735
parent_context: Optional[AsyncPayloadRecord] = None,
17291736
) -> AsyncPayloadRecord:
17301737
"""Execute stream field."""
1738+
is_awaitable = self.is_awaitable
17311739
async_payload_record = StreamRecord(
17321740
label, item_path, None, parent_context, self
17331741
)
17341742
completed_item: Any
1735-
try:
1736-
try:
1737-
if self.is_awaitable(item):
17381743

1739-
async def await_completed_item() -> Any:
1744+
if is_awaitable(item):
1745+
# noinspection PyShadowingNames
1746+
async def await_completed_items() -> Optional[List[Any]]:
1747+
try:
1748+
try:
17401749
completed = self.complete_value(
17411750
item_type,
17421751
field_nodes,
@@ -1745,76 +1754,79 @@ async def await_completed_item() -> Any:
17451754
await item,
17461755
async_payload_record,
17471756
)
1748-
return (
1757+
return [
17491758
await completed
17501759
if self.is_awaitable(completed)
17511760
else completed
1761+
]
1762+
except Exception as raw_error:
1763+
error = located_error(
1764+
raw_error, field_nodes, item_path.as_list()
1765+
)
1766+
handle_field_error(
1767+
error, item_type, async_payload_record.errors
17521768
)
1769+
self.filter_subsequent_payloads(item_path, async_payload_record)
1770+
return [None]
1771+
except GraphQLError as error:
1772+
async_payload_record.errors.append(error)
1773+
self.filter_subsequent_payloads(path, async_payload_record)
1774+
return None
17531775

1754-
completed_item = await_completed_item()
1776+
async_payload_record.add_items(await_completed_items())
1777+
return async_payload_record
17551778

1756-
else:
1757-
completed_item = self.complete_value(
1758-
item_type,
1759-
field_nodes,
1760-
info,
1761-
item_path,
1762-
item,
1763-
async_payload_record,
1764-
)
1779+
try:
1780+
try:
1781+
completed_item = self.complete_value(
1782+
item_type,
1783+
field_nodes,
1784+
info,
1785+
item_path,
1786+
item,
1787+
async_payload_record,
1788+
)
17651789

1766-
if self.is_awaitable(completed_item):
1790+
completed_items: Any
17671791

1768-
async def await_completed_item() -> Any:
1792+
if is_awaitable(completed_item):
1793+
# noinspection PyShadowingNames
1794+
async def await_completed_items() -> Optional[List[Any]]:
17691795
# noinspection PyShadowingNames
17701796
try:
1771-
return await completed_item
1772-
except Exception as raw_error:
1773-
# noinspection PyShadowingNames
1774-
error = located_error(
1775-
raw_error, field_nodes, item_path.as_list()
1776-
)
1777-
handle_field_error(
1778-
error, item_type, async_payload_record.errors
1779-
)
1780-
self.filter_subsequent_payloads(
1781-
item_path, async_payload_record
1782-
)
1797+
try:
1798+
return [await completed_item]
1799+
except Exception as raw_error: # pragma: no cover
1800+
# noinspection PyShadowingNames
1801+
error = located_error(
1802+
raw_error, field_nodes, item_path.as_list()
1803+
)
1804+
handle_field_error(
1805+
error, item_type, async_payload_record.errors
1806+
)
1807+
self.filter_subsequent_payloads(
1808+
item_path, async_payload_record
1809+
)
1810+
return [None]
1811+
except GraphQLError as error: # pragma: no cover
1812+
async_payload_record.errors.append(error)
1813+
self.filter_subsequent_payloads(path, async_payload_record)
17831814
return None
17841815

1785-
complete_item = await_completed_item()
1786-
1816+
completed_items = await_completed_items()
17871817
else:
1788-
complete_item = completed_item
1818+
completed_items = [completed_item]
1819+
17891820
except Exception as raw_error:
17901821
error = located_error(raw_error, field_nodes, item_path.as_list())
17911822
handle_field_error(error, item_type, async_payload_record.errors)
1792-
self.filter_subsequent_payloads( # pragma: no cover
1793-
item_path, async_payload_record
1794-
)
1795-
complete_item = None # pragma: no cover
1823+
self.filter_subsequent_payloads(item_path, async_payload_record)
1824+
completed_items = [None]
17961825

17971826
except GraphQLError as error:
17981827
async_payload_record.errors.append(error)
17991828
self.filter_subsequent_payloads(item_path, async_payload_record)
1800-
async_payload_record.add_items(None)
1801-
return async_payload_record
1802-
1803-
completed_items: AwaitableOrValue[Optional[List[Any]]]
1804-
if self.is_awaitable(complete_item):
1805-
1806-
async def await_completed_items() -> Optional[List[Any]]:
1807-
# noinspection PyShadowingNames
1808-
try:
1809-
return [await complete_item] # type: ignore
1810-
except GraphQLError as error:
1811-
async_payload_record.errors.append(error)
1812-
self.filter_subsequent_payloads(path, async_payload_record)
1813-
return None
1814-
1815-
completed_items = await_completed_items()
1816-
else:
1817-
completed_items = [complete_item]
1829+
completed_items = None
18181830

18191831
async_payload_record.add_items(completed_items)
18201832
return async_payload_record

tests/execution/test_executor.py

+2
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ async def asyncReturnErrorWithExtensions(self, _info):
514514
],
515515
)
516516

517+
@pytest.mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning")
517518
def handles_sync_errors_combined_with_async_ones():
518519
is_async_resolver_finished = False
519520

@@ -560,6 +561,7 @@ async def async_resolver(_obj, _info):
560561
],
561562
)
562563

564+
@pytest.mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning")
563565
def full_response_path_is_included_for_non_nullable_fields():
564566
def resolve_ok(*_args):
565567
return {}

tests/execution/test_stream.py

+49
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,54 @@ async def await_friend(f):
536536
},
537537
]
538538

539+
@pytest.mark.asyncio()
540+
async def can_stream_a_field_that_returns_a_list_with_nested_async_fields():
541+
document = parse(
542+
"""
543+
query {
544+
friendList @stream(initialCount: 2) {
545+
name
546+
id
547+
}
548+
}
549+
"""
550+
)
551+
552+
async def get_name(f):
553+
return f.name
554+
555+
async def get_id(f):
556+
return f.id
557+
558+
result = await complete(
559+
document,
560+
{
561+
"friendList": lambda _info: [
562+
{"name": get_name(f), "id": get_id(f)} for f in friends
563+
]
564+
},
565+
)
566+
assert result == [
567+
{
568+
"data": {
569+
"friendList": [
570+
{"name": "Luke", "id": "1"},
571+
{"name": "Han", "id": "2"},
572+
]
573+
},
574+
"hasNext": True,
575+
},
576+
{
577+
"incremental": [
578+
{
579+
"items": [{"name": "Leia", "id": "3"}],
580+
"path": ["friendList", 2],
581+
}
582+
],
583+
"hasNext": False,
584+
},
585+
]
586+
539587
@pytest.mark.asyncio()
540588
async def handles_error_in_list_of_awaitables_before_initial_count_reached():
541589
document = parse(
@@ -1292,6 +1340,7 @@ async def friend_list(_info):
12921340
}
12931341

12941342
@pytest.mark.asyncio()
1343+
@pytest.mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning")
12951344
async def does_not_filter_payloads_when_null_error_is_in_a_different_path():
12961345
document = parse(
12971346
"""

0 commit comments

Comments
 (0)