Skip to content

Stream tweets to CSV as fetched (crash-safe, lower memory)#1

Merged
cybermejo merged 1 commit into
mainfrom
worktree-stream-csv-rows
Jun 17, 2026
Merged

Stream tweets to CSV as fetched (crash-safe, lower memory)#1
cybermejo merged 1 commit into
mainfrom
worktree-stream-csv-rows

Conversation

@cybermejo

Copy link
Copy Markdown
Owner

Summary

Streams scraped tweets to the output CSV as they are fetched, instead of buffering every row in memory and writing once at the end.

Why

The old main() accumulated all rows in an in-memory list and only opened the CSV after all scraping finished. A mid-run failure (network error, rate-limit exhaustion, Ctrl-C) therefore lost the entire run despite credits already spent, and memory grew with the result size.

What changed

  • main() opens the csv.DictWriter up front inside a with block and writes each deduped row immediately; the block flushes/closes the file as an exception unwinds, so already-fetched tweets survive a crash.
  • Only the seen id set + a small list of reply-target ids are held in memory — not full row dicts.
  • New helpers _write_new and _stream_replies replace the mutate-a-list _collect_replies; this also folds away the triplicated dedup logic.
  • Output ordering (search → user → replies) is unchanged.

Testing

Full validation loop green from scraper/: ruff check, ruff format --check, mypy, pytest --cov56 passed. Added end-to-end main() tests including test_main_persists_rows_fetched_before_a_midrun_crash, which fails on the old code and passes now (proves the crash-safety guarantee). Tests are fully mocked (no network).

Previously main() accumulated every row in an in-memory list and wrote the
CSV only after all scraping finished. A mid-run failure (network error,
rate-limit exhaustion, Ctrl-C) therefore lost the entire run despite credits
already spent, and memory grew with result size.

Now the DictWriter is opened up front inside a with-block and each deduped row
is written as it arrives, so the file is flushed/closed (preserving partial
output) when an exception unwinds. Only the seen-id set and a list of
reply-target ids are held in memory, not the full row dicts.

- Add _write_new (dedup + write) and _stream_replies, replacing the
  mutate-a-list _collect_replies; fold the triplicated dedup into _stream_query.
- Output ordering (search, then user, then replies) is unchanged.
- Add end-to-end main() tests incl. partial-output-survives-crash; replace the
  _collect_replies unit tests with _write_new/_stream_replies tests.
@cybermejo cybermejo self-assigned this Jun 17, 2026
@cybermejo cybermejo added the enhancement New feature or request label Jun 17, 2026
@cybermejo
cybermejo merged commit 96df411 into main Jun 17, 2026
4 checks passed
@cybermejo
cybermejo deleted the worktree-stream-csv-rows branch June 17, 2026 12:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant