Skip to content

Commit 5437ca5

Browse files
committed
Fix stream record test
1 parent b224af6 commit 5437ca5

File tree

3 files changed

+36
-41
lines changed

3 files changed

+36
-41
lines changed

src/graphql/execution/incremental_publisher.py

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
AsyncGenerator,
1010
AsyncIterator,
1111
Awaitable,
12+
Collection,
1213
NamedTuple,
1314
Sequence,
1415
Union,
@@ -328,7 +329,7 @@ def __ne__(self, other: object) -> bool:
328329
class InitialResult(NamedTuple):
329330
"""The state of the initial result"""
330331

331-
children: set[IncrementalDataRecord]
332+
children: dict[IncrementalDataRecord, None]
332333
is_completed: bool
333334

334335

@@ -356,16 +357,19 @@ class IncrementalPublisher:
356357
357358
Each Incremental Data record also contains similar metadata, i.e. these records also
358359
contain similar ``is_completed`` and ``children`` properties.
360+
361+
Note: Instead of sets we use dicts (with values set to None) which preserve order
362+
and thereby achieve more deterministic results.
359363
"""
360364

361365
_initial_result: InitialResult
362-
_released: set[IncrementalDataRecord]
363-
_pending: set[IncrementalDataRecord]
366+
_released: dict[IncrementalDataRecord, None]
367+
_pending: dict[IncrementalDataRecord, None]
364368

365369
def __init__(self) -> None:
366-
self._initial_result = InitialResult(set(), False)
367-
self._released = set()
368-
self._pending = set()
370+
self._initial_result = InitialResult({}, False)
371+
self._released = {}
372+
self._pending = {}
369373
self._resolve = Event()
370374
self._tasks: set[Awaitable] = set()
371375

@@ -382,13 +386,10 @@ async def subscribe(
382386
while not is_done:
383387
released = self._released
384388
for item in released:
385-
pending.discard(item)
386-
self._released = (
387-
set()
388-
) # TODO, solve differently? use clear() and local variable?
389+
del pending[item]
390+
self._released = {}
389391

390392
result = self._get_incremental_result(released)
391-
released.clear()
392393

393394
if not self.has_next():
394395
is_done = True
@@ -420,7 +421,8 @@ def prepare_new_deferred_fragment_record(
420421
) -> DeferredFragmentRecord:
421422
deferred_fragment_record = DeferredFragmentRecord(label, path, parent_context)
422423

423-
(parent_context or self._initial_result).children.add(deferred_fragment_record)
424+
context = parent_context or self._initial_result
425+
context.children[deferred_fragment_record] = None
424426
return deferred_fragment_record
425427

426428
def prepare_new_stream_items_record(
@@ -434,7 +436,8 @@ def prepare_new_stream_items_record(
434436
label, path, parent_context, async_iterator
435437
)
436438

437-
(parent_context or self._initial_result).children.add(stream_items_record)
439+
context = parent_context or self._initial_result
440+
context.children[stream_items_record] = None
438441
return stream_items_record
439442

440443
def complete_deferred_fragment_record(
@@ -484,7 +487,7 @@ def filter(
484487

485488
self._delete(child)
486489
parent = child.parent_context or self._initial_result
487-
parent.children.discard(child)
490+
del parent.children[child]
488491

489492
if isinstance(child, StreamItemsRecord):
490493
async_iterator = child.async_iterator
@@ -504,26 +507,26 @@ def _reset(self) -> None:
504507
self._resolve.clear()
505508

506509
def _introduce(self, item: IncrementalDataRecord) -> None:
507-
self._pending.add(item)
510+
self._pending[item] = None
508511

509512
def _release(self, item: IncrementalDataRecord) -> None:
510513
if item in self._pending:
511-
self._pending.remove(item)
512-
self._released.add(item)
514+
del self._pending[item]
515+
self._released[item] = None
513516
self._trigger()
514517

515518
def _push(self, item: IncrementalDataRecord) -> None:
516-
self._released.add(item)
517-
self._pending.add(item)
519+
self._released[item] = None
520+
self._pending[item] = None
518521
self._trigger()
519522

520523
def _delete(self, item: IncrementalDataRecord) -> None:
521-
self._released.discard(item)
522-
self._pending.discard(item)
524+
del self._released[item]
525+
del self._pending[item]
523526
self._trigger()
524527

525528
def _get_incremental_result(
526-
self, completed_records: set[IncrementalDataRecord]
529+
self, completed_records: Collection[IncrementalDataRecord]
527530
) -> SubsequentIncrementalExecutionResult | None:
528531
incremental_results: list[IncrementalResult] = []
529532
encountered_completed_async_iterator = False
@@ -574,13 +577,13 @@ def _publish(self, incremental_data_record: IncrementalDataRecord) -> None:
574577

575578
def _get_descendants(
576579
self,
577-
children: set[IncrementalDataRecord],
578-
descendants: set[IncrementalDataRecord] | None = None,
579-
) -> set[IncrementalDataRecord]:
580+
children: dict[IncrementalDataRecord, None],
581+
descendants: dict[IncrementalDataRecord, None] | None = None,
582+
) -> dict[IncrementalDataRecord, None]:
580583
if descendants is None:
581-
descendants = set()
584+
descendants = {}
582585
for child in children:
583-
descendants.add(child)
586+
descendants[child] = None
584587
self._get_descendants(child.children, descendants)
585588
return descendants
586589

@@ -604,7 +607,7 @@ class DeferredFragmentRecord:
604607
path: list[str | int]
605608
data: dict[str, Any] | None
606609
parent_context: IncrementalDataRecord | None
607-
children: set[IncrementalDataRecord]
610+
children: dict[IncrementalDataRecord, None]
608611
is_completed: bool
609612

610613
def __init__(
@@ -617,7 +620,7 @@ def __init__(
617620
self.path = path.as_list() if path else []
618621
self.parent_context = parent_context
619622
self.errors = []
620-
self.children = set()
623+
self.children = {}
621624
self.is_completed = False
622625
self.data = None
623626

@@ -641,7 +644,7 @@ class StreamItemsRecord:
641644
path: list[str | int]
642645
items: list[str] | None
643646
parent_context: IncrementalDataRecord | None
644-
children: set[IncrementalDataRecord]
647+
children: dict[IncrementalDataRecord, None]
645648
async_iterator: AsyncIterator[Any] | None
646649
is_completed_async_iterator: bool
647650
is_completed: bool
@@ -658,7 +661,7 @@ def __init__(
658661
self.parent_context = parent_context
659662
self.async_iterator = async_iterator
660663
self.errors = []
661-
self.children = set()
664+
self.children = {}
662665
self.is_completed = False
663666
self.items = None
664667

tests/execution/test_defer.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
from asyncio import sleep
4-
from operator import itemgetter
54
from typing import Any, AsyncGenerator, NamedTuple
65

76
import pytest
@@ -515,8 +514,6 @@ async def can_defer_a_fragment_within_an_already_deferred_fragment():
515514
"""
516515
)
517516
result = await complete(document)
518-
# incremental results can sometimes arrive in different order which is ok
519-
result[1]["incremental"].sort(key=itemgetter("label"))
520517

521518
assert result == [
522519
{"data": {"hero": {}}, "hasNext": True},

tests/execution/test_stream.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import pytest
77
from graphql.error import GraphQLError
88
from graphql.execution import (
9-
ExecutionContext,
109
ExecutionResult,
1110
ExperimentalIncrementalExecutionResults,
1211
IncrementalStreamResult,
@@ -173,13 +172,9 @@ def can_format_and_print_incremental_stream_result():
173172
)
174173

175174
def can_print_stream_record():
176-
context = ExecutionContext.build(schema, parse("{ hero { id } }"))
177-
assert isinstance(context, ExecutionContext)
178-
record = StreamItemsRecord(None, None, None, None, context)
175+
record = StreamItemsRecord(None, None, None, None)
179176
assert str(record) == "StreamItemsRecord(path=[])"
180-
record = StreamItemsRecord(
181-
"foo", Path(None, "bar", "Bar"), None, record, context
182-
)
177+
record = StreamItemsRecord("foo", Path(None, "bar", "Bar"), record, None)
183178
assert (
184179
str(record) == "StreamItemsRecord("
185180
"path=['bar'], label='foo', parent_context)"

0 commit comments

Comments
 (0)