Metadata-Version: 2.4
Name: lexigram-storage
Version: 0.1.1
Summary: Unified blob storage abstraction for Lexigram Framework - S3, GCS, Azure Blob, and local filesystem
Project-URL: Homepage, https://github.com/lexigram-dev/lexigram
Project-URL: Repository, https://github.com/lexigram-dev/lexigram
Project-URL: Documentation, https://docs.lexigram.dev/storage
Project-URL: Issues, https://github.com/lexigram-dev/lexigram/issues
Project-URL: Changelog, https://github.com/lexigram-dev/lexigram/blob/main/CHANGELOG.md
Author-email: Lexigram Framework Team <team@lexigram.dev>
Maintainer-email: Lexigram Framework Team <team@lexigram.dev>
License: MIT
License-File: LICENSE
Keywords: async,azure,blob,filesystem,framework,gcs,s3,storage
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Filesystems
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: aiofiles>=23.0.0
Requires-Dist: jinja2>=3.1.0
Requires-Dist: lexigram-contracts>=0.1.0
Requires-Dist: lexigram>=0.1.1
Requires-Dist: python-magic>=0.4.27
Provides-Extra: all
Requires-Dist: aiobotocore>=2.0.0; extra == 'all'
Requires-Dist: azure-storage-blob>=12.0.0; extra == 'all'
Requires-Dist: gcloud-aio-storage>=9.0.0; extra == 'all'
Requires-Dist: lexigram-testing>=0.1.1; extra == 'all'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'all'
Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
Requires-Dist: pytest-mock>=3.10.0; extra == 'all'
Requires-Dist: pytest>=8.0.0; extra == 'all'
Requires-Dist: types-aiobotocore[s3]>=2.0.0; extra == 'all'
Provides-Extra: aws
Requires-Dist: aiobotocore>=2.0.0; extra == 'aws'
Requires-Dist: types-aiobotocore[s3]>=2.0.0; extra == 'aws'
Provides-Extra: azure
Requires-Dist: azure-storage-blob>=12.0.0; extra == 'azure'
Provides-Extra: dev
Requires-Dist: black>=23.0.0; extra == 'dev'
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Provides-Extra: gcp
Requires-Dist: gcloud-aio-storage>=9.0.0; extra == 'gcp'
Provides-Extra: test
Requires-Dist: lexigram-testing>=0.1.1; extra == 'test'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'test'
Requires-Dist: pytest-cov>=4.0.0; extra == 'test'
Requires-Dist: pytest-mock>=3.10.0; extra == 'test'
Requires-Dist: pytest>=8.0.0; extra == 'test'
Description-Content-Type: text/markdown

# lexigram-storage

Unified blob storage abstraction for Lexigram Framework — S3, GCS, Azure Blob, and local filesystem

---

## Overview

lexigram-storage provides a unified `BlobStore` interface over Amazon S3, Google Cloud Storage, Azure Blob Storage, Cloudflare R2, and local disk — with signed URLs, streaming uploads, content-type negotiation, and server-side encryption. All services are wired via `StorageProvider`, which registers the blob store protocol with the DI container.

---

## Install

```bash
uv add lexigram-storage
# Optional extras
uv add "lexigram-storage[s3]"     # Amazon S3 (aiobotocore)
uv add "lexigram-storage[gcp]"    # Google Cloud Storage
uv add "lexigram-storage[azure]"  # Azure Blob Storage
```

## Quick Start

```python
from lexigram import Application
from lexigram.di.module import Module, module

# Import the module from the package
from lexigram.storage import StorageModule

@module(imports=[StorageModule.configure(...)])
class AppModule(Module):
    pass

app = Application(modules=[AppModule])
if __name__ == "__main__":
    app.run()
```

## Configuration

> **Zero-config usage:** Call `StorageModule.configure()` with no arguments to use defaults.

### Option 1 — YAML file

```yaml
# application.yaml
storage:
  default_driver: "s3"
  drivers:
    s3:
      bucket: "my-app-uploads"
      region: "us-east-1"
      access_key: "${AWS_ACCESS_KEY_ID}"
      secret_key: "${AWS_SECRET_ACCESS_KEY}"
```

