|
3 | 3 | import asyncio |
4 | 4 | from typing import AsyncGenerator, Iterator, Any |
5 | 5 |
|
6 | | -class AsyncToSyncIterator: |
7 | | - """ |
8 | | - Converts an async generator into a synchronous iterator while ensuring proper event loop handling. |
9 | | - """ |
10 | | - |
11 | | - def __init__(self, async_gen: AsyncGenerator[Any, None]): |
12 | | - """ |
13 | | - Initializes the iterator by consuming an async generator synchronously. |
14 | | -
|
15 | | - Args: |
16 | | - async_gen (AsyncGenerator): The async generator yielding results. |
17 | | - """ |
18 | | - self.async_gen = async_gen |
19 | | - self.loop = self._get_event_loop() |
20 | | - self.iterator = self._to_iterator() |
21 | | - |
22 | | - def _get_event_loop(self) -> asyncio.AbstractEventLoop: |
23 | | - """Returns the currently running event loop or creates a new one if none exists.""" |
24 | | - try: |
25 | | - loop = asyncio.get_running_loop() |
26 | | - if loop.is_running(): |
27 | | - return None # Indicate an already running loop (handled in `_to_iterator()`) |
28 | | - except RuntimeError: |
29 | | - loop = asyncio.new_event_loop() |
30 | | - asyncio.set_event_loop(loop) |
31 | | - return loop |
32 | | - |
33 | | - def _to_iterator(self) -> Iterator: |
34 | | - """ |
35 | | - Ensures that the async generator is consumed using the correct event loop. |
36 | | - Uses streaming (does not load all results into memory). |
37 | | - """ |
38 | | - if self.loop: |
39 | | - return iter(self.loop.run_until_complete(self._stream_results())) |
40 | | - else: |
41 | | - return iter(asyncio.run(self._stream_results())) # Safe for Jupyter, PySpark |
42 | | - |
43 | | - # Caution : prone to OOM errors |
44 | | - async def _stream_results(self): |
45 | | - # """Streams async generator results without collecting all in memory.""" |
46 | | - # page_count = 0 |
47 | | - # async for item in self.async_gen: |
48 | | - # if page_count >= self.max_pages: |
49 | | - # raise RuntimeError("Pagination limit reached, possible infinite loop detected!") |
50 | | - # yield item |
51 | | - # page_count += 1 # Track pages to prevent infinite loops |
52 | | - return [item async for item in self.async_gen] |
53 | | - |
54 | | - def __iter__(self) -> Iterator: |
55 | | - """Returns the synchronous iterator.""" |
56 | | - return self.iterator |
57 | | - |
58 | | - |
59 | 6 | import asyncio |
60 | 7 | from typing import AsyncGenerator, Iterator, Any |
61 | 8 |
|
62 | | -class AsyncToSyncIteratorV2: |
| 9 | +class AsyncToSyncIterator: |
63 | 10 | """ |
64 | 11 | Converts an async generator into a synchronous iterator while ensuring proper event loop handling. |
65 | 12 | """ |
|
0 commit comments