Simple functions for working with S3
Project description
s3func
Simple functions for working with S3-compatible object storage
s3func is a lightweight Python library providing a simplified interface for interacting with S3-compatible object storage services (AWS S3, Backblaze B2, MEGA S4, and others). It removes the boto3 dependency in favor of a fast, urllib3-based client with custom SigV4 signing.
Key Features
- Zero Boto3 Dependency: Minimal overhead and faster imports.
- Provider-Agnostic: One
S3Sessionfor AWS S3 and any S3-compatible provider (Backblaze B2, MEGA S4, ...), with provider quirks handled portably (strict RFC3986 signing of paths and queries). - Distributed Locking: Verified shared/exclusive locking on plain object storage - no CAS required (see docs/locking.md).
- Streaming Support: Efficiently stream large objects.
- Automatic Retries: Built-in adaptive retry logic for transient network issues.
Installation
pip install s3func
Usage Examples
S3 Operations
from s3func import S3Session
# Initialize session for AWS S3
session = S3Session(
access_key_id='YOUR_ACCESS_KEY',
access_key='YOUR_SECRET_KEY',
bucket='my-bucket',
region='us-east-1'
)
# Also works with other S3-compatible providers (Contabo, Wasabi, DigitalOcean, etc.)
# by providing an endpoint_url.
session = S3Session(
access_key_id='YOUR_ACCESS_KEY',
access_key='YOUR_SECRET_KEY',
bucket='my-bucket',
endpoint_url='https://eu2.contabostorage.com'
)
# Upload an object
session.put_object('hello.txt', b'Hello, S3!')
# Download an object
resp = session.get_object('hello.txt')
print(resp.data.decode())
# List objects
for obj in session.list_objects(prefix='logs/').iter_objects():
print(obj['key'], obj['content_length'])
Custom Metadata
You can easily read and write custom metadata headers.
# Upload with metadata
session.put_object(
'data.csv',
b'col1,col2\n1,2',
metadata={'processed': 'false', 'source': 'sensor-1'}
)
# Read metadata
resp = session.head_object('data.csv')
print(resp.metadata['processed']) # 'false'
Distributed Locking
s3func provides a powerful distributed lock that mimics Python's threading.Lock API.
# Using S3 Lock via context manager
with session.lock('process-1'):
# This block is protected by a distributed lock
print("Doing some exclusive work...")
# Explicit acquire/release with timeout
lock = session.lock('my-resource')
if lock.acquire(blocking=True, timeout=10):
try:
# Perform operation
pass
finally:
lock.release()
Performance Tips
- Streaming: Set
stream=Truein the session (default) or individual requests to handle large files without loading them entirely into memory. - Adaptive Retries: The library uses
urllib3retry logic configured for high-concurrency environments to handle rate limiting and network blips automatically.
How Distributed Locking Works
Full walk-through with diagrams: docs/locking.md.
The lock is a Lamport-bakery-style election over plain object storage (no compare-and-swap needed):
- Acquisition: A worker writes two small ticket objects (
seq-0andseq-1). - Self-visibility gate (0.9.0): it polls the listing until its OWN ticket is
visible - a listing that cannot show your own writes cannot be trusted to show
competitors (raises after
visibility_timeout, default 30s). - Election: it lists all tickets and yields to older ones (
seq-1timestamp; lexicographiclock_idbreaks ties). Shared tickets yield only to older exclusive tickets. - Confirming re-list (0.9.0): winning requires a second clear listing taken
settle_delay(default 1.0s) later - a violation now needs two independent stale listings. - Own-ticket invariant (0.9.0): every decisive listing must still contain the
worker's own ticket; if another client deleted it (e.g.
break_other_locks), acquisition raises instead of "winning" without a ticket. Recovering a ticket vialock_id=restores the ticket only -acquire()re-runs the election. - Auto-Cleanup:
weakref.finalizedeletes ticket objects even if the process exits unexpectedly (best effort).
Guarantee and residual window: on storage with strongly consistent listings the
election is safe. On eventually-consistent listings the hardening reduces the
failure mode to two consecutive independently-stale listings (measured on B2:
80/80 listings were first-poll consistent - see benchmarks/results_visibility_lag.md).
No provider we tested currently offers atomic conditional writes
(benchmarks/conditional_write_probe.py is the qualification gate for adding a
true CAS lock per provider; MEGA S4 accepts the headers but is not atomic under
concurrency). Tune via session.lock(key, settle_delay=..., visibility_timeout=...).
Development
Setup environment
We use uv to manage the development environment and production build.
uv sync --all-extras --dev
Running Tests
uv run pytest
License
This project is licensed under the terms of the Apache Software License 2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 s3func-0.9.1.tar.gz.
File metadata
- Download URL: s3func-0.9.1.tar.gz
- Upload date:
- Size: 39.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76c19bd8f0410b86668d13b43384554d06b9653c5e6f45dd64f1556de3383938
|
|
| MD5 |
bd5e3223c236417ffa5e0e8f0bdd19c4
|
|
| BLAKE2b-256 |
e2da8b4104d401131d90399f293a759f11214e69c935b8f7b400eb8f6d2d820a
|
File details
Details for the file s3func-0.9.1-py3-none-any.whl.
File metadata
- Download URL: s3func-0.9.1-py3-none-any.whl
- Upload date:
- Size: 46.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
39b73cddbe34604b479508d7332a9e53c1af2b1489dbc31880e1bde3ca24f47e
|
|
| MD5 |
5459e7d430cd70a88cc31dadf958f5eb
|
|
| BLAKE2b-256 |
44cb206f7d65945d8e947d32bc66e655ae07ed74dbf3af4f3a447b761f77471f
|