From 84f4f65cc0df26303161e2cae23ed02535fb2377 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 02:30:11 +0000 Subject: [PATCH 1/3] docs: thin out README by moving detailed tables to docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created comprehensive docs/stores.md with all store information - Added summary tables to docs/wrappers.md and docs/adapters.md - Added DataclassAdapter documentation to adapters.md - Updated README to have concise overviews with links to full docs - Updated mkdocs.yml navigation to include stores.md The README now provides a good overview while linking to detailed documentation for stores, wrappers, and adapters, reducing duplication and making the documentation easier to maintain. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: William Easton --- README.md | 127 +++-------- docs/adapters.md | 55 ++++- docs/stores.md | 579 +++++++++++++++++++++++++++++++++++++++++++++++ docs/wrappers.md | 22 ++ mkdocs.yml | 1 + 5 files changed, 690 insertions(+), 94 deletions(-) create mode 100644 docs/stores.md diff --git a/README.md b/README.md index f32f4eb0..9b9d6e74 100644 --- a/README.md +++ b/README.md @@ -184,81 +184,34 @@ ttl_many(keys: list[str], collection: str | None = None) -> list[tuple[dict[str, ### Stores -The library provides a variety of stores that implement the protocol. +The library provides multiple store implementations organized into three +categories: -A ✅ means a store is available, a ☑️ under async means a store is available -but the underlying implementation is synchronous. A ✖️ means a store is -not available. +- **Local stores**: In-memory and disk-based storage (Memory, Disk, RocksDB, etc.) +- **Secret stores**: Secure OS-level storage for sensitive data (Keyring, Vault) +- **Distributed stores**: Network-based storage for multi-node apps (Redis, + DynamoDB, MongoDB, etc.) -Stability is a measure of the likelihood that the way data is stored will change -in a backwards incompatible way. +Each store has a **stability rating** indicating likelihood of +backwards-incompatible changes. Stable stores (Redis, Valkey, Disk, Keyring) +are recommended for long-term storage. -- A stable store is one we do not intend to change in a backwards incompatible way. -- A preview store is one that is unlikely to change in a backwards incompatible way. -- An unstable store is one that is likely to change in a backwards incompatible way. - -If you are using py-key-value-aio for caching, stability may not be a concern for -you. If you are using py-key-value-aio for long-term storage, stability is a -concern and you should consider using a stable store. - -#### Local stores - -Local stores are stored in memory or on disk, local to the application. - -| Local Stores | Stability | Async | Sync | Example | -|------------------|:---------:|:-----:|:----:|:-------| -| Memory | N/A | ✅ | ✅ | `MemoryStore()` | -| Disk | Stable | ☑️ | ✅ | `DiskStore(directory="./cache")` | -| Disk (Per-Collection) | Stable | ☑️ | ✅ | `MultiDiskStore(directory="./cache")` | -| Null (test) | N/A | ✅ | ✅ | `NullStore()` | -| RocksDB | Unstable | ☑️ | ✅ | `RocksDBStore(path="./rocksdb")` | -| Simple (test) | N/A | ✅ | ✅ | `SimpleStore()` | -| Windows Registry | Unstable | ☑️ | ✅ | `WindowsRegistryStore(hive="HKEY_CURRENT_USER", registry_path="Software\\py-key-value")` | - -#### Local - Secret stores - -Secret stores are stores that are used to store sensitive data, typically in -an Operating System's secret store. - -| Secret Stores | Stability | Async | Sync | Example | -|---------------|:---------:|:-----:|:----:|:-------| -| Keyring | Stable | ✅ | ✅ | `KeyringStore(service_name="py-key-value")` | -| Vault | Unstable | ✅ | ✅ | `VaultStore(url="http://localhost:8200", token="your-token")` | - -Note: The Windows Keyring has strict limits on the length of values which may -cause issues with large values. - -#### Distributed stores - -Distributed stores are stores that are used to store data in a distributed -system, for access across multiple application nodes. - -| Distributed Stores | Stability | Async | Sync | Example | -|------------------|:---------:|:-----:|:----:|:-------| -| DynamoDB | Unstable | ✅ | ✖️ | `DynamoDBStore(table_name="kv-store", region_name="us-east-1")` | -| Elasticsearch | Unstable | ✅ | ✅ | `ElasticsearchStore(url="https://localhost:9200", api_key="your-api-key", index="kv-store")` | -| Memcached | Unstable | ✅ | ✖️ | `MemcachedStore(host="127.0.0.1", port=11211")` | -| MongoDB | Unstable | ✅ | ✅ | `MongoDBStore(url="mongodb://localhost:27017/test")` | -| Redis | Stable | ✅ | ✅ | `RedisStore(url="redis://localhost:6379/0")` | -| Valkey | Stable | ✅ | ✅ | `ValkeyStore(host="localhost", port=6379)` | +**[📚 View all stores, installation guides, and examples →](https://strawgate.github.io/py-key-value/stores/)** ### Adapters -Adapters "wrap" any protocol-compliant store but do not themselves implement -the protocol. +Adapters provide specialized interfaces for working with stores. Unlike wrappers, +they don't implement the protocol but instead offer alternative APIs for specific +use cases: -They simplify your applications interactions with stores and provide additional -functionality. While your application will accept an instance that implements -the protocol, your application code might be simplified by using an adapter. +- **DataclassAdapter**: Type-safe dataclass storage with automatic validation +- **PydanticAdapter**: Type-safe Pydantic model storage with serialization +- **RaiseOnMissingAdapter**: Raise exceptions instead of returning None for + missing keys -| Adapter | Description | Example | -|---------|:------------|:------------------| -| DataclassAdapter | Type-safe storage/retrieval of dataclass models with transparent serialization/deserialization. | `DataclassAdapter(key_value=memory_store, dataclass_type=User)` | -| PydanticAdapter | Type-safe storage/retrieval of Pydantic models with transparent serialization/deserialization. | `PydanticAdapter(key_value=memory_store, pydantic_model=User)` | -| RaiseOnMissingAdapter | Optional raise-on-missing behavior for `get`, `get_many`, `ttl`, and `ttl_many`. | `RaiseOnMissingAdapter(key_value=memory_store)` | +**[📚 View all adapters with examples →](https://strawgate.github.io/py-key-value/adapters/)** -For example, the PydanticAdapter allows you to store and retrieve Pydantic -models with transparent serialization/deserialization: +**Quick example** - PydanticAdapter for type-safe storage: ```python import asyncio @@ -298,33 +251,21 @@ asyncio.run(example()) ### Wrappers -The library provides a wrapper pattern for adding functionality to a store. -Wrappers themselves implement the protocol meaning that you can wrap any store -with any wrapper, and chain wrappers together as needed. - -The following wrappers are available: - -| Wrapper | Description | Example | -|---------|---------------|-----| -| CollectionRoutingWrapper | Route operations to different stores based on a collection name. | `CollectionRoutingWrapper(collection_map={"sessions": redis_store, "users": dynamo_store}, default_store=memory_store)` | -| CompressionWrapper | Compress values before storing and decompress on retrieval. | `CompressionWrapper(key_value=memory_store, min_size_to_compress=0)` | -| DefaultValueWrapper | Return a default value when key is missing. | `DefaultValueWrapper(key_value=memory_store, default_value={})` | -| FernetEncryptionWrapper | Encrypt values before storing and decrypt on retrieval. | `FernetEncryptionWrapper(key_value=memory_store, source_material="your-source-material", salt="your-salt")` | -| FallbackWrapper | Fallback to a secondary store when the primary store fails. | `FallbackWrapper(primary_key_value=memory_store, fallback_key_value=memory_store)` | -| LimitSizeWrapper | Limit the size of entries stored in the cache. | `LimitSizeWrapper(key_value=memory_store, max_size=1024, raise_on_too_large=True)` | -| LoggingWrapper | Log the operations performed on the store. | `LoggingWrapper(key_value=memory_store, log_level=logging.INFO, structured_logs=True)` | -| PassthroughCacheWrapper | Wrap two stores to provide a read-through cache. | `PassthroughCacheWrapper(primary_key_value=memory_store, cache_key_value=memory_store)` | -| PrefixCollectionsWrapper | Prefix all collections with a given prefix. | `PrefixCollectionsWrapper(key_value=memory_store, prefix="users")` | -| PrefixKeysWrapper | Prefix all keys with a given prefix. | `PrefixKeysWrapper(key_value=memory_store, prefix="users")` | -| ReadOnlyWrapper | Prevent all write operations on the underlying store. | `ReadOnlyWrapper(key_value=memory_store, raise_on_write=True)` | -| RetryWrapper | Retry failed operations with exponential backoff. | `RetryWrapper(key_value=memory_store, max_retries=3, initial_delay=0.1, max_delay=10.0, exponential_base=2.0)` | -| RoutingWrapper | Route operations to different stores based on a routing function. | `RoutingWrapper(routing_function=lambda collection: redis_store if collection == "sessions" else dynamo_store, default_store=memory_store)` | -| SingleCollectionWrapper | Wrap a store to only use a single collection. | `SingleCollectionWrapper(key_value=memory_store, single_collection="users")` | -| StatisticsWrapper | Track operation statistics for the store. | `StatisticsWrapper(key_value=memory_store)` | -| TimeoutWrapper | Add timeout protection to store operations. | `TimeoutWrapper(key_value=redis_store, timeout=5.0)` | -| TTLClampWrapper | Clamp the TTL to a given range. | `TTLClampWrapper(key_value=memory_store, min_ttl=60, max_ttl=3600)` | - -Wrappers can be stacked on top of each other to create more complex functionality. +Wrappers add functionality to stores while implementing the protocol themselves, +allowing them to be stacked and used anywhere a store is expected. Available +wrappers include: + +- **Performance**: Compression, Caching (Passthrough), Statistics, Timeout +- **Security**: Encryption (Fernet), ReadOnly +- **Reliability**: Retry, Fallback +- **Routing**: CollectionRouting, Routing, SingleCollection +- **Organization**: PrefixKeys, PrefixCollections +- **Constraints**: LimitSize, TTLClamp, DefaultValue +- **Observability**: Logging, Statistics + +**[📚 View all wrappers with examples →](https://strawgate.github.io/py-key-value/wrappers/)** + +Wrappers can be stacked for complex functionality: ```python # Create a retriable redis store with timeout protection that is monitored, diff --git a/docs/adapters.md b/docs/adapters.md index 9e25de71..b016516c 100644 --- a/docs/adapters.md +++ b/docs/adapters.md @@ -4,6 +4,14 @@ Adapters provide specialized interfaces for working with key-value stores. Unlik wrappers, adapters don't implement the `AsyncKeyValue` protocol - instead, they provide alternative APIs tailored for specific use cases. +## Available Adapters + +| Adapter | Description | +|---------|-------------| +| [DataclassAdapter](#dataclassadapter) | Type-safe storage/retrieval of dataclass models with transparent serialization | +| [PydanticAdapter](#pydanticadapter) | Type-safe storage/retrieval of Pydantic models with transparent serialization | +| [RaiseOnMissingAdapter](#raiseonmissingadapter) | Optional raise-on-missing behavior for get operations | + ## Adapters vs Wrappers **Wrappers:** @@ -20,7 +28,52 @@ provide alternative APIs tailored for specific use cases. - Add type safety and specialized behavior - Transform how you interact with the store -## Available Adapters +## Adapter Details + +### DataclassAdapter + +The `DataclassAdapter` provides type-safe storage and retrieval of Python +dataclass models. It automatically handles serialization and validation using +Pydantic for validation. + +#### Use Cases + +- Type-safe data storage with dataclasses +- Automatic validation on retrieval +- Working with Python's native dataclass decorator +- Ensuring data integrity + +#### Basic Example + +```python +from dataclasses import dataclass +from key_value.aio.stores.memory import MemoryStore +from key_value.aio.adapters.dataclass import DataclassAdapter + +@dataclass +class User: + name: str + email: str + age: int + +# Create adapter +adapter = DataclassAdapter( + key_value=MemoryStore(), + dataclass_type=User +) + +# Store a user (type-safe) +user = User(name="Alice", email="alice@example.com", age=30) +await adapter.put(key="user:123", value=user, collection="users") + +# Retrieve and get a validated model +retrieved_user = await adapter.get(key="user:123", collection="users") +if retrieved_user: + print(retrieved_user.name) # Type-safe: "Alice" + print(retrieved_user.email) # Type-safe: "alice@example.com" +``` + +--- ### PydanticAdapter diff --git a/docs/stores.md b/docs/stores.md new file mode 100644 index 00000000..bd13141d --- /dev/null +++ b/docs/stores.md @@ -0,0 +1,579 @@ +# Stores + +Stores are the core implementations of the `AsyncKeyValue` protocol. They provide +the actual storage backend for your key-value data. + +## Store Categories + +Stores are organized into three categories based on their storage location and +use case: + +- **Local Stores**: In-memory or on-disk storage local to the application +- **Secret Stores**: Secure storage for sensitive data in OS secret stores +- **Distributed Stores**: Network-based storage for multi-node applications + +## Stability Levels + +Each store has a stability rating that indicates the likelihood of +backwards-incompatible changes to how data is stored: + +- **Stable**: No planned backwards-incompatible changes +- **Preview**: Unlikely to change in backwards-incompatible ways +- **Unstable**: May change in backwards-incompatible ways +- **N/A**: Not applicable (e.g., in-memory stores) + +If you're using py-key-value for caching, stability may not matter. For +long-term storage, prefer stable stores. + +## Local Stores + +Local stores are stored in memory or on disk, local to the application. + +| Store | Stability | Async | Sync | Description | +|-------|:---------:|:-----:|:----:|:------------| +| Memory | N/A | ✅ | ✅ | Fast in-memory storage for development and caching | +| Disk | Stable | ☑️ | ✅ | Persistent file-based storage in a single file | +| Disk (Per-Collection) | Stable | ☑️ | ✅ | Persistent storage with separate files per collection | +| Null (test) | N/A | ✅ | ✅ | No-op store for testing without side effects | +| RocksDB | Unstable | ☑️ | ✅ | High-performance embedded database | +| Simple (test) | N/A | ✅ | ✅ | Simple in-memory store for testing | +| Windows Registry | Unstable | ☑️ | ✅ | Windows Registry-based storage | + +**Legend:** +- ✅ = Fully async implementation available +- ☑️ = Available but uses synchronous underlying implementation +- ✖️ = Not available + +### MemoryStore + +Fast in-memory storage ideal for development, testing, and caching. + +```python +from key_value.aio.stores.memory import MemoryStore + +store = MemoryStore() +``` + +**Installation:** +```bash +pip install py-key-value-aio[memory] +``` + +**Use Cases:** +- Development and testing +- Fast caching +- Session storage +- Temporary data + +**Characteristics:** +- No persistence (data lost on restart) +- Extremely fast +- No external dependencies +- Thread-safe + +--- + +### DiskStore + +Persistent file-based storage using a single JSON file. + +```python +from key_value.aio.stores.disk import DiskStore + +store = DiskStore(directory="./cache") +``` + +**Installation:** +```bash +pip install py-key-value-aio[disk] +``` + +**Use Cases:** +- Local caching with persistence +- Development environments +- Single-node applications +- Small datasets + +**Characteristics:** +- Persists across restarts +- Simple file format (JSON) +- Suitable for small to medium datasets +- All data in one file + +--- + +### MultiDiskStore + +Persistent storage with separate files per collection. + +```python +from key_value.aio.stores.multi_disk import MultiDiskStore + +store = MultiDiskStore(directory="./cache") +``` + +**Installation:** +```bash +pip install py-key-value-aio[disk] +``` + +**Use Cases:** +- Organizing data by collection +- Better performance with many collections +- Easier to manage individual collections + +**Characteristics:** +- One file per collection +- Better suited for many collections +- Easier collection management +- JSON-based storage + +--- + +### RocksDBStore + +High-performance embedded database using RocksDB. + +```python +from key_value.aio.stores.rocksdb import RocksDBStore + +store = RocksDBStore(path="./rocksdb") +``` + +**Installation:** +```bash +pip install py-key-value-aio[rocksdb] +``` + +**Use Cases:** +- High-throughput applications +- Large datasets +- Performance-critical applications + +**Characteristics:** +- Very fast reads and writes +- Efficient storage +- Requires native dependencies +- Stable storage format: **Unstable** + +--- + +### WindowsRegistryStore + +Storage using the Windows Registry. + +```python +from key_value.aio.stores.registry import WindowsRegistryStore + +store = WindowsRegistryStore( + hive="HKEY_CURRENT_USER", + registry_path="Software\\py-key-value" +) +``` + +**Installation:** +```bash +pip install py-key-value-aio[registry] +``` + +**Use Cases:** +- Windows-specific applications +- System configuration storage +- Integration with Windows settings + +**Characteristics:** +- Windows-only +- Persists in registry +- Subject to registry limitations +- Stable storage format: **Unstable** + +--- + +### NullStore + +No-op store that discards all data. Useful for testing. + +```python +from key_value.aio.stores.null import NullStore + +store = NullStore() +``` + +**Use Cases:** +- Testing without side effects +- Disabling storage temporarily +- Performance baseline testing + +--- + +### SimpleStore + +Simple in-memory store for testing. + +```python +from key_value.aio.stores.simple import SimpleStore + +store = SimpleStore() +``` + +**Use Cases:** +- Basic testing +- Minimal implementation reference + +--- + +## Secret Stores + +Secret stores provide secure storage for sensitive data, typically using +operating system secret management facilities. + +| Store | Stability | Async | Sync | Description | +|-------|:---------:|:-----:|:----:|:------------| +| Keyring | Stable | ✅ | ✅ | OS-level secure storage (Keychain, Credential Manager, etc.) | +| Vault | Unstable | ✅ | ✅ | HashiCorp Vault integration for enterprise secrets | + +### KeyringStore + +Secure storage using the operating system's keyring (macOS Keychain, Windows +Credential Manager, Linux Secret Service). + +```python +from key_value.aio.stores.keyring import KeyringStore + +store = KeyringStore(service_name="py-key-value") +``` + +**Installation:** +```bash +pip install py-key-value-aio[keyring] +``` + +**Use Cases:** +- Storing API keys and tokens +- User credentials +- Sensitive configuration +- Encrypted local storage + +**Characteristics:** +- OS-level encryption +- Secure by default +- Cross-platform +- **Windows limitation**: Strict value length limits + +**Important:** Windows Keyring has strict limits on value length which may +cause issues with large values. + +--- + +### VaultStore + +Integration with HashiCorp Vault for enterprise secret management. + +```python +from key_value.aio.stores.vault import VaultStore + +store = VaultStore( + url="http://localhost:8200", + token="your-token" +) +``` + +**Installation:** +```bash +pip install py-key-value-aio[vault] +``` + +**Use Cases:** +- Enterprise secret management +- Multi-environment deployments +- Centralized secret rotation +- Audit logging + +**Characteristics:** +- Enterprise-grade security +- Centralized management +- Audit logging +- Stable storage format: **Unstable** + +--- + +## Distributed Stores + +Distributed stores provide network-based storage for multi-node applications. + +| Store | Stability | Async | Sync | Description | +|-------|:---------:|:-----:|:----:|:------------| +| DynamoDB | Unstable | ✅ | ✖️ | AWS DynamoDB key-value storage | +| Elasticsearch | Unstable | ✅ | ✅ | Full-text search with key-value capabilities | +| Memcached | Unstable | ✅ | ✖️ | High-performance distributed memory cache | +| MongoDB | Unstable | ✅ | ✅ | Document database used as key-value store | +| Redis | Stable | ✅ | ✅ | Popular in-memory data structure store | +| Valkey | Stable | ✅ | ✅ | Open-source Redis fork | + +### RedisStore + +High-performance in-memory store using Redis. + +```python +from key_value.aio.stores.redis import RedisStore + +store = RedisStore(url="redis://localhost:6379/0") +``` + +**Installation:** +```bash +pip install py-key-value-aio[redis] +``` + +**Use Cases:** +- Distributed caching +- Session storage +- Real-time applications +- High-throughput systems + +**Characteristics:** +- Very fast (in-memory) +- Production-ready +- Rich feature set +- Horizontal scaling support +- **Stable storage format** + +--- + +### ValkeyStore + +Open-source Redis fork with similar performance characteristics. + +```python +from key_value.aio.stores.valkey import ValkeyStore + +store = ValkeyStore(host="localhost", port=6379) +``` + +**Installation:** +```bash +pip install py-key-value-aio[valkey] +``` + +**Use Cases:** +- Same as Redis +- Open-source preference +- Redis API compatibility + +**Characteristics:** +- Redis-compatible +- Open-source governance +- Production-ready +- **Stable storage format** + +--- + +### DynamoDBStore + +AWS DynamoDB integration for serverless and cloud-native applications. + +```python +from key_value.aio.stores.dynamodb import DynamoDBStore + +store = DynamoDBStore( + table_name="kv-store", + region_name="us-east-1" +) +``` + +**Installation:** +```bash +pip install py-key-value-aio[dynamodb] +``` + +**Use Cases:** +- AWS-native applications +- Serverless architectures +- Global distribution +- Managed infrastructure + +**Characteristics:** +- Fully managed +- Auto-scaling +- Global tables +- Pay-per-use pricing +- Stable storage format: **Unstable** + +--- + +### ElasticsearchStore + +Full-text search engine used as a key-value store. + +```python +from key_value.aio.stores.elasticsearch import ElasticsearchStore + +store = ElasticsearchStore( + url="https://localhost:9200", + api_key="your-api-key", + index="kv-store" +) +``` + +**Installation:** +```bash +pip install py-key-value-aio[elasticsearch] +``` + +**Use Cases:** +- Applications already using Elasticsearch +- Need for search capabilities +- Analytics and logging + +**Characteristics:** +- Search capabilities +- Distributed by default +- Rich querying +- Stable storage format: **Unstable** + +--- + +### MongoDBStore + +Document database used as a key-value store. + +```python +from key_value.aio.stores.mongodb import MongoDBStore + +store = MongoDBStore(url="mongodb://localhost:27017/test") +``` + +**Installation:** +```bash +pip install py-key-value-aio[mongodb] +``` + +**Use Cases:** +- Applications already using MongoDB +- Document-oriented data +- Flexible schemas + +**Characteristics:** +- Document storage +- Rich querying +- Horizontal scaling +- Stable storage format: **Unstable** + +--- + +### MemcachedStore + +High-performance distributed memory caching system. + +```python +from key_value.aio.stores.memcached import MemcachedStore + +store = MemcachedStore(host="127.0.0.1", port=11211) +``` + +**Installation:** +```bash +pip install py-key-value-aio[memcached] +``` + +**Use Cases:** +- Distributed caching +- Session storage +- High-throughput caching + +**Characteristics:** +- Very fast +- Simple protocol +- Distributed by design +- No persistence +- Stable storage format: **Unstable** + +--- + +## Choosing a Store + +### Development + +**Recommended:** `MemoryStore` or `DiskStore` + +- Fast iteration +- No setup required +- Easy debugging + +```python +# Development +from key_value.aio.stores.memory import MemoryStore +store = MemoryStore() +``` + +### Production Caching + +**Recommended:** `RedisStore` or `ValkeyStore` + +- High performance +- Distributed +- Production-ready +- Stable storage format + +```python +# Production caching +from key_value.aio.stores.redis import RedisStore +store = RedisStore(url="redis://localhost:6379/0") +``` + +### Long-Term Storage + +**Recommended:** Stores with **Stable** stability rating + +- `RedisStore` +- `ValkeyStore` +- `DiskStore` +- `MultiDiskStore` +- `KeyringStore` + +Avoid unstable stores for data you can't afford to lose or migrate. + +### Sensitive Data + +**Recommended:** `KeyringStore` or `VaultStore` + +- OS-level encryption +- Secure by default +- Audit logging (Vault) + +```python +# Sensitive data +from key_value.aio.stores.keyring import KeyringStore +store = KeyringStore(service_name="my-app") +``` + +### Serverless/Cloud + +**Recommended:** `DynamoDBStore` (AWS) + +- Fully managed +- Auto-scaling +- No servers to maintain + +```python +# AWS Lambda +from key_value.aio.stores.dynamodb import DynamoDBStore +store = DynamoDBStore(table_name="kv-store", region_name="us-east-1") +``` + +## Store Compatibility + +All stores implement the same protocol, making it easy to switch: + +```python +# Development +store = MemoryStore() + +# Production +store = RedisStore(url="redis://localhost:6379/0") + +# Your code works with both! +await store.put(key="user:123", value={"name": "Alice"}, collection="users") +``` + +See the [API Reference](api/stores.md) for complete store documentation. diff --git a/docs/wrappers.md b/docs/wrappers.md index fa514b05..ccc183c2 100644 --- a/docs/wrappers.md +++ b/docs/wrappers.md @@ -4,6 +4,28 @@ Wrappers are a powerful feature of py-key-value that allow you to add functionality to any key-value store. Wrappers implement the `AsyncKeyValue` protocol, so they can be used anywhere a store can be used. +## Available Wrappers + +| Wrapper | Description | +|---------|-------------| +| [CollectionRoutingWrapper](#collectionroutingwrapper) | Route operations to different stores based on collection name | +| [CompressionWrapper](#compressionwrapper) | Compress values before storing and decompress on retrieval | +| [DefaultValueWrapper](#defaultvaluewrapper) | Return a default value when key is missing | +| [FernetEncryptionWrapper](#fernetencryptionwrapper) | Encrypt values before storing and decrypt on retrieval | +| [FallbackWrapper](#fallbackwrapper) | Fallback to a secondary store when the primary store fails | +| [LimitSizeWrapper](#limitsizewrapper) | Limit the size of entries stored in the cache | +| [LoggingWrapper](#loggingwrapper) | Log the operations performed on the store | +| [PassthroughCacheWrapper](#passthroughcachewrapper) | Wrap two stores to provide a read-through cache | +| [PrefixCollectionsWrapper](#prefixcollectionswrapper) | Prefix all collections with a given prefix | +| [PrefixKeysWrapper](#prefixkeyswrapper) | Prefix all keys with a given prefix | +| [ReadOnlyWrapper](#readonlywrapper) | Prevent all write operations on the underlying store | +| [RetryWrapper](#retrywrapper) | Retry failed operations with exponential backoff | +| [RoutingWrapper](#routingwrapper) | Route operations to different stores based on a routing function | +| [SingleCollectionWrapper](#singlecollectionwrapper) | Wrap a store to only use a single collection | +| [StatisticsWrapper](#statisticswrapper) | Track operation statistics for the store | +| [TimeoutWrapper](#timeoutwrapper) | Add timeout protection to store operations | +| [TTLClampWrapper](#ttlclampwrapper) | Clamp the TTL to a given range | + ## What Are Wrappers? Wrappers follow the decorator pattern - they wrap around a key-value store and diff --git a/mkdocs.yml b/mkdocs.yml index c3ea4d9c..13726dae 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -67,6 +67,7 @@ markdown_extensions: nav: - Home: index.md - Getting Started: getting-started.md + - Stores: stores.md - Wrappers: wrappers.md - Adapters: adapters.md - API Reference: From 2de7e1c807b233d31e358b2546a4842323c30188 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 02:42:20 +0000 Subject: [PATCH 2/3] fix: update README links to use strawgate.com and fix markdown lint errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Changed all documentation links from strawgate.github.io to strawgate.com - Updated project links section to point to docs instead of subdirectory READMEs - Removed invalid link fragments from docs/wrappers.md table - Fixed duplicate heading in docs/wrappers.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: William Easton --- README.md | 20 ++++++++++---------- docs/wrappers.md | 7 ++----- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 9b9d6e74..d2759e05 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ This monorepo contains two libraries: ## Documentation -- [Full Documentation](https://strawgate.github.io/py-key-value/) -- [Getting Started Guide](https://strawgate.github.io/py-key-value/getting-started/) -- [Wrappers Guide](https://strawgate.github.io/py-key-value/wrappers/) -- [Adapters Guide](https://strawgate.github.io/py-key-value/adapters/) -- [API Reference](https://strawgate.github.io/py-key-value/api/protocols/) +- [Full Documentation](https://strawgate.com/py-key-value/) +- [Getting Started Guide](https://strawgate.com/py-key-value/getting-started/) +- [Wrappers Guide](https://strawgate.com/py-key-value/wrappers/) +- [Adapters Guide](https://strawgate.com/py-key-value/adapters/) +- [API Reference](https://strawgate.com/py-key-value/api/protocols/) ## Why use this library? @@ -196,7 +196,7 @@ Each store has a **stability rating** indicating likelihood of backwards-incompatible changes. Stable stores (Redis, Valkey, Disk, Keyring) are recommended for long-term storage. -**[📚 View all stores, installation guides, and examples →](https://strawgate.github.io/py-key-value/stores/)** +**[📚 View all stores, installation guides, and examples →](https://strawgate.com/py-key-value/stores/)** ### Adapters @@ -209,7 +209,7 @@ use cases: - **RaiseOnMissingAdapter**: Raise exceptions instead of returning None for missing keys -**[📚 View all adapters with examples →](https://strawgate.github.io/py-key-value/adapters/)** +**[📚 View all adapters with examples →](https://strawgate.com/py-key-value/adapters/)** **Quick example** - PydanticAdapter for type-safe storage: @@ -263,7 +263,7 @@ wrappers include: - **Constraints**: LimitSize, TTLClamp, DefaultValue - **Observability**: Logging, Statistics -**[📚 View all wrappers with examples →](https://strawgate.github.io/py-key-value/wrappers/)** +**[📚 View all wrappers with examples →](https://strawgate.com/py-key-value/wrappers/)** Wrappers can be stacked for complex functionality: @@ -353,8 +353,8 @@ library. ## Project links -- Async README: `key-value/key-value-aio/README.md` -- Sync README: `key-value/key-value-sync/README.md` +- [Full Documentation](https://strawgate.com/py-key-value/) +- [API Reference](https://strawgate.com/py-key-value/api/protocols/) Contributions welcome but may not be accepted. File an issue before submitting a pull request. If you do not get agreement on your proposal before making a diff --git a/docs/wrappers.md b/docs/wrappers.md index 2d01473d..ee595c63 100644 --- a/docs/wrappers.md +++ b/docs/wrappers.md @@ -8,9 +8,7 @@ protocol, so they can be used anywhere a store can be used. | Wrapper | Description | |---------|-------------| -| [CollectionRoutingWrapper](#collectionroutingwrapper) | Route operations to different stores based on collection name | | [CompressionWrapper](#compressionwrapper) | Compress values before storing and decompress on retrieval | -| [DefaultValueWrapper](#defaultvaluewrapper) | Return a default value when key is missing | | [FernetEncryptionWrapper](#fernetencryptionwrapper) | Encrypt values before storing and decrypt on retrieval | | [FallbackWrapper](#fallbackwrapper) | Fallback to a secondary store when the primary store fails | | [LimitSizeWrapper](#limitsizewrapper) | Limit the size of entries stored in the cache | @@ -20,11 +18,10 @@ protocol, so they can be used anywhere a store can be used. | [PrefixKeysWrapper](#prefixkeyswrapper) | Prefix all keys with a given prefix | | [ReadOnlyWrapper](#readonlywrapper) | Prevent all write operations on the underlying store | | [RetryWrapper](#retrywrapper) | Retry failed operations with exponential backoff | -| [RoutingWrapper](#routingwrapper) | Route operations to different stores based on a routing function | | [SingleCollectionWrapper](#singlecollectionwrapper) | Wrap a store to only use a single collection | +| [TTLClampWrapper](#ttlclampwrapper) | Clamp the TTL to a given range | | [StatisticsWrapper](#statisticswrapper) | Track operation statistics for the store | | [TimeoutWrapper](#timeoutwrapper) | Add timeout protection to store operations | -| [TTLClampWrapper](#ttlclampwrapper) | Clamp the TTL to a given range | ## What Are Wrappers? @@ -54,7 +51,7 @@ Wrappers execute in the order they are stacked: - **Writes** (put, delete): Outer wrapper → Inner wrapper → Store - **Reads** (get, ttl): Store → Inner wrapper → Outer wrapper -## Available Wrappers +## Wrapper Details ### CompressionWrapper From 36ca051280aa8b9f2d5fbc709b13682bdab1ebe6 Mon Sep 17 00:00:00 2001 From: William Easton Date: Tue, 28 Oct 2025 21:47:24 -0500 Subject: [PATCH 3/3] lint --- docs/stores.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/docs/stores.md b/docs/stores.md index bd13141d..f4d49a6a 100644 --- a/docs/stores.md +++ b/docs/stores.md @@ -40,6 +40,7 @@ Local stores are stored in memory or on disk, local to the application. | Windows Registry | Unstable | ☑️ | ✅ | Windows Registry-based storage | **Legend:** + - ✅ = Fully async implementation available - ☑️ = Available but uses synchronous underlying implementation - ✖️ = Not available @@ -55,17 +56,20 @@ store = MemoryStore() ``` **Installation:** + ```bash pip install py-key-value-aio[memory] ``` **Use Cases:** + - Development and testing - Fast caching - Session storage - Temporary data **Characteristics:** + - No persistence (data lost on restart) - Extremely fast - No external dependencies @@ -84,17 +88,20 @@ store = DiskStore(directory="./cache") ``` **Installation:** + ```bash pip install py-key-value-aio[disk] ``` **Use Cases:** + - Local caching with persistence - Development environments - Single-node applications - Small datasets **Characteristics:** + - Persists across restarts - Simple file format (JSON) - Suitable for small to medium datasets @@ -113,16 +120,19 @@ store = MultiDiskStore(directory="./cache") ``` **Installation:** + ```bash pip install py-key-value-aio[disk] ``` **Use Cases:** + - Organizing data by collection - Better performance with many collections - Easier to manage individual collections **Characteristics:** + - One file per collection - Better suited for many collections - Easier collection management @@ -141,16 +151,19 @@ store = RocksDBStore(path="./rocksdb") ``` **Installation:** + ```bash pip install py-key-value-aio[rocksdb] ``` **Use Cases:** + - High-throughput applications - Large datasets - Performance-critical applications **Characteristics:** + - Very fast reads and writes - Efficient storage - Requires native dependencies @@ -172,16 +185,19 @@ store = WindowsRegistryStore( ``` **Installation:** + ```bash pip install py-key-value-aio[registry] ``` **Use Cases:** + - Windows-specific applications - System configuration storage - Integration with Windows settings **Characteristics:** + - Windows-only - Persists in registry - Subject to registry limitations @@ -200,6 +216,7 @@ store = NullStore() ``` **Use Cases:** + - Testing without side effects - Disabling storage temporarily - Performance baseline testing @@ -217,6 +234,7 @@ store = SimpleStore() ``` **Use Cases:** + - Basic testing - Minimal implementation reference @@ -244,17 +262,20 @@ store = KeyringStore(service_name="py-key-value") ``` **Installation:** + ```bash pip install py-key-value-aio[keyring] ``` **Use Cases:** + - Storing API keys and tokens - User credentials - Sensitive configuration - Encrypted local storage **Characteristics:** + - OS-level encryption - Secure by default - Cross-platform @@ -279,17 +300,20 @@ store = VaultStore( ``` **Installation:** + ```bash pip install py-key-value-aio[vault] ``` **Use Cases:** + - Enterprise secret management - Multi-environment deployments - Centralized secret rotation - Audit logging **Characteristics:** + - Enterprise-grade security - Centralized management - Audit logging @@ -321,17 +345,20 @@ store = RedisStore(url="redis://localhost:6379/0") ``` **Installation:** + ```bash pip install py-key-value-aio[redis] ``` **Use Cases:** + - Distributed caching - Session storage - Real-time applications - High-throughput systems **Characteristics:** + - Very fast (in-memory) - Production-ready - Rich feature set @@ -351,16 +378,19 @@ store = ValkeyStore(host="localhost", port=6379) ``` **Installation:** + ```bash pip install py-key-value-aio[valkey] ``` **Use Cases:** + - Same as Redis - Open-source preference - Redis API compatibility **Characteristics:** + - Redis-compatible - Open-source governance - Production-ready @@ -382,17 +412,20 @@ store = DynamoDBStore( ``` **Installation:** + ```bash pip install py-key-value-aio[dynamodb] ``` **Use Cases:** + - AWS-native applications - Serverless architectures - Global distribution - Managed infrastructure **Characteristics:** + - Fully managed - Auto-scaling - Global tables @@ -416,16 +449,19 @@ store = ElasticsearchStore( ``` **Installation:** + ```bash pip install py-key-value-aio[elasticsearch] ``` **Use Cases:** + - Applications already using Elasticsearch - Need for search capabilities - Analytics and logging **Characteristics:** + - Search capabilities - Distributed by default - Rich querying @@ -444,16 +480,19 @@ store = MongoDBStore(url="mongodb://localhost:27017/test") ``` **Installation:** + ```bash pip install py-key-value-aio[mongodb] ``` **Use Cases:** + - Applications already using MongoDB - Document-oriented data - Flexible schemas **Characteristics:** + - Document storage - Rich querying - Horizontal scaling @@ -472,16 +511,19 @@ store = MemcachedStore(host="127.0.0.1", port=11211) ``` **Installation:** + ```bash pip install py-key-value-aio[memcached] ``` **Use Cases:** + - Distributed caching - Session storage - High-throughput caching **Characteristics:** + - Very fast - Simple protocol - Distributed by design