Skip to main content

Simple functions for working with S3

Project description

s3func

Simple functions for working with S3-compatible object storage

build codecov PyPI version


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 S3Session for 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=True in the session (default) or individual requests to handle large files without loading them entirely into memory.
  • Adaptive Retries: The library uses urllib3 retry 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):

  1. Acquisition: A worker writes two small ticket objects (seq-0 and seq-1).
  2. 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).
  3. Election: it lists all tickets and yields to older ones (seq-1 timestamp; lexicographic lock_id breaks ties). Shared tickets yield only to older exclusive tickets.
  4. 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.
  5. 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 via lock_id= restores the ticket only - acquire() re-runs the election.
  6. Auto-Cleanup: weakref.finalize deletes 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

s3func-0.9.1.tar.gz (39.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

s3func-0.9.1-py3-none-any.whl (46.2 kB view details)

Uploaded Python 3

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

Hashes for s3func-0.9.1.tar.gz
Algorithm Hash digest
SHA256 76c19bd8f0410b86668d13b43384554d06b9653c5e6f45dd64f1556de3383938
MD5 bd5e3223c236417ffa5e0e8f0bdd19c4
BLAKE2b-256 e2da8b4104d401131d90399f293a759f11214e69c935b8f7b400eb8f6d2d820a

See more details on using hashes here.

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

Hashes for s3func-0.9.1-py3-none-any.whl
Algorithm Hash digest
SHA256 39b73cddbe34604b479508d7332a9e53c1af2b1489dbc31880e1bde3ca24f47e
MD5 5459e7d430cd70a88cc31dadf958f5eb
BLAKE2b-256 44cb206f7d65945d8e947d32bc66e655ae07ed74dbf3af4f3a447b761f77471f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page