### Option 2 — Profiles + Environment Variables *(recommended)*

```bash
export LEX_STORAGE__ENABLED=true
# Environment variables for each field
```

### Option 3 — Python

```python
from lexigram.storage.config import StorageConfig
from lexigram.storage import StorageModule

config = StorageConfig(default_driver="s3", ...)
StorageModule.configure(config)
```

### Config reference

| Field | Default | Env var | Description |
|-------|---------|---------|-------------|
| `default_driver` | `"local"` | `LEX_STORAGE__DEFAULT_DRIVER` | Active driver: `s3`, `gcs`, `azure`, `r2`, `local`, `memory` |
| `drivers.s3.bucket` | — | `LEX_STORAGE__DRIVERS__S3__BUCKET` | S3 bucket name |
| `drivers.s3.region` | `"us-east-1"` | `LEX_STORAGE__DRIVERS__S3__REGION` | AWS region |
| `drivers.s3.access_key` | — | `LEX_STORAGE__DRIVERS__S3__ACCESS_KEY` | AWS access key ID |
| `drivers.s3.secret_key` | — | `LEX_STORAGE__DRIVERS__S3__SECRET_KEY` | AWS secret access key |
| `drivers.s3.endpoint_url` | `null` | `LEX_STORAGE__DRIVERS__S3__ENDPOINT_URL` | Override endpoint (MinIO, LocalStack) |
| `drivers.gcs.bucket` | — | `LEX_STORAGE__DRIVERS__GCS__BUCKET` | GCS bucket name |
| `drivers.gcs.credentials_path` | — | `LEX_STORAGE__DRIVERS__GCS__CREDENTIALS_PATH` | Path to service account JSON |
| `drivers.azure.account_name` | — | `LEX_STORAGE__DRIVERS__AZURE__ACCOUNT_NAME` | Azure storage account name |
| `drivers.azure.container` | — | `LEX_STORAGE__DRIVERS__AZURE__CONTAINER` | Azure blob container |
| `drivers.local.root_dir` | — | `LEX_STORAGE__DRIVERS__LOCAL__ROOT_DIR` | Root directory for local storage |
| `service.max_file_size_mb` | `100` | `LEX_STORAGE__SERVICE__MAX_FILE_SIZE_MB` | Maximum upload size in MB |

## Module Factory Methods

| Method | Description |
|--------|-------------|
| `StorageModule.configure(config, enable_encryption)` | Configure with explicit StorageConfig |
| `StorageModule.stub()` | Minimal config for testing |

## Key Features

- **S3** — Multi-part upload, server-side encryption, lifecycle rules
- **GCS** — Resumable uploads, CMEK, uniform bucket-level access
- **Azure** — Block blobs, shared access signatures (SAS), CDN integration
- **R2** — Cloudflare R2 (S3-compatible) support
- **Local driver** — On-disk storage for development and CI
- **Memory driver** — In-process storage for unit tests
- **Signed URLs** — Time-limited GET / PUT pre-signed URLs for direct browser upload
- **Content negotiation** — Automatic MIME type detection from extension and magic bytes
- **Key-value store** — Lightweight `KVStore` for small blobs (config, flags)
- **Streaming** — `put_stream()` / `get_stream()` for arbitrarily large files

## Testing

```python
async with Application.boot(modules=[StorageModule.stub()]) as app:
    # your test code
    ...
```

## Key Source Files

| File | What it contains |
|------|----------------|
| `src/lexigram/storage/module.py` | `StorageModule` class with factory methods |
| `src/lexigram/storage/di/provider.py` | `StorageProvider` — wires storage protocols into DI container |
| `src/lexigram/storage/config.py` | `StorageConfig` and sub-config classes |
| `src/lexigram/storage/drivers/` | Driver implementations (S3, GCS, Azure, R2, local, memory) |
| `src/lexigram/storage/blob.py` | `BlobStore` interface implementation |