Skip to content

Commit 628e6cd

Browse files
committed
Reverse sort order of listed orders
On listing orders the API returns newest orders first. To print newest orders at the bottom of the list the sort order is reversed. To keep memory usage within limits the reversal is only performed within chunks.
1 parent 7b4df15 commit 628e6cd

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

src/frequenz/client/electricity_trading/cli/etrading.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33

44
"""CLI tool to interact with the trading API."""
55

6+
from collections import deque
67
from datetime import datetime, timedelta, timezone
78
from decimal import Decimal
89
from enum import Enum
10+
from typing import AsyncIterator
911

1012
from frequenz.client.electricity_trading import (
1113
Client,
@@ -84,6 +86,9 @@ async def list_orders(
8486
for the 15 minute delivery period starting at delivery_start.
8587
If no delivery_start is provided, stream new orders for any delivery period.
8688
89+
Note that retrieved sort order for listed orders (starting from the newest)
90+
is reversed in chunks trying to bring more recent orders to the bottom.
91+
8792
Args:
8893
url: URL of the trading API.
8994
key: API key.
@@ -104,7 +109,7 @@ async def list_orders(
104109
)
105110
lst = client.list_gridpool_orders(gid, delivery_period=delivery_period)
106111

107-
async for order in lst:
112+
async for order in reverse_iterator(lst):
108113
print_order(order)
109114

110115
if delivery_start and delivery_start <= datetime.now(timezone.utc):
@@ -282,3 +287,27 @@ def print_order(order: OrderDetail) -> None:
282287
order.state_detail.state,
283288
]
284289
print(",".join(v.name if isinstance(v, Enum) else str(v) for v in values))
290+
291+
292+
async def reverse_iterator(
293+
iterator: AsyncIterator[OrderDetail], chunk_size: int = 100_000
294+
) -> AsyncIterator[OrderDetail]:
295+
"""Reverse an async iterator in chunks to avoid loading all elements into memory.
296+
297+
Args:
298+
iterator: Async iterator to reverse.
299+
chunk_size: Size of the buffer to store elements.
300+
301+
Yields:
302+
Elements of the iterator in reverse order.
303+
"""
304+
buffer: deque[OrderDetail] = deque(maxlen=chunk_size)
305+
async for item in iterator:
306+
buffer.append(item)
307+
if len(buffer) == chunk_size:
308+
for item in reversed(buffer):
309+
yield item
310+
buffer.clear()
311+
if buffer:
312+
for item in reversed(buffer):
313+
yield item

0 commit comments

Comments
 (0)