chore(release): 0.0.3

Squash-merge lib-standardisation: adopt repo standards across packaging,
tooling, docs, and CI.

- standardize pyproject.toml (canonical packaging, lint config, extras, GSDFC pydoclint)
- add py.typed marker, modernize type hints and Google-style docstrings
- nest generated docs under docs/lib and docs/mcp; add hand-written wiki
- adopt standard Type A PyPI CI pipeline (tag==version guard + quality gate)
- promote generated CHANGELOG.md; bump version to 0.0.3
This commit is contained in:
2026-10-17 02:16:46 +05:30
parent c541577788
commit 371b74806f
96 changed files with 1756 additions and 2200 deletions

View File

@@ -1,5 +1,5 @@
from .store import CredentialStore
from .pickle import PickleCredentialStore
from .redis import RedisCredentialStore
from .store import CredentialStore
__all__ = ["CredentialStore", "PickleCredentialStore", "RedisCredentialStore"]

View File

@@ -16,7 +16,7 @@ untrusted environments.
"""
import pickle
from typing import Optional, TypeVar
from typing import TypeVar
from mail_intake.credentials.store import CredentialStore
@@ -55,12 +55,12 @@ class PickleCredentialStore(CredentialStore[T]):
"""
self.path = path
def load(self) -> Optional[T]:
def load(self) -> T | None:
"""
Load credentials from the local filesystem.
Returns:
Optional[T]:
T | None:
An instance of type `T` if credentials are present and
successfully deserialized; otherwise `None`.

View File

@@ -1,4 +1,5 @@
from typing import Optional, TypeVar
from typing import TypeVar
from .store import CredentialStore
T = TypeVar("T")
@@ -6,6 +7,6 @@ T = TypeVar("T")
class PickleCredentialStore(CredentialStore[T]):
path: str
def __init__(self, path: str) -> None: ...
def load(self) -> Optional[T]: ...
def load(self) -> T | None: ...
def save(self, credentials: T) -> None: ...
def clear(self) -> None: ...

View File

@@ -24,8 +24,8 @@ Credential validation, refresh, rotation, and acquisition remain the
responsibility of authentication provider implementations.
"""
from typing import Optional, TypeVar, Callable
from collections.abc import Callable
from typing import Any, TypeVar
from mail_intake.credentials.store import CredentialStore
@@ -57,30 +57,27 @@ class RedisCredentialStore(CredentialStore[T]):
def __init__(
self,
redis_client,
redis_client: Any,
key: str,
serialize: Callable[[T], bytes],
deserialize: Callable[[bytes], T],
ttl_seconds: Optional[int] = None,
ttl_seconds: int | None = None,
):
"""
Initialize a Redis-backed credential store.
Args:
redis_client (Any):
An initialized Redis client instance (for example, ``redis.Redis`` or a compatible interface) used to communicate with the Redis server.
Initialized Redis client instance used for persistence.
key (str):
The Redis key under which credentials are stored. Callers are responsible for applying appropriate namespacing to avoid collisions.
Storage key under which credentials are persisted.
serialize (Callable[[T], bytes]):
A callable that converts a credential object of type ``T`` into a ``bytes`` representation suitable for storage in Redis.
Callable that encodes credentials to bytes for storage.
deserialize (Callable[[bytes], T]):
A callable that converts a ``bytes`` payload retrieved from Redis back into a credential object of type ``T``.
ttl_seconds (Optional[int]):
Optional time-to-live (TTL) for the stored credentials, expressed in seconds. When provided, Redis will automatically expire the stored credentials after the specified duration. If ``None``, credentials are stored without an expiration.
Callable that decodes stored bytes back into credentials.
ttl_seconds (int | None):
Optional time-to-live in seconds after which stored
credentials expire automatically. ``None`` disables expiry.
"""
self.redis = redis_client
self.key = key
@@ -88,12 +85,12 @@ class RedisCredentialStore(CredentialStore[T]):
self.deserialize = deserialize
self.ttl_seconds = ttl_seconds
def load(self) -> Optional[T]:
def load(self) -> T | None:
"""
Load credentials from Redis.
Returns:
Optional[T]:
T | None:
An instance of type `T` if credentials are present and
successfully deserialized; otherwise `None`.

View File

@@ -1,4 +1,6 @@
from typing import Optional, TypeVar, Callable, Any
from collections.abc import Callable
from typing import Any, TypeVar
from .store import CredentialStore
T = TypeVar("T")
@@ -8,8 +10,15 @@ class RedisCredentialStore(CredentialStore[T]):
key: str
serialize: Callable[[T], bytes]
deserialize: Callable[[bytes], T]
ttl_seconds: Optional[int]
def __init__(self, redis_client: Any, key: str, serialize: Callable[[T], bytes], deserialize: Callable[[bytes], T], ttl_seconds: Optional[int] = ...) -> None: ...
def load(self) -> Optional[T]: ...
ttl_seconds: int | None
def __init__(
self,
redis_client: Any,
key: str,
serialize: Callable[[T], bytes],
deserialize: Callable[[bytes], T],
ttl_seconds: int | None = ...,
) -> None: ...
def load(self) -> T | None: ...
def save(self, credentials: T) -> None: ...
def clear(self) -> None: ...

View File

@@ -19,9 +19,8 @@ or secrets managers—without coupling authentication logic to any
specific storage mechanism.
"""
from abc import ABC, abstractmethod
from typing import Generic, Optional, TypeVar
from typing import Generic, TypeVar
T = TypeVar("T")
@@ -48,12 +47,12 @@ class CredentialStore(ABC, Generic[T]):
"""
@abstractmethod
def load(self) -> Optional[T]:
def load(self) -> T | None:
"""
Load previously persisted credentials.
Returns:
Optional[T]:
T | None:
An instance of type `T` if credentials are available and
loadable; otherwise `None`.

View File

@@ -1,11 +1,11 @@
from abc import ABC, abstractmethod
from typing import Generic, Optional, TypeVar
from typing import Generic, TypeVar
T = TypeVar("T")
class CredentialStore(ABC, Generic[T]):
@abstractmethod
def load(self) -> Optional[T]: ...
def load(self) -> T | None: ...
@abstractmethod
def save(self, credentials: T) -> None: ...
@abstractmethod