bytehaul
Python bindings for the bytehaul Rust download library. This guide targets the published 0.2.3 release.
Requirements
- Python 3.9+
- Rust toolchain and
uvonly when building from source; neither is required to install an available wheel.
Each source-build command block below assumes you start from the repository root.
Installation
From PyPI
pip install "bytehaul==0.2.3"
See the 0.2.3 release notes.
From source (development)
uv sync --project bindings/python
cd bindings/python
uv run --project . maturin develop -m Cargo.toml
Build wheel
cd bindings/python
uv run --project . maturin build --release -m Cargo.toml
Usage
Simple download
import bytehaul
bytehaul.download("https://example.com/file.bin", output_path="output.bin")
# Let bytehaul decide the filename and place it in downloads/
bytehaul.download("https://example.com/file.bin", output_dir="downloads")
With options
bytehaul.download(
"https://example.com/file.bin",
output_path="output.bin",
max_connections=8,
max_download_speed=1_000_000, # 1 MB/s
headers={"Authorization": "Bearer token"},
)
Network settings
bytehaul.download(
"https://example.com/file.bin",
output_path="output.bin",
proxy="http://127.0.0.1:7890",
dns_servers=["1.1.1.1", "8.8.8.8:53"],
doh_servers=["https://dns.google/dns-query"],
enable_ipv6=False,
)
doh_servers expects HTTPS URLs. If you pass a hostname such as dns.google, bytehaul will use the system resolver once during client construction to bootstrap the DoH endpoint addresses.
Logging
# Enable debug logging on the convenience function
bytehaul.download(
"https://example.com/file.bin",
output_path="output.bin",
log_level="debug",
)
# Or on the Downloader object
from bytehaul import Downloader
downloader = Downloader(log_level="info")
Valid levels: "off" (default), "error", "warn", "info", "debug", "trace".
Object API with progress and cancellation
from bytehaul import Downloader
downloader = Downloader(
connect_timeout=15.0,
dns_servers=["1.1.1.1"],
doh_servers=["https://dns.google/dns-query"],
enable_ipv6=False,
)
task = downloader.download(
"https://example.com/large.bin",
output_dir="downloads",
proxy="http://127.0.0.1:7890",
)
# Poll progress
snap = task.progress()
print(
f"State: {snap.state}, Downloaded: {snap.downloaded}, "
f"Speed: {snap.speed:.0f} B/s, ETA: {snap.eta_secs}"
)
# Pause or cancel if needed
# task.pause()
# task.cancel()
# Wait for completion
task.wait()
Error handling
from bytehaul import download, DownloadFailedError, CancelledError, PausedError, ConfigError
try:
download("https://example.com/file.bin", output_path="output.bin")
except ConfigError as e:
print(f"Invalid parameter: {e}")
except PausedError:
print("Download was paused")
except CancelledError:
print("Download was cancelled")
except DownloadFailedError as e:
print(f"Download failed: {e}")
Response-body timeouts, connection resets and early EOF for a known-size body are retried within max_retries, which counts additional attempts after the first (0 disables retries). With a known total and matching object validators, continuation starts at the durable prefix confirmed by the writer; ignored Range requests or changed object metadata trigger a safe restart from zero. Disk write and synchronization errors are not retried as network failures.
API Reference
download(url, output_path=None, output_dir=None, **options)
Blocking convenience function. Downloads a file and returns when complete.
output_path: explicit filename or relative output pathoutput_dir: destination directory for explicit or auto-detected filenames- If
output_pathis omitted, bytehaul choosesContent-Disposition→ URL path →download - Absolute
output_pathvalues are still accepted whenoutput_diris omitted
Downloader(connect_timeout=None, proxy=None, http_proxy=None, https_proxy=None, dns_servers=None, doh_servers=None, enable_ipv6=None, log_level=None)
Reusable downloader instance.
downloader.download(url, output_path=None, output_dir=None, **options) -> DownloadTask
Proxy settings passed to Downloader(...) act as defaults. You can override them per task by passing proxy, http_proxy, or https_proxy directly to downloader.download(...).
DownloadTask
Handle to a running download.
task.progress() -> ProgressSnapshot— current download progresstask.pause()— pause the download and persist resume metadata when availabletask.cancel()— cancel the downloadtask.wait()— block until download completes (releases GIL)
wait() consumes the task handle. It cannot be called twice, and progress() is unavailable after it returns or raises.
ProgressSnapshot
Frozen snapshot of download progress.
| Attribute | Type | Description |
|---|---|---|
total_size |
int | None |
Total file size (if known) |
downloaded |
int |
UI-oriented received bytes, not a durable resume offset |
state |
str |
"pending", "downloading", "completed", "failed", "cancelled", "paused" |
speed |
float |
Recent-window speed in bytes/second |
eta_secs |
float | None |
Estimated remaining seconds |
elapsed_secs |
float | None |
Elapsed time in seconds |
downloaded may decrease during retries or already equal total_size when final synchronization fails. Final write or synchronization failures produce failed state, and the control file retains only confirmed durable progress. Use the result or exception from task.wait() to determine success; do not use the displayed byte count as a resume offset.
speed and eta_secs are computed from the same recent throughput window. speed is not a whole-download lifetime average, and eta_secs stays None until bytehaul has enough recent samples or a known total size.
Download options
| Parameter | Type | Default |
|---|---|---|
output_path |
str | Path | None |
None |
output_dir |
str | Path | None |
None |
headers |
dict[str, str] |
{} |
max_connections |
int |
4 |
connect_timeout |
float (secs) |
30.0 |
read_timeout |
float (secs) |
60.0 |
memory_budget |
int |
67108864 |
file_allocation |
"none" | "prealloc" |
"prealloc" |
resume |
bool |
True |
piece_size |
int |
1048576 |
min_split_size |
int |
10485760 |
max_retries |
int |
5 |
retry_base_delay |
float (secs) |
1.0 |
retry_max_delay |
float (secs) |
30.0 |
max_retry_elapsed |
float | None (secs) |
None |
control_save_interval |
float (secs) |
5.0 |
autosave_sync_every |
int |
2 |
max_download_speed |
int |
0 (unlimited) |
checksum_sha256 |
str | None |
None |
log_level |
str | None |
None ("off") |
max_retries counts additional retries after the initial request/transfer attempt; 0 disables retries. Single-connection body failures resume from the writer's flushed contiguous prefix, while Range or object-metadata mismatches reset the file before restarting.
control_save_interval checks whether a checkpoint is due; autosave_sync_every batches those checks when unsaved progress exists. Set log_level on the convenience download(...) function or the Downloader(...) constructor.
Valid log_level values: "off", "error", "warn", "info", "debug", "trace" (case-insensitive).
Contiguous requests
Version 0.2.3 adds request_batch_size to both download
APIs, after existing positional parameters. None or 0 keeps one lease per
request; for example, request_batch_size=4 * 1024 * 1024 groups adjacent pieces
into bounded Range requests. Completion/checkpoint granularity remains
piece_size, with at most 64 leases per batch. Values below a piece do not split
it, and grouping stops at completed/active/partially processed pieces.
Strong-ETag multi-connection transfers can also retain writer-confirmed prefixes on interrupted-body retries or adaptive reassignment. Incomplete pieces remain incomplete across process restarts. These engine behaviors apply to both Python entry points, while the experimental HTTP idle-pool option remains Rust-only.
Slow-transfer recovery
Available starting with version 0.2.2. These options apply to both download(...) and Downloader.download(...); None selects the Rust engine default.
| Parameter | Default | Meaning |
|---|---|---|
slow_transfer_mode |
"adaptive" |
"disabled", "adaptive", or "adaptive_with_hedging" (case-insensitive) |
low_speed_limit |
None |
Optional positive absolute floor, bytes/second |
low_speed_duration |
15.0 |
Sustained low-speed time, seconds |
slow_start_grace |
5.0 |
Startup grace, seconds |
slow_sample_window |
5.0 |
Speed observation window, seconds |
Durations must be finite, positive and at most 86,400 seconds. Adaptive recovery is on by default for multi-connection Range downloads. Hedging is opt-in, needs a strong ETag and a spare connection slot, and stages at most one small spare response before choosing a writer. It does not duplicate progress or exceed max_connections. All network payload shares the configured rate limit. Performance recovery and hedging together reserve at most min(total_size / 100, 16 MiB) of extra Range work; requests that do not fit are skipped. Normal error retries use the existing retry policy.
from bytehaul import Downloader
task = Downloader(log_level="debug").download(
"https://example.com/file.bin",
"file.bin",
slow_transfer_mode="adaptive_with_hedging",
)
task.wait()
Use slow_transfer_mode="disabled" to disable performance-triggered cancellation and hedging. Single-connection and non-Range fallback behavior is unchanged. Recovery excludes intentional rate limiting and local backpressure; it cannot remove a shared origin bandwidth limit.
When max_download_speed is nonzero, automatic slow-request recovery and hedging are suppressed to avoid treating intentional rate limiting as a network fault. Ordinary timeouts and error retries still apply.
Network options
Use these on Downloader(...) to set defaults, or pass proxy, http_proxy, and https_proxy directly to downloader.download(...) or the blocking download(...) helper.
| Parameter | Type | Default |
|---|---|---|
proxy |
str | None |
None |
http_proxy |
str | None |
None |
https_proxy |
str | None |
None |
dns_servers |
list[str] | None |
None |
doh_servers |
list[str] | None |
None |
enable_ipv6 |
bool | None |
True |
Running tests
uv sync --project bindings/python
cd bindings/python
uv run --project . maturin develop -m Cargo.toml
uv run --no-sync --project . pytest tests/ -v
After maturin develop, use --no-sync for tests so uv does not replace the freshly built development extension during another environment sync.
Building wheels for release
Single platform:
cd bindings/python
uv run --project . maturin build --release -m Cargo.toml
Cross-platform (via CI):
# Linux x86_64 + aarch64, macOS x86_64 + arm64, Windows x86_64
# Use maturin's GitHub Actions: https://github.com/PyO3/maturin-action
The project uses abi3-py39, so a single wheel per platform covers all Python 3.9+ versions.
License
MIT. See the repository LICENSE file.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bytehaul-0.2.3.tar.gz.
File metadata
- Download URL: bytehaul-0.2.3.tar.gz
- Upload date:
- Size: 267.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9711de9f9e9678af542a6dbdc3678637a2361b5e497e41704a64189665a693fa
|
|
| MD5 |
900c2686e5bb881d18922e0255f1b959
|
|
| BLAKE2b-256 |
baf40e53deaba4f41a468901caa783be62bece9239c60d34da1a11350867379d
|
Provenance
The following attestation bundles were made for bytehaul-0.2.3.tar.gz:
Publisher:
publish-pypi.yml on triwinds/bytehaul
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bytehaul-0.2.3.tar.gz -
Subject digest:
9711de9f9e9678af542a6dbdc3678637a2361b5e497e41704a64189665a693fa - Sigstore transparency entry: 2770360224
- Sigstore integration time:
-
Permalink:
triwinds/bytehaul@b7d549af16769fdc437860f59efa5a32a37ac7f3 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/triwinds
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@b7d549af16769fdc437860f59efa5a32a37ac7f3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file bytehaul-0.2.3-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: bytehaul-0.2.3-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 3.0 MB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a0fa8b7afbf7d6d322c69beacfb5d6e15181ea8a72d63ece0c42f6c6b2ec0068
|
|
| MD5 |
9f548c0f29334ad27c53002dd3b7670a
|
|
| BLAKE2b-256 |
fd90a63fc9743dcf6a5b8dd765ec319e394e2d4fef9e9bcd2666f670601ec3a7
|
Provenance
The following attestation bundles were made for bytehaul-0.2.3-cp39-abi3-win_amd64.whl:
Publisher:
publish-pypi.yml on triwinds/bytehaul
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bytehaul-0.2.3-cp39-abi3-win_amd64.whl -
Subject digest:
a0fa8b7afbf7d6d322c69beacfb5d6e15181ea8a72d63ece0c42f6c6b2ec0068 - Sigstore transparency entry: 2770360284
- Sigstore integration time:
-
Permalink:
triwinds/bytehaul@b7d549af16769fdc437860f59efa5a32a37ac7f3 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/triwinds
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@b7d549af16769fdc437860f59efa5a32a37ac7f3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file bytehaul-0.2.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: bytehaul-0.2.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 3.5 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c02c734f85a2cee27c8ebbc4158193df522f57e36f4c75bbae526b4cb698bf6
|
|
| MD5 |
6487ee23c84ea9113798d858e8ea6fd2
|
|
| BLAKE2b-256 |
c56fbc29b0d2969ad507d2922da9d8b0cf9278ea5d4f59ec0a7a74c41e861116
|
Provenance
The following attestation bundles were made for bytehaul-0.2.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
publish-pypi.yml on triwinds/bytehaul
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bytehaul-0.2.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
5c02c734f85a2cee27c8ebbc4158193df522f57e36f4c75bbae526b4cb698bf6 - Sigstore transparency entry: 2770360419
- Sigstore integration time:
-
Permalink:
triwinds/bytehaul@b7d549af16769fdc437860f59efa5a32a37ac7f3 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/triwinds
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@b7d549af16769fdc437860f59efa5a32a37ac7f3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file bytehaul-0.2.3-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: bytehaul-0.2.3-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 3.1 MB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23267a5805146e51bf73e83322a61c5c0a18afc261af267d99f8cb46aca78a88
|
|
| MD5 |
c380bdb1494c32f617a4b877ace7b56f
|
|
| BLAKE2b-256 |
e064a630aadd2338a192bee523cd3394bb75ca56242fcff2d0d9bf960bcdb22c
|
Provenance
The following attestation bundles were made for bytehaul-0.2.3-cp39-abi3-macosx_11_0_arm64.whl:
Publisher:
publish-pypi.yml on triwinds/bytehaul
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bytehaul-0.2.3-cp39-abi3-macosx_11_0_arm64.whl -
Subject digest:
23267a5805146e51bf73e83322a61c5c0a18afc261af267d99f8cb46aca78a88 - Sigstore transparency entry: 2770360477
- Sigstore integration time:
-
Permalink:
triwinds/bytehaul@b7d549af16769fdc437860f59efa5a32a37ac7f3 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/triwinds
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@b7d549af16769fdc437860f59efa5a32a37ac7f3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file bytehaul-0.2.3-cp39-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: bytehaul-0.2.3-cp39-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 3.2 MB
- Tags: CPython 3.9+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34fc1ac6a6991eae98ec16b684eccdac96ac7b5b0f0e1dda391745a461609208
|
|
| MD5 |
9ccb9adef5c73ae08b389a4b2695ea5b
|
|
| BLAKE2b-256 |
6689d48cb2f5dbfebc499f9a81326ef40a92f616069956731596652b2bcb1aa2
|
Provenance
The following attestation bundles were made for bytehaul-0.2.3-cp39-abi3-macosx_10_12_x86_64.whl:
Publisher:
publish-pypi.yml on triwinds/bytehaul
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bytehaul-0.2.3-cp39-abi3-macosx_10_12_x86_64.whl -
Subject digest:
34fc1ac6a6991eae98ec16b684eccdac96ac7b5b0f0e1dda391745a461609208 - Sigstore transparency entry: 2770360371
- Sigstore integration time:
-
Permalink:
triwinds/bytehaul@b7d549af16769fdc437860f59efa5a32a37ac7f3 -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/triwinds
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@b7d549af16769fdc437860f59efa5a32a37ac7f3 -
Trigger Event:
push
-
Statement type: