pyhaul — resumable, crash-safe async downloads with aiohttp.ClientSession #12433
Replies: 2 comments 1 reply
|
PS: Here's how I designed the checkpoint file spec. It would have been a bit nicer to use BLAKE3 for this but I wanted pyhaul to be a zero dependencies library so I had to go with what was in stdlib. Still, the format is solid IMHO, it scales well for large files, the headers are aligned on word boundaries to make it super easy to read into a C or Rust struct. It's a tree hash of sha256 in 8mb chunks, so when re-reading after a resume you only need to rehash the tail chunk rather than read an entire 100GB file. Also some careful file handling and I/O sequencing to get the atomicity guarantees correct and handle file growth/preallocation and path handling correct on Linux/Mac/Windows. And a neat little immutable, O(1) HTTP headers implementation that preserves wire ordering and handles all the case normalization without needing any third party libraries. |
Uh oh!
There was an error while loading. Please reload this page.
I built pyhaul, a pure-Python library for resumable HTTP downloads. It has first-class aiohttp support — pass your
aiohttp.ClientSessiondirectly and pyhaul handles byte-range negotiation, ETag validation, and crash-safe checkpointing.Basic usage
One
haul_async()= one HTTP request. It either succeeds, or it saves progress so the next call resumes from the last durable byte.Concurrent downloads with TaskGroup
How it works with aiohttp
ClientSession— it never creates, configures, or closes it. Auth, proxies, timeouts, connector settings all pass through unchanged.async with/async fornatively. It's not a sync wrapper in a thread pool.auto_decompress=Falseon requests internally to get raw bytes for accurate byte-range resume. Your session's other settings are untouched.aiohttp.ClientErrorstaysaiohttp.ClientError. You catch the types you already know.What pyhaul handles
The "resumable download" problem is deceptively complex at the protocol level. Some things pyhaul takes care of:
If-Rangeand starts over cleanly instead of splicing mismatched data..partfile that gets atomically renamed on success. Checkpoint metadata is flushed to disk after data, never before.Cache-Control: no-transformto prevent proxies from re-compressing range responses.I wrote up a deep-dive comparing pyhaul's behavior to curl, wget, and aria2 (verified against source code) if anyone's interested in the protocol details.
Links
Pure Python, zero required dependencies, MIT licensed, Python 3.12+. Also supports httpx, requests, niquests, and urllib3 if you use those. Feedback welcome.
All reactions