English | νκ΅μ΄
A Python implementation of the TUS resumable upload protocol v1.0.0 for server and client, with zero runtime dependencies.
- π Zero Dependencies: Built using Python standard library only (no external dependencies for core functionality)
- π¦ Server & Client: Complete implementation of both sides
- π Resume Capability: Automatically resume interrupted uploads
- β Data Integrity: Optional SHA1 checksum verification
- π Retry Logic: Built-in automatic retry with exponential backoff
- π Progress Tracking: Detailed upload progress callbacks with stats
- π Web Framework Support: Integration examples for Flask, FastAPI, and Django
- π Python 3.9+: Supports Python 3.9 through 3.14
- πͺ Storage Backend: SQLite-based storage (extensible to other backends)
- π TLS Support: Certificate verification control and mTLS authentication
- π URL Storage: Persist upload URLs across sessions
- π― TUS Protocol Compliant: Implements TUS v1.0.0 core protocol with creation, termination, and checksum extensions
# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install the package
uv pip install resumable-uploadpip install resumable-uploadfrom http.server import HTTPServer
from resumable_upload import TusServer, TusHTTPRequestHandler, SQLiteStorage
# Create storage backend
storage = SQLiteStorage(db_path="uploads.db", upload_dir="uploads")
# Create TUS server
tus_server = TusServer(storage=storage, base_path="/files")
# Create HTTP handler
class Handler(TusHTTPRequestHandler):
pass
Handler.tus_server = tus_server
# Start server
server = HTTPServer(("0.0.0.0", 8080), Handler)
print("Server running on http://localhost:8080")
server.serve_forever()from resumable_upload import TusClient
# Create client
client = TusClient("http://localhost:8080/files")
# Upload file with progress callback
from resumable_upload import UploadStats
def progress(stats: UploadStats):
print(f"Progress: {stats.progress_percent:.1f}% | "
f"{stats.uploaded_bytes}/{stats.total_bytes} bytes | "
f"Speed: {stats.upload_speed_mbps:.2f} MB/s")
upload_url = client.upload_file(
"large_file.bin",
metadata={"filename": "large_file.bin"},
progress_callback=progress
)
print(f"Upload complete: {upload_url}")Pick any subset of sha1, sha256, sha512, md5 to advertise and validate:
TusServer(storage=..., checksum_algorithms=("sha1", "sha256"))Client picks which one to send:
TusClient("...", checksum="sha256")Observability + domain-specific retry gating:
def before(method, url, headers): print(f"-> {method} {url}")
def after(method, url, status): print(f"<- {method} {status}")
def should_retry(err, attempt): return not isinstance(err, PermissionError)
client = TusClient(
"...",
before_request=before,
after_response=after,
on_should_retry=should_retry,
)Three URL-storage backends ship (all implement the same URLStorage ABC):
FileURLStorageβ durable JSON file, multi-process safe via flockSQLiteURLStorageβ durable DB, recommended for multi-process clientsInMemoryURLStorageβ fast, non-durable (tests, short sessions)
Look up a resumable upload by file:
previous = client.find_previous_uploads("big.bin")
if previous:
client.resume_upload("big.bin", previous[0]["upload_url"])Mount a TUS server as an ASGI application:
from fastapi import FastAPI
from resumable_upload import SQLiteStorage, TusServer
from resumable_upload.asgi import TusASGIApp
app = FastAPI()
tus = TusServer(storage=SQLiteStorage(), base_path="/files")
app.mount("/files", TusASGIApp(tus))The adapter runs the synchronous TusServer.handle_request on a thread pool via asyncio.to_thread, so the event loop stays free.
Run a TUS server from the shell without writing any Python:
# Console script (installed via pip/uv)
resumable-upload serve --host 0.0.0.0 --port 8080 --upload-dir ./uploads
# Or via module invocation
python -m resumable_upload serve --port 8080Flags: --host, --port, --base-path, --upload-dir, --db-path, --max-size, --max-chunk-size, --upload-expiry, --cors-origin, --log-level. Run resumable-upload serve --help for details.
For large files over high-bandwidth connections, split the file into N concurrent partial uploads and merge them server-side via the concatenation extension:
client = TusClient("http://localhost:8080/files", chunk_size=1024 * 1024)
url = client.upload_file("large.bin", parallel_uploads=4)Requires a server that implements the TUS concatenation extension (this library does). Compatible with tus-js-client's parallelUploads option.
For advanced workflows (e.g., resumable uploads split across devices or sessions), use the partial / final primitives directly:
url1 = client.create_partial_upload("part1.bin")
url2 = client.create_partial_upload("part2.bin")
final_url = client.create_final_upload(
partial_urls=[url1, url2],
metadata={"filename": "merged.bin"},
)For detailed guides see the Advanced Usage section on the docs site:
- Automatic retry with exponential backoff and
on_should_retrygating β Retry & Error Handling - Resume interrupted uploads (in-session and cross-session) β Resume & Partial Uploads
- Concatenation extension and
parallel_uploads=Nβ Concatenation & Parallel Uploads - Tracing and retry hooks β Observability & Retry Gating
- Low-level chunk control via
Uploader+ cancellation withstop_eventβ Low-Level Uploader - Web framework integration: Flask, FastAPI, Django, generic ASGI
- Operations: CLI, Metrics, Distributed Locks
Full API documentation is available on the docs site: Client, Server, Storage, Exceptions & Utilities.
| Class | Import | Purpose |
|---|---|---|
TusClient |
from resumable_upload import TusClient |
Upload files via TUS protocol |
TusServer |
from resumable_upload import TusServer |
Serve TUS uploads (framework-agnostic) |
TusHTTPRequestHandler |
from resumable_upload import TusHTTPRequestHandler |
Handler for Python's built-in HTTPServer |
SQLiteStorage |
from resumable_upload import SQLiteStorage |
SQLite + filesystem storage backend |
FileURLStorage |
from resumable_upload import FileURLStorage |
JSON file-based URL persistence |
Uploader |
from resumable_upload.client.uploader import Uploader |
Low-level chunk-by-chunk control |
TusClient: url, chunk_size (default 1 MB), checksum (SHA1, default True), max_retries (default 3), retry_delay (default 1.0s, exponential backoff capped at 60s), timeout (default 30s), store_url / url_storage (cross-session resume), verify_tls_cert, headers
TusServer: storage, base_path (default /files), max_size, upload_expiry, cors_allow_origins, request_timeout (default 30s β Slowloris protection)
SQLiteStorage: db_path (default uploads.db), upload_dir (default uploads) β thread-safe via per-upload lock; process-safe via fcntl.flock
FileURLStorage: storage_path (default .tus_urls.json) β thread-safe via threading.Lock; process-safe via fcntl.flock
This library implements TUS protocol v1.0.0. Full compliance details: TUS Compliance.
| Extension | Status |
|---|---|
| core | β Implemented |
| creation | β Implemented |
| creation-with-upload | β Implemented |
| termination | β Implemented |
| checksum | β Implemented (SHA1) |
| expiration | β Implemented |
| concatenation | β Implemented (SQLite / S3 / GCS / Azure) |
Note: TUS
Upload-Checksumuses SHA1 as required by the spec. The internal client-side fingerprint for cross-session resume uses SHA-256 and is not part of the TUS protocol.
| Feature | Status |
|---|---|
X-HTTP-Method-Override |
β Implemented β POST rewrites to PATCH/DELETE/HEAD for environments that block those methods |
# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create virtual environment and install dependencies
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install all dependencies (dev and test)
make install
# Run minimal tests (excluding web frameworks)
make test-minimal
# Run all tests (including web frameworks)
make test
# Or use Makefile for convenience
make lint # Run linting
make format # Format code
make test-minimal # Run minimal tests
make test # Run all tests
make test-all-versions # Test on all Python versions (3.9-3.14) - requires tox
make ci # Run full CI checks (lint + format + test)- Docs site: sts07142.github.io/resumable-upload
- English README: README.md
- νκ΅μ΄ README: README.ko.md
- Advanced Usage: advanced-usage/retry
- Full API Reference: api-reference/client
- TUS Protocol Compliance: compliance
Contributions are welcome! Please check out the Contributing Guide for guidelines.
MIT License - see LICENSE file for details.
This library is inspired by the official TUS Python client and implements the TUS resumable upload protocol.
- π« Issues: GitHub Issues
- π Documentation: sts07142.github.io/resumable-upload
- π Star us on GitHub!