Skip to content

sts07142/resumable-upload

Resumable Upload

Python Version PyPI Version License

English | ν•œκ΅­μ–΄

A Python implementation of the TUS resumable upload protocol v1.0.0 for server and client, with zero runtime dependencies.

✨ Features

  • πŸš€ 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

πŸ“¦ Installation

Using uv (Recommended)

# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install the package
uv pip install resumable-upload

Using pip

pip install resumable-upload

πŸš€ Quick Start

Basic Server

from 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()

Basic Client

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}")

Checksum algorithms

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")

Client hooks and URL storage

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 flock
  • SQLiteURLStorage β€” durable DB, recommended for multi-process clients
  • InMemoryURLStorage β€” 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"])

ASGI (FastAPI, Starlette, Quart, etc.)

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.

Command-line Server

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 8080

Flags: --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.

Parallel chunk uploads

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.

Manual partial / final control

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"},
)

πŸ”§ Advanced Usage

For detailed guides see the Advanced Usage section on the docs site:

πŸ“š API Reference

Full API documentation is available on the docs site: Client, Server, Storage, Exceptions & Utilities.

Quick Reference

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

Key Parameters

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

πŸ” TUS Protocol Compliance

This library implements TUS protocol v1.0.0. Full compliance details: TUS Compliance.

Extensions

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-Checksum uses 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.

Non-standard but supported

Feature Status
X-HTTP-Method-Override βœ… Implemented β€” POST rewrites to PATCH/DELETE/HEAD for environments that block those methods

πŸ§ͺ Testing

Using uv (Recommended)

# 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)

πŸ“– Documentation

🀝 Contributing

Contributions are welcome! Please check out the Contributing Guide for guidelines.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

This library is inspired by the official TUS Python client and implements the TUS resumable upload protocol.

πŸ“ž Support

About

A Python implementation of the [TUS resumable upload protocol](https://tus.io/) v1.0.0 for server and client, with zero runtime dependencies.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors