Skip to content

Commit bde4ba2

Browse files
committed
fix(dataset): bound CSV export memory usage
Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
1 parent 6e60ba7 commit bde4ba2

2 files changed

Lines changed: 25 additions & 9 deletions

File tree

src/crawlee/_utils/file.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,21 @@ async def export_csv_to_stream(
203203
if 'lineterminator' not in kwargs:
204204
kwargs['lineterminator'] = '\n'
205205

206-
items = [item async for item in iterator if item]
207-
if not items:
208-
return
209-
210-
fieldnames = list(dict.fromkeys(key for item in items for key in item))
211-
writer = csv.DictWriter(dst, fieldnames=fieldnames, **kwargs)
212-
writer.writeheader()
213-
for item in items:
214-
writer.writerow(item)
206+
fieldnames = dict[str, None]()
207+
with tempfile.TemporaryFile(mode='w+', encoding='utf-8') as items:
208+
async for item in iterator:
209+
if not item:
210+
continue
211+
212+
fieldnames.update(dict.fromkeys(item))
213+
json.dump(item, items)
214+
items.write('\n')
215+
216+
if not fieldnames:
217+
return
218+
219+
writer = csv.DictWriter(dst, fieldnames=fieldnames, **kwargs)
220+
writer.writeheader()
221+
items.seek(0)
222+
for item in items:
223+
writer.writerow(json.loads(item))

tests/unit/_utils/test_file.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ async def test_export_csv_to_stream_skips_empty_items() -> None:
6363
assert dst.getvalue() == 'id,name\n1,Item 1\n2,Item 2\n'
6464

6565

66+
async def test_export_csv_to_stream_handles_empty_iterator() -> None:
67+
dst = StringIO()
68+
await export_csv_to_stream(_async_iter([]), dst)
69+
70+
assert dst.getvalue() == ''
71+
72+
6673
# Tests for validate_subdirectory (storage name/alias directory validation).
6774

6875

0 commit comments

Comments
 (0)