fleche.storage.base
Attributes
Exceptions
Common base class for all non-exit exceptions. |
|
Inappropriate argument value (of correct type). |
Classes
Describes the kind of operation being performed on storage. |
|
Minimal base that exposes the |
|
Abstract base providing key-management helpers for any keyed storage. |
|
Primitive backend interface for key-value storage. |
|
Abstract domain interface for value storage. |
|
Bridges |
|
Abstract domain interface for call storage. |
|
Bridges |
Functions
|
Shared empty-check + single/tuple unwrap for a batched |
|
Return the unique Digest for key prefix, or raise KeyError / AmbiguousDigestError. |
Module Contents
- exception fleche.storage.base.SaveError[source]
Bases:
ExceptionCommon base class for all non-exit exceptions.
- exception fleche.storage.base.AmbiguousDigestError[source]
Bases:
ValueErrorInappropriate argument value (of correct type).
- class fleche.storage.base.Intent[source]
Bases:
enum.StrEnumDescribes the kind of operation being performed on storage.
Mixins may use this to choose between exclusive and shared locks.
WRITEalways takes the exclusive lock.READis a no-op for now — the locking mixins short-circuit it and acquire nothing. It is reserved for a future reader-writer lock, where reads would take a shared lock instead. Because it currently grants no mutual exclusion,READmust never guard a read-modify-write sequence.
- fleche.storage.base._apply_shrink(shrink_many: Callable[Ellipsis, tuple[Digest, ...]], keys: tuple[Digest | str, ...]) Digest | tuple[Digest, ...][source]
Shared empty-check + single/tuple unwrap for a batched
shrink(*keys)overload.Calls
shrink_many(*keys), which must return a same-length tuple ofDigest, and unwraps it to a singleDigestwhen keys has length one. Shared byKeyManagement.shrink()andshrink(), whose batched_shrinkimplementations differ but whose public overload boilerplate does not.
- fleche.storage.base._resolve_prefix(key: Digest | str, candidates: Iterable[Digest], *, dedupe: bool = False) fleche.digest.Digest[source]
Return the unique Digest for key prefix, or raise KeyError / AmbiguousDigestError.
With
dedupe=False(the default), candidates must contain at most two entries (the two lexicographically smallest keys that start with key); callers are responsible for fetching them efficiently (e.g. via aLIKE … LIMIT 2query for SQL backends).With
dedupe=True, candidates is first reduced to its sorted unique values — for callers combining results from multiple sub-storages, where the same digest may legitimately appear more than once.
- class fleche.storage.base.OperationContext[source]
Bases:
abc.ABCMinimal base that exposes the
_operation_context()hook.Both
KeyManagement(storage layer) andBaseCache(cache layer) inherit from this class so that the same thread-safety mixins (SerializingMixin,PerKeyLockMixin) can attach to either layer without duplication.- _operation_context(key: fleche.digest.Digest | str, *, intent: Intent = Intent.WRITE)[source]
Context manager entered around every operation on
key.The base implementation is a no-op. Override in a mixin to inject any resource scoped to the operation — a threading lock, a SQLAlchemy session, an open file handle, a decompression stream, etc.
Receiving
keylets implementations choose between a single global resource (ignore the key) or per-key resources (e.g. a striped lock table or a key-specific file handle).intentdescribes the kind of operation being performed. Mixins may use it to choose between exclusive and shared locks. Currently the only defined value isIntent.WRITE(the default).Composing multiple mixins: use
super()to chain so that every mixin in the MRO gets to wrap the operation:@contextlib.contextmanager def _operation_context(self, key, *, intent=Intent.WRITE): with self._lock: # this mixin's resource with super()._operation_context(key, intent=intent): yield
- class fleche.storage.base.KeyManagement[source]
Bases:
OperationContextAbstract base providing key-management helpers for any keyed storage.
Subclasses must implement
list,_evict, and_contains. The concrete helpersevict,contains,expand, andshrinkare implemented here once and inherited by all storage classes.Every public operation enters
_operation_context()around the compound work it performs, so mixins can inject an operation-scoped resource (e.g. a threading lock, a SQLAlchemy session, a file handle) without overriding every method individually.- abstractmethod list() Iterable[fleche.digest.Digest][source]
- abstractmethod _evict(key: fleche.digest.Digest) None[source]
- abstractmethod _contains(key: fleche.digest.Digest) bool[source]
- evict(key: fleche.digest.Digest | str) None[source]
Removes the entry corresponding to the key from the storage.
- contains(key: fleche.digest.Digest | str) bool[source]
Return True if the key is present in the storage, False otherwise.
- expand(key: fleche.digest.Digest | str) fleche.digest.Digest[source]
Expands a short-hand digest to the full length one.
- shrink(key: fleche.digest.Digest | str, /) fleche.digest.Digest[source]
- shrink(key: fleche.digest.Digest | str, /, *keys: fleche.digest.Digest | str) tuple[Digest, ...]
Find the shortest substring(s) that unambiguously reference each key.
With a single key, returns one
Digest. With multiple keys, returns a tuple ofDigestin the same order as the inputs; the batched form fetcheslist()once instead of per-key, which matters on backends where listing is expensive (e.g. SQL, filesystem).
- _shrink(*keys: fleche.digest.Digest | str) tuple[Digest, ...][source]
- _shrink_one(key: Digest | str, sorted_all: Sequence[str]) fleche.digest.Digest[source]
- _normalize_key(key: fleche.digest.Digest | str) fleche.digest.Digest[source]
Expand a short digest prefix to a full key, or wrap a full key as Digest.
- class fleche.storage.base.StorageBackend[source]
Bases:
KeyManagementPrimitive backend interface for key-value storage.
Backends implement the low-level
put/get/_evict/listoperations. Higher-level classes (ValueMixin,CallMixin) add domain-specific logic on top.- abstractmethod put(value: Any, key: fleche.digest.Digest) fleche.digest.Digest[source]
- abstractmethod get(key: fleche.digest.Digest) Any[source]
- _contains(key: fleche.digest.Digest) bool[source]
- class fleche.storage.base.ValueStorage[source]
Bases:
KeyManagementAbstract domain interface for value storage.
- abstractmethod save(value: Any, key: fleche.digest.Digest | None = None) fleche.digest.Digest[source]
- abstractmethod load(key: fleche.digest.Digest | str) Any[source]
- class fleche.storage.base.ValueMixin[source]
Bases:
ValueStorage,StorageBackendBridges
ValueStoragewithStorageBackendprimitives.Implements
saveandloadusingputandget. Concrete classes inherit from this and aStorageBackendimplementation to get a fully functional value storage.- save(value: Any, key: fleche.digest.Digest | None = None) fleche.digest.Digest[source]
- load(key: fleche.digest.Digest | str) Any[source]
- class fleche.storage.base.CallStorage[source]
Bases:
KeyManagementAbstract domain interface for call storage.
- abstractmethod save(call: fleche.call.DigestedCall) fleche.digest.Digest[source]
- abstractmethod load(key: fleche.digest.Digest | str) fleche.call.DigestedCall[source]
- abstractmethod query(template: fleche.call.QueryCall) Iterable[fleche.call.DigestedCall][source]
- transform(func: Callable[[fleche.call.DigestedCall], fleche.call.DigestedCall] | None = None) None[source]
Applies a transformation function to all DigestedCall objects in the storage.
- Parameters:
func – A function that takes a
DigestedCalland returns a transformed one. IfNone, the identity is used (useful for re-calculating keys).
- class fleche.storage.base.CallMixin[source]
Bases:
CallStorage,StorageBackendBridges
CallStoragewithStorageBackendprimitives.Implements
save,load, andqueryusingputandget, deriving the storage key from the call’s lookup key.transformis inherited fromCallStorage.Concrete classes inherit from this and a
StorageBackendimplementation to get a fully functional call storage.- load(key: fleche.digest.Digest | str) fleche.call.DigestedCall[source]
- query(template: fleche.call.QueryCall) Iterable[fleche.call.DigestedCall][source]
Find cached calls that ‘match’ the template.
Returns all calls where the given arguments, results or metadata match exactly the stored ones. Values may be given either as they are or as
Digest.- Parameters:
template (Call) – specification for calls to return; use None as wildcard.
- Returns:
an iterable over all matching digested call objects
- Return type:
Iterable[DigestedCall]