Skip to content

Store

persista.store

Contain stores.

persista.store.OnConflict module-attribute

OnConflict = Literal['raise', 'skip', 'overwrite', 'merge']

Strategy for handling keys that already exist in the store.

Used by :meth:BaseStore.set, :meth:BaseStore.set_many, and :meth:BaseStore.set_batches to control what happens when a key being written already has a value in the store.

Example
>>> from persista.store import InMemoryStore
>>> with InMemoryStore() as store:
...     store.set("key", {"a": 1})
...     store.set("key", {"b": 2}, on_conflict="merge")
...     store.get("key")
...
{'a': 1, 'b': 2}

persista.store.BaseDuckDBStore

Bases: ThreadedAsyncStoreMixin, BaseStore, MultilineDisplayMixin

Define a base class for DuckDB-backed key-value stores.

Subclasses only need to implement :meth:_select_columns, :meth:_row_to_kv, :meth:_set_many, and :meth:filter, which control how a value is laid out across the table's columns (see :class:DuckDBStore for a single JSON column layout and :class:~persista.store.duckdb_typed.TypedDuckDBStore for a typed column layout with a JSON overflow column).

Parameters:

Name Type Description Default
database Path | str

Path to the DuckDB file, or ":memory:" for an in-memory database (useful for testing). Matches the database argument name used by duckdb.connect.

required
**kwargs Any

Additional keyword arguments to pass to duckdb.connect.

{}

persista.store.BaseDuckDBStore.get_columns_info

get_columns_info() -> dict[str, str]

Return the column names and types of the store's table.

Returns:

Type Description
dict[str, str]

A mapping of column name to DuckDB type name.

Example
>>> from persista.store import DuckDBStore
>>> with DuckDBStore(":memory:") as store:
...     store.get_columns_info()
...
{'key': 'VARCHAR', 'value': 'JSON'}

persista.store.BaseDuckDBStore.show_columns_info

show_columns_info() -> None

Print the store's table column names and types to stdout.

This is a convenience wrapper around :meth:get_columns_info for interactive/debugging use. For programmatic access, use :meth:get_columns_info instead.

persista.store.BaseFileStore

Bases: ThreadedAsyncStoreMixin, BaseStore, MultilineDisplayMixin

Define a base class for file-based key-value stores.

Each value is persisted as its own file in a directory, using :mod:iden.io to read and write files. Keys are mapped to filenames with urllib.parse.quote, so keys containing characters like / or .. cannot escape the store's directory. There is no index of keys beyond the directory listing itself, so :meth:keys, :meth:filter, and :meth:iter_batches all work by scanning the directory.

Subclasses only need to set :attr:extension and implement :meth:_save and :meth:_load, which control how a value is serialized to and from a file (see :class:JsonFileStore for a JSON encoding and :class:PickleFileStore for a pickle encoding).

Parameters:

Name Type Description Default
path str | PathLike[str]

The directory where value files are stored. Created automatically if it does not already exist.

required
**kwargs Any

Additional keyword arguments to pass to the underlying iden.io save function.

{}

persista.store.BaseFileStore.extension abstractmethod property

extension: str

File extension (including the leading dot) used for value files.

persista.store.BaseFileStore.path property

path: Path

The directory where value files are stored.

persista.store.BaseLmdbStore

Bases: ThreadedAsyncStoreMixin, BaseStore, MultilineDisplayMixin

Define a base class for LMDB-backed key-value stores.

LMDB is an embedded, memory-mapped key-value store backed by a single-directory environment on disk, so unlike Redis this store needs no separate server process and no explicit tracking of keys: the environment's own B+tree already provides ordered iteration, membership checks, and a cheap entry count. :meth:filter is still implemented client-side by scanning every value in the store, since LMDB has no query language for matching on the content of a value.

Subclasses only need to implement :meth:_encode and :meth:_decode, which control how a value is serialized to and from what is stored in LMDB (see :class:LmdbStore for a JSON encoding and :class:PickleLmdbStore for a pickle encoding).

Parameters:

Name Type Description Default
path str | PathLike[str]

The directory where the LMDB environment is stored. Created automatically if it does not already exist.

required
map_size int

The maximum size in bytes of the memory map, i.e. the upper bound on the total size of the environment (keys and values combined). Passed to lmdb.open.

_DEFAULT_MAP_SIZE
**kwargs Any

Additional keyword arguments to pass to lmdb.open.

{}

persista.store.BasePostgresStore

Bases: BaseStore, MultilineDisplayMixin

Define a base class for Postgres-backed key-value stores.

Holds both a psycopg.Connection (opened eagerly in __init__) and a psycopg.AsyncConnection (opened lazily, on first async use, guarded by an asyncio.Lock). Unlike :class:~persista.store.sqlite.BaseSQLiteStore (where aiosqlite is a separate optional package layered on stdlib sqlite3), psycopg bundles both psycopg.Connection and psycopg.AsyncConnection in the same package, which is already a hard requirement for the sync side -- so every async method here always uses :class:psycopg.AsyncConnection directly, with no asyncio.to_thread fallback.

A single table (named by the table argument, "store" by default) backs every value; the primary key column is named by :attr:_key_column. :meth:get, :meth:get_many, :meth:filter, and :meth:iter_batches (and their async equivalents) all query the full row and hand it to :meth:_row_to_value to turn it back into a value dict, which is what lets subclasses differ in how a value is laid out across columns (a single JSONB column vs. typed columns plus a JSONB overflow column) without duplicating any of the surrounding query logic. This mirrors :class:~persista.store.sqlite.BaseSQLiteStore.

Subclasses only need to implement :meth:_create_table_sql, :meth:_row_to_value, :meth:_build_filter_condition, :meth:_set_many, and :meth:_aset_many (see :class:PostgresStore for a JSONB-only layout and :class:~persista.store.postgres.TypedPostgresStore for an optionally typed one).

Parameters:

Name Type Description Default
conninfo str

The connection string/DSN passed to psycopg.connect (e.g. "postgresql://user:pass@localhost/dbname").

required
table str

The name of the table backing this store. Must be a valid SQL identifier (letters, digits, underscores, not starting with a digit).

'store'
**kwargs Any

Additional keyword arguments to pass to psycopg.connect/psycopg.AsyncConnection.connect.

{}

persista.store.BaseRedisStore

Bases: BaseStore, MultilineDisplayMixin

Define a base class for Redis-backed key-value stores.

A Redis set at __keys__ tracks the keys currently in the store, which allows :meth:count, :meth:keys, and :meth:contains_many to avoid scanning the whole keyspace. Unlike the SQL-backed stores, Redis has no query language for matching on the content of a value, so :meth:filter is implemented client-side by scanning every value in the store.

Subclasses only need to implement :meth:_encode and :meth:_decode, which control how a value is serialized to and from what is stored in Redis (see :class:RedisStore for a JSON encoding and :class:~persista.store.redis_pickle.PickleRedisStore for a pickle encoding).

Every sync method runs through the eagerly-created redis.Redis client; every async (a-prefixed) method runs through a redis.asyncio.Redis client, created lazily on first use, since redis-py bundles both under one package (unlike SQLite/aiosqlite, no asyncio.to_thread fallback is needed here).

Parameters:

Name Type Description Default
url str

The Redis connection URL passed to redis.Redis.from_url (e.g. "redis://localhost:6379/0").

'redis://localhost:6379/0'
**kwargs Any

Additional keyword arguments to pass to redis.Redis.from_url.

{}

persista.store.BaseSQLiteStore

Bases: BaseStore, MultilineDisplayMixin

Define a base class for SQLite-backed key-value stores.

A single store table backs every value; the primary key column is named by :attr:_key_column. :meth:get, :meth:get_many, :meth:filter, and :meth:iter_batches all query the full row and hand it to :meth:_row_to_value to turn it back into a value dict, which is what lets subclasses differ in how a value is laid out across columns (a single JSON column vs. typed columns plus a JSON overflow column) without duplicating any of the surrounding query logic.

Subclasses only need to implement :meth:_create_table_sql, :meth:_row_to_value, :meth:_filter_expr, and :meth:_set_many (see :class:SQLiteStore for a JSON-only layout and :class:~persista.store.sqlite_typed.TypedSQLiteStore for an optionally typed one).

The constructor mirrors :func:sqlite3.connect: the first positional argument is the database argument accepted by sqlite3.connect (a path, ":memory:", or a file: URI when uri=True is passed), and any additional keyword arguments are forwarded as-is. Use :meth:from_path for a more convenient constructor that builds the appropriate URI for you, including read-only access.

Parameters:

Name Type Description Default
database Path | str

The database argument passed to sqlite3.connect (path, ":memory:", or file: URI).

required
**kwargs Any

Additional keyword arguments to pass to sqlite3.connect (e.g. uri=True, timeout, check_same_thread).

{}

persista.store.BaseSQLiteStore.from_path classmethod

from_path(
    path: Path | str,
    *,
    read_only: bool = False,
    **kwargs: Any
) -> Self

Construct a store from a file path.

Builds the appropriate file: URI for sqlite3.connect, including read-only access, so callers don't need to construct SQLite URIs themselves.

Parameters:

Name Type Description Default
path Path | str

Path to the SQLite file, or ":memory:" for an in-memory database (useful for testing).

required
read_only bool

If True, open the database in read-only mode. The database file must already exist.

False
**kwargs Any

Additional keyword arguments to pass to the constructor (and, from there, to sqlite3.connect).

{}

Returns:

Type Description
Self

A new store connected to path.

Example
>>> import tempfile
>>> from persista.store import SQLiteStore
>>> with tempfile.TemporaryDirectory() as tmpdir:
...     with SQLiteStore.from_path(f"{tmpdir}/data.db") as store:
...         store.set("1", {"title": "Intro to Python"})
...         store.get("1")
...
{'title': 'Intro to Python'}

persista.store.BaseSQLiteStore.get_columns_info

get_columns_info() -> dict[str, str]

Return the column names and types of the store's table.

Returns:

Type Description
dict[str, str]

A mapping of column name to SQLite declared type.

Example
>>> from persista.store import SQLiteStore
>>> with SQLiteStore(":memory:") as store:
...     store.get_columns_info()
...
{'key': 'TEXT', 'value': 'JSON'}

persista.store.BaseSQLiteStore.show_columns_info

show_columns_info() -> None

Print the store's table column names and types to stdout.

This is a convenience wrapper around :meth:get_columns_info for interactive/debugging use. For programmatic access, use :meth:get_columns_info instead.

persista.store.BaseStore

Bases: ABC

Abstract base class for key-value stores.

Defines the common interface that all key-value store implementations must provide. Values are stored as dicts, which allows :meth:filter to match on the content of a value.

Every operation that touches the underlying store has a sync method (e.g. :meth:get) and an async twin prefixed with a (e.g. :meth:aget), both callable on the same instance -- there is no separate async class. Implementations back these with whatever mix of blocking and native-async drivers suits the backend (see subclasses for details); callers only need to pick which method to call based on whether they're in sync or async code.

To implement a custom store, subclass :class:BaseStore and implement all abstract methods.

Implementations are expected to support use as a sync context manager (with SomeStore(...) as store: ..., calling :meth:open on entry and :meth:close on exit) and as an async context manager (async with SomeStore(...) as store: ..., calling :meth:aopen on entry and :meth:aclose on exit).

Constructing a store does not connect to the underlying backend: implementations must defer that to :meth:open/:meth:aopen, so every other method (including :meth:close) raises until the store has been opened, either explicitly or via the context manager.

Example
>>> from persista.store import InMemoryStore
>>> with InMemoryStore() as store:  # calls open()/close() automatically
...     store.set("user:1", {"name": "Ann"})
...     store.get("user:1")
...
{'name': 'Ann'}

persista.store.BaseStore.closed abstractmethod property

closed: bool

Indicate whether the store is closed.

Returns:

Type Description
bool

True if the store has been closed, False if it is

bool

open and ready to use.

persista.store.BaseStore.aclear abstractmethod async

aclear() -> None

Async equivalent of :meth:clear.

persista.store.BaseStore.aclose abstractmethod async

aclose() -> None

Async equivalent of :meth:close.

persista.store.BaseStore.acontains abstractmethod async

acontains(key: str) -> bool

Async equivalent of :meth:contains.

persista.store.BaseStore.acontains_many abstractmethod async

acontains_many(keys: list[str]) -> list[bool]

Async equivalent of :meth:contains_many.

persista.store.BaseStore.acount abstractmethod async

acount() -> int

Async equivalent of :meth:count.

persista.store.BaseStore.adelete abstractmethod async

adelete(key: str) -> None

Async equivalent of :meth:delete.

persista.store.BaseStore.adelete_many abstractmethod async

adelete_many(keys: list[str]) -> None

Async equivalent of :meth:delete_many.

persista.store.BaseStore.afilter abstractmethod async

afilter(**field_filters: Any) -> list[dict[str, Any]]

Async equivalent of :meth:filter.

persista.store.BaseStore.aget abstractmethod async

aget(key: str) -> dict[str, Any] | None

Async equivalent of :meth:get.

persista.store.BaseStore.aget_many abstractmethod async

aget_many(keys: list[str]) -> list[dict[str, Any] | None]

Async equivalent of :meth:get_many.

persista.store.BaseStore.aiter_batches abstractmethod

aiter_batches(
    batch_size: int = 32,
) -> AsyncIterator[dict[str, dict[str, Any]]]

Async equivalent of :meth:iter_batches.

persista.store.BaseStore.akeys abstractmethod

akeys() -> AsyncIterator[str]

Async equivalent of :meth:keys.

persista.store.BaseStore.aopen abstractmethod async

aopen() -> None

Async equivalent of :meth:open.

persista.store.BaseStore.aset abstractmethod async

aset(
    key: str,
    value: dict[str, Any],
    on_conflict: OnConflict = "overwrite",
) -> None

Async equivalent of :meth:set.

persista.store.BaseStore.aset_batches async

aset_batches(
    items: Iterable[tuple[str, dict[str, Any]]],
    batch_size: int = 32,
    on_conflict: OnConflict = "overwrite",
) -> None

Async equivalent of :meth:set_batches.

persista.store.BaseStore.aset_many abstractmethod async

aset_many(
    items: Mapping[str, dict[str, Any]],
    on_conflict: OnConflict = "overwrite",
) -> None

Async equivalent of :meth:set_many.

persista.store.BaseStore.avalues async

avalues(
    batch_size: int = 32,
) -> AsyncIterator[dict[str, Any]]

Async equivalent of :meth:values.

persista.store.BaseStore.clear abstractmethod

clear() -> None

Remove every key-value pair from the store.

This is equivalent to resetting the store to empty, without closing it.

persista.store.BaseStore.close abstractmethod

close() -> None

Close the store and release any underlying resources (e.g. database connections, file handles).

Implementations should make repeated calls to close() safe (i.e. idempotent), since :meth:__exit__ calls it unconditionally and callers may also close a store manually before using it as a context manager.

persista.store.BaseStore.contains abstractmethod

contains(key: str) -> bool

Check if the key exists in the store.

Parameters:

Name Type Description Default
key str

The key to check.

required

Returns:

Type Description
bool

True if the key exists in the store, False otherwise.

persista.store.BaseStore.contains_many abstractmethod

contains_many(keys: list[str]) -> list[bool]

Check which keys exist in the store.

Parameters:

Name Type Description Default
keys list[str]

The keys to check.

required

Returns:

Type Description
list[bool]

A list of booleans, in the same order as keys, where

list[bool]

each entry is True if the corresponding key exists in

list[bool]

the store and False otherwise.

persista.store.BaseStore.count abstractmethod

count() -> int

Return the total number of key-value pairs in the store.

Returns:

Type Description
int

The number of key-value pairs currently stored.

persista.store.BaseStore.delete abstractmethod

delete(key: str) -> None

Delete a value by its key.

Keys that do not exist should be silently ignored.

Parameters:

Name Type Description Default
key str

The key of the value to delete.

required

persista.store.BaseStore.delete_many abstractmethod

delete_many(keys: list[str]) -> None

Delete multiple values by their keys.

Keys that do not exist should be silently ignored.

Parameters:

Name Type Description Default
keys list[str]

The keys of the values to delete.

required

persista.store.BaseStore.filter abstractmethod

filter(**field_filters: Any) -> list[dict[str, Any]]

Retrieve values whose content matches all provided field filters.

All filters should be combined with AND. Each keyword argument matches the corresponding key in the stored value exactly.

Parameters:

Name Type Description Default
**field_filters Any

Key-value pairs where each key is a field name within a stored value and the value is the exact value to match. Calling with no arguments should return every value in the store.

{}

Returns:

Type Description
list[dict[str, Any]]

A list of matching values.

persista.store.BaseStore.from_uri abstractmethod classmethod

from_uri(uri: str, *, read_only: bool = False) -> Self

Reconstruct a store from a URI produced by :meth:to_uri.

Parameters:

Name Type Description Default
uri str

A URI produced by :meth:to_uri (of a store of this same class).

required
read_only bool

If True and this store type supports a read-only connection mode, open it read-only. Ignored by store types with no such mode.

False

Returns:

Type Description
Self

A new store instance.

persista.store.BaseStore.get abstractmethod

get(key: str) -> dict[str, Any] | None

Retrieve a single value by its key.

Parameters:

Name Type Description Default
key str

The key to look up.

required

Returns:

Type Description
dict[str, Any] | None

The value associated with key, or None if the

dict[str, Any] | None

key is not found.

persista.store.BaseStore.get_many abstractmethod

get_many(keys: list[str]) -> list[dict[str, Any] | None]

Retrieve multiple values by their keys.

Parameters:

Name Type Description Default
keys list[str]

The keys to look up.

required

Returns:

Type Description
list[dict[str, Any] | None]

A list the same length as keys, with the

list[dict[str, Any] | None]

corresponding value for each key that exists, or

list[dict[str, Any] | None]

None for keys that are not found.

persista.store.BaseStore.iter_batches abstractmethod

iter_batches(
    batch_size: int = 32,
) -> Iterator[dict[str, dict[str, Any]]]

Yield key-value pairs in batches, avoiding loading the whole store into memory at once.

This is the scalable equivalent of :meth:values: instead of materializing every value as a single mapping, it streams them from the underlying store in chunks of batch_size.

Parameters:

Name Type Description Default
batch_size int

The maximum number of pairs to yield per batch. Must be a positive integer.

32

Yields:

Type Description
dict[str, dict[str, Any]]

Dicts mapping key to value, each with at most

dict[str, dict[str, Any]]

batch_size entries, in the same order as

dict[str, dict[str, Any]]

meth:values. The last batch may contain fewer than

dict[str, dict[str, Any]]

batch_size entries.

persista.store.BaseStore.keys abstractmethod

keys() -> Iterator[str]

Iterate over all keys in the store.

Yields:

Type Description
str

Every key currently in the store.

persista.store.BaseStore.open abstractmethod

open() -> None

Connect to the underlying backend and prepare the store for use (e.g. open a database connection, create a directory).

The constructor must not do this itself: implementations connect lazily, only once open() (or :meth:__enter__) is called. Implementations should make repeated calls to open() safe (i.e. idempotent), since a store may be reopened after :meth:close.

persista.store.BaseStore.set abstractmethod

set(
    key: str,
    value: dict[str, Any],
    on_conflict: OnConflict = "overwrite",
) -> None

Add a single key-value pair to the store.

Parameters:

Name Type Description Default
key str

The key to set.

required
value dict[str, Any]

The value to associate with key.

required
on_conflict OnConflict

The strategy to use if key already exists in the store:

  • "raise": raise a :class:KeyError and leave the existing value unchanged.
  • "skip": leave the existing value unchanged.
  • "overwrite": replace the existing value with value.
  • "merge": shallow-merge value into the existing value, with fields from value taking precedence on overlapping keys.
'overwrite'

Raises:

Type Description
KeyError

If on_conflict is "raise" and key already exists.

persista.store.BaseStore.set_batches

set_batches(
    items: Iterable[tuple[str, dict[str, Any]]],
    batch_size: int = 32,
    on_conflict: OnConflict = "overwrite",
) -> None

Add key-value pairs from an iterable, writing them to the store in mini-batches.

This is the streaming equivalent of :meth:set_many: instead of requiring every key-value pair to be materialized into a single mapping upfront, it consumes items lazily and writes at most batch_size pairs at a time. This keeps memory usage bounded when items comes from a generator over a large or unbounded source.

Parameters:

Name Type Description Default
items Iterable[tuple[str, dict[str, Any]]]

An iterable of (key, value) pairs to add.

required
batch_size int

The maximum number of pairs to write to the store per underlying :meth:set_many call. Must be a positive integer.

32
on_conflict OnConflict

The strategy to use for keys that already exist in the store. See :meth:set for the meaning of each option. Applied independently per batch, so with "raise" a conflict is only detected once the offending batch is written, not upfront.

'overwrite'

Raises:

Type Description
KeyError

If on_conflict is "raise" and any key already exists.

persista.store.BaseStore.set_many abstractmethod

set_many(
    items: Mapping[str, dict[str, Any]],
    on_conflict: OnConflict = "overwrite",
) -> None

Add multiple key-value pairs to the store.

Parameters:

Name Type Description Default
items Mapping[str, dict[str, Any]]

The values to add, keyed by their unique key.

required
on_conflict OnConflict

The strategy to use for keys in items that already exist in the store. See :meth:set for the meaning of each option.

'overwrite'

Raises:

Type Description
KeyError

If on_conflict is "raise" and any key in items already exists.

persista.store.BaseStore.to_uri abstractmethod

to_uri() -> str

Return a URI that identifies where this store's data lives.

Returns:

Type Description
str

A URI. For a store backed by a file/database, passing

str

this URI to :meth:from_uri reconnects to the same

str

data. For a process-local store, the URI carries no

str

reconnection information and :meth:from_uri returns a

str

fresh, empty store.

persista.store.BaseStore.values

values(batch_size: int = 32) -> Iterator[dict[str, Any]]

Iterate over all values without loading them all into memory at once.

Parameters:

Name Type Description Default
batch_size int

The batch size used internally when pulling values from the underlying store. Does not affect the granularity of what is yielded -- values are always yielded one at a time.

32

Yields:

Type Description
dict[str, Any]

One value at a time, in the same order as

dict[str, Any]

meth:iter_batches.

persista.store.DuckDBStore

Bases: BaseDuckDBStore

A DuckDB-backed key-value store.

Persists values to a DuckDB database and supports adding, retrieving, filtering, and deleting key-value pairs. Each value is stored as a JSON column, which provides flexibility for arbitrary value fields without requiring a fixed schema.

Parameters:

Name Type Description Default
database Path | str

Path to the DuckDB file, or ":memory:" for an in-memory database (useful for testing). Matches the database argument name used by duckdb.connect.

':memory:'
**kwargs Any

Additional keyword arguments to pass to duckdb.connect.

{}
Example
>>> from persista.store import DuckDBStore
>>> with DuckDBStore(":memory:") as store:
...     store.set_many(
...         {
...             "1": {
...                 "title": "Intro to Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "2": {
...                 "title": "Advanced Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "3": {"title": "History of Rome", "author": "Bob", "category": "History"},
...         }
...     )
...     len(store.filter(author="Alice"))
...     len(store.filter(author="Alice", category="Programming"))
...     len(store.filter(category="History"))
...
2
2
1

persista.store.InMemoryStore

Bases: ThreadedAsyncStoreMixin, BaseStore, InlineDisplayMixin

A :class:~persista.store.BaseStore implementation backed by a plain dict.

Values are held entirely in process memory -- nothing is persisted to disk. This is primarily useful for testing, small-scale exploration, or pipelines that don't need durability. Async methods (aget, aset, ...) are provided by :class:~persista.store._threaded.ThreadedAsyncStoreMixin, which runs each sync call in a worker thread.

Values are deep-copied on both write and read so that mutating a value returned by this store (or a value passed into :meth:set / :meth:set_many) never affects the store's internal state. This trades some performance for isolation; for very large values or hot loops, consider a store that doesn't copy on every access.

Example
>>> from persista.store import InMemoryStore
>>> with InMemoryStore() as store:
...     store.set("1", {"text": "hello"})
...     store.count()
...     store.get("1")
...
1
{'text': 'hello'}

persista.store.JsonFileStore

Bases: BaseFileStore

A file-based key-value store that serializes each value to its own JSON file.

Values are stored in human-readable form and can be read by any JSON-compatible tool, but only JSON-compatible value fields (str, int, float, bool, None, list, dict) are supported; use :class:PickleFileStore if you need to persist arbitrary Python objects.

Parameters:

Name Type Description Default
path str | PathLike[str]

The directory where value files are stored. Created automatically if it does not already exist.

required
**kwargs Any

Additional keyword arguments to pass to iden.io.save_json.

{}
Example
>>> import tempfile
>>> from persista.store import JsonFileStore
>>> with tempfile.TemporaryDirectory() as tmpdir, JsonFileStore(tmpdir) as store:
...     store.set_many(
...         {
...             "1": {
...                 "title": "Intro to Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "2": {
...                 "title": "Advanced Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "3": {"title": "History of Rome", "author": "Bob", "category": "History"},
...         }
...     )
...     len(store.filter(author="Alice"))
...
2

persista.store.LmdbStore

Bases: BaseLmdbStore

An LMDB-backed key-value store.

Persists values to an LMDB environment and supports adding, retrieving, filtering, and deleting key-value pairs. Each value is stored as a JSON-encoded string, which provides flexibility for arbitrary value fields without requiring a fixed schema and can be read back by any LMDB client regardless of language. This means only JSON-compatible value fields (str, int, float, bool, None, list, dict) are supported; use :class:PickleLmdbStore if you need to persist arbitrary Python objects.

Parameters:

Name Type Description Default
path str | PathLike[str]

The directory where the LMDB environment is stored. Created automatically if it does not already exist.

required
map_size int

The maximum size in bytes of the memory map, i.e. the upper bound on the total size of the environment (keys and values combined). Passed to lmdb.open.

_DEFAULT_MAP_SIZE
**kwargs Any

Additional keyword arguments to pass to lmdb.open.

{}
Example
>>> import tempfile
>>> from persista.store import LmdbStore
>>> with tempfile.TemporaryDirectory() as tmpdir, LmdbStore(tmpdir) as store:
...     store.set_many(
...         {
...             "1": {
...                 "title": "Intro to Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "2": {
...                 "title": "Advanced Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "3": {"title": "History of Rome", "author": "Bob", "category": "History"},
...         }
...     )
...     len(store.filter(author="Alice"))
...
2

persista.store.NullStore

Bases: BaseStore, InlineDisplayMixin

A :class:~persista.store.BaseStore implementation that forgets everything written to it.

Every :meth:set/:meth:aset/:meth:set_many/:meth:aset_many call is silently discarded, so :meth:get/:meth:aget always report a miss and the store always reports as empty. Because nothing is ever stored, on_conflict="raise" can never actually raise KeyError here, unlike other :class:~persista.store.BaseStore implementations. This is primarily useful for plugging into :class:~persista.cache.cache.Cache to disable caching without changing any calling code: every lookup misses, so get_or_compute/memoize always recompute the value.

There is no I/O to offload here, so the async methods run inline rather than through a thread pool.

Example
>>> from persista.store import NullStore
>>> from persista.cache import Cache
>>> with Cache(store=NullStore()) as cache:
...     cache.set("greeting", "hello")
...     cache.get("greeting") is None
...
True

persista.store.PickleFileStore

Bases: BaseFileStore

A file-based key-value store that serializes each value to its own pickle file.

Unlike :class:JsonFileStore, this store can persist arbitrary Python objects within a value's fields (tuples, sets, custom classes, etc.), not just JSON-compatible types. The tradeoff is that value files are opaque binary blobs (not human-readable), and, since :func:pickle.loads can execute arbitrary code, this store must never be pointed at a directory that isn't fully trusted.

Parameters:

Name Type Description Default
path str | PathLike[str]

The directory where value files are stored. Created automatically if it does not already exist.

required
**kwargs Any

Additional keyword arguments to pass to iden.io.save_pickle.

{}
Example
>>> import tempfile
>>> from persista.store import PickleFileStore
>>> with tempfile.TemporaryDirectory() as tmpdir, PickleFileStore(tmpdir) as store:
...     store.set("1", {"title": "Intro to Python", "tags": ("python", "intro")})
...     store.get("1")
...
{'title': 'Intro to Python', 'tags': ('python', 'intro')}

persista.store.PickleLmdbStore

Bases: BaseLmdbStore

An LMDB-backed key-value store that serializes values with pickle instead of JSON.

Unlike :class:LmdbStore, this store can persist arbitrary Python objects within a value's fields (tuples, sets, custom classes, etc.), not just JSON-compatible types. The tradeoff is that values are opaque binary blobs from outside Python (not human-readable, not inspectable from non-Python LMDB clients), and, since :func:pickle.loads can execute arbitrary code, this store must never be pointed at an LMDB environment that isn't fully trusted.

Parameters:

Name Type Description Default
path str | PathLike[str]

The directory where the LMDB environment is stored. Created automatically if it does not already exist.

required
map_size int

The maximum size in bytes of the memory map, i.e. the upper bound on the total size of the environment (keys and values combined). Passed to lmdb.open.

_DEFAULT_MAP_SIZE
**kwargs Any

Additional keyword arguments to pass to lmdb.open.

{}
Example
>>> import tempfile
>>> from persista.store import PickleLmdbStore
>>> with tempfile.TemporaryDirectory() as tmpdir, PickleLmdbStore(tmpdir) as store:
...     store.set("1", {"title": "Intro to Python", "tags": ("python", "intro")})
...     store.get("1")
...
{'title': 'Intro to Python', 'tags': ('python', 'intro')}

persista.store.PickleRedisStore

Bases: BaseRedisStore

A Redis-backed key-value store that serializes values with pickle instead of JSON.

Unlike :class:~persista.store.RedisStore, this store can persist arbitrary Python objects within a value's fields (tuples, sets, custom classes, etc.), not just JSON-compatible types. The tradeoff is that values are opaque binary blobs from outside Python (not human-readable, not inspectable from non-Python Redis clients), and, since :func:pickle.loads can execute arbitrary code, this store must never be pointed at a Redis instance that isn't fully trusted.

Parameters:

Name Type Description Default
url str

The Redis connection URL passed to redis.Redis.from_url (e.g. "redis://localhost:6379/0").

'redis://localhost:6379/0'
**kwargs Any

Additional keyword arguments to pass to redis.Redis.from_url.

{}
Example
>>> from persista.store import PickleRedisStore
>>> with PickleRedisStore("redis://localhost:6379/0") as store:  # doctest: +SKIP
...     store.set("1", {"title": "Intro to Python", "tags": {"python", "intro"}})
...     store.get("1")
...
{'title': 'Intro to Python', 'tags': {'python', 'intro'}}

persista.store.PickleSQLiteStore

Bases: BaseSQLiteStore

A SQLite-backed key-value store that serializes values with pickle instead of JSON.

Unlike :class:SQLiteStore, this store can persist arbitrary Python objects within a value's fields (tuples, sets, datetimes, custom classes, etc.), not just JSON-compatible types. The tradeoff is that values are opaque binary blobs: SQLite's json1 functions can't see into them, so :meth:filter can't push field comparisons down to SQL and instead falls back to scanning and unpickling every row in Python. Since :func:pickle.loads can execute arbitrary code, this store must never be pointed at a database file that isn't fully trusted.

The constructor mirrors :func:sqlite3.connect directly. For the common case of opening a file by path (optionally read-only), use :meth:from_path instead.

Parameters:

Name Type Description Default
database Path | str

The database argument passed to sqlite3.connect (path, ":memory:", or file: URI).

':memory:'
**kwargs Any

Additional keyword arguments to pass to sqlite3.connect.

{}
Example
>>> from persista.store import PickleSQLiteStore
>>> with PickleSQLiteStore(":memory:") as store:
...     store.set("1", {"title": "Intro to Python", "tags": ["python", "intro"]})
...     store.get("1")
...
{'title': 'Intro to Python', 'tags': ['python', 'intro']}

persista.store.PostgresStore

Bases: BasePostgresStore

A Postgres-backed key-value store.

Persists values to a Postgres database and supports adding, retrieving, filtering, and deleting key-value pairs. Each value is stored as a JSONB column, which provides flexibility for arbitrary value fields without requiring a fixed schema.

Parameters:

Name Type Description Default
conninfo str

The connection string/DSN passed to psycopg.connect (e.g. "postgresql://user:pass@localhost/dbname").

required
table str

The name of the table backing this store.

'store'
**kwargs Any

Additional keyword arguments to pass to psycopg.connect.

{}
Example
>>> from persista.store import PostgresStore
>>> with PostgresStore(  # doctest: +SKIP
...     "postgresql://user:pass@localhost/dbname"
... ) as store:
...     store.set_many(
...         {
...             "1": {"title": "Intro to Python", "author": "Alice"},
...             "2": {"title": "Advanced Python", "author": "Alice"},
...         }
...     )
...     len(store.filter(author="Alice"))
...
2

persista.store.RedisStore

Bases: BaseRedisStore

A Redis-backed key-value store.

Persists values to Redis and supports adding, retrieving, filtering, and deleting key-value pairs. Each value is stored as a JSON string, which provides flexibility for arbitrary value fields without requiring a fixed schema, is human-readable directly from Redis, and can be read by any Redis client regardless of language. This means only JSON-compatible value fields (str, int, float, bool, None, list, dict) are supported; use :class:~persista.store.redis_pickle.PickleRedisStore if you need to persist arbitrary Python objects.

Parameters:

Name Type Description Default
url str

The Redis connection URL passed to redis.Redis.from_url (e.g. "redis://localhost:6379/0").

'redis://localhost:6379/0'
**kwargs Any

Additional keyword arguments to pass to redis.Redis.from_url.

{}
Example
>>> from persista.store import RedisStore
>>> with RedisStore("redis://localhost:6379/0") as store:  # doctest: +SKIP
...     store.set_many(
...         {
...             "1": {
...                 "title": "Intro to Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "2": {
...                 "title": "Advanced Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "3": {"title": "History of Rome", "author": "Bob", "category": "History"},
...         }
...     )
...     len(store.filter(author="Alice"))
...
2

persista.store.SQLiteStore

Bases: BaseSQLiteStore

A SQLite-backed key-value store.

Persists values to a SQLite database and supports adding, retrieving, filtering, and deleting key-value pairs. Each value is stored as a JSON column (using SQLite's built-in json1 functions), which provides flexibility for arbitrary value fields without requiring a fixed schema.

The constructor mirrors :func:sqlite3.connect directly. For the common case of opening a file by path (optionally read-only), use :meth:from_path instead.

Parameters:

Name Type Description Default
database Path | str

The database argument passed to sqlite3.connect (path, ":memory:", or file: URI).

':memory:'
**kwargs Any

Additional keyword arguments to pass to sqlite3.connect.

{}
Example
>>> from persista.store import SQLiteStore
>>> with SQLiteStore(":memory:") as store:
...     store.set_many(
...         {
...             "1": {
...                 "title": "Intro to Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "2": {
...                 "title": "Advanced Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "3": {"title": "History of Rome", "author": "Bob", "category": "History"},
...         }
...     )
...     len(store.filter(author="Alice"))
...     len(store.filter(author="Alice", category="Programming"))
...     len(store.filter(category="History"))
...
2
2
1

persista.store.TypedDuckDBStore

Bases: BaseDuckDBStore

A DuckDB-backed key-value store with an optional typed value schema.

Persists values to a DuckDB database and supports adding, retrieving, and filtering by value fields. An optional value_schema maps known value field names to DuckDB types. Known fields are stored as typed columns for fast, index-friendly queries. Any value fields not in the schema are stored in an extra JSON overflow column, so nothing is lost.

Parameters:

Name Type Description Default
database Path | str

Path to the DuckDB file, or ":memory:" for an in-memory database (useful for testing). Matches the database argument name used by duckdb.connect.

':memory:'
value_schema dict[str, str] | None

Optional mapping of value field names to DuckDB type strings (e.g. {"author": "VARCHAR", "year": "INTEGER"}). Fields in the schema get native typed columns; all other value fields go into the extra JSON overflow column. Defaults to None, which stores every value field as JSON only.

None
**kwargs Any

Additional keyword arguments to pass to duckdb.connect.

{}
Example
>>> from persista.store import TypedDuckDBStore
>>> schema = {"author": "VARCHAR", "year": "INTEGER", "category": "VARCHAR"}
>>> with TypedDuckDBStore(":memory:", value_schema=schema) as store:
...     store.set_many(
...         {
...             "1": {
...                 "title": "Intro to Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "2": {
...                 "title": "Advanced Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "3": {"title": "History of Rome", "author": "Bob", "category": "History"},
...         }
...     )
...     len(store.filter(author="Alice"))
...     len(store.filter(author="Alice", category="Programming"))
...     len(store.filter(category="History"))
...
2
2
1
Note

:meth:from_uri reconstructs the store with an empty value_schema, so value fields that were stored in typed columns won't appear in :meth:get/:meth:filter results until the caller re-supplies the original value_schema to a fresh construction; the data itself isn't lost in the database, just not visible through the reconstructed store.

persista.store.TypedPostgresStore

Bases: BasePostgresStore

A Postgres-backed key-value store with an optional typed value schema.

Persists values to a Postgres database and supports adding, retrieving, and filtering by value fields. An optional value_schema maps known value field names to Postgres types. Known fields are stored as typed columns for fast, index-friendly queries. Any value fields not in the schema are stored in an extra JSONB overflow column, so nothing is lost. Mirrors :class:~persista.store.sqlite.TypedSQLiteStore.

Parameters:

Name Type Description Default
conninfo str

The connection string/DSN passed to psycopg.connect.

required
table str

The name of the table backing this store.

'store'
value_schema dict[str, str] | None

Optional mapping of value field names to Postgres type strings (e.g. {"author": "TEXT", "year": "INTEGER"}). Fields in the schema get native typed columns; all other value fields go into the extra JSONB overflow column. Defaults to None, which stores every value field as JSONB only.

None
**kwargs Any

Additional keyword arguments to pass to psycopg.connect.

{}
Example
>>> from persista.store import TypedPostgresStore
>>> schema = {"author": "TEXT", "year": "INTEGER"}
>>> with TypedPostgresStore(  # doctest: +SKIP
...     "postgresql://user:pass@localhost/dbname", value_schema=schema
... ) as store:
...     store.set_many(
...         {
...             "1": {"title": "Intro to Python", "author": "Alice", "year": 2022},
...             "2": {"title": "History of Rome", "author": "Bob", "year": 2021},
...         }
...     )
...     len(store.filter(author="Alice"))
...
1
Note

:meth:from_uri reconstructs the store with an empty value_schema and the default table name, so value fields that were stored in typed columns won't appear in :meth:get/:meth:filter results until the caller re-supplies the original value_schema/table to a fresh construction; the data itself isn't lost in the database, just not visible through the reconstructed store.

persista.store.TypedSQLiteStore

Bases: BaseSQLiteStore

A SQLite-backed key-value store with an optional typed value schema.

Persists values to a SQLite database and supports adding, retrieving, and filtering by value fields. An optional value_schema maps known value field names to SQLite types. Known fields are stored as typed columns for fast, index-friendly queries. Any value fields not in the schema are stored in an extra JSON overflow column, so nothing is lost.

The constructor mirrors :func:sqlite3.connect directly (plus the value_schema argument). For the common case of opening a file by path (optionally read-only), use :meth:from_path instead.

Parameters:

Name Type Description Default
database Path | str

The database argument passed to sqlite3.connect (path, ":memory:", or file: URI).

':memory:'
value_schema dict[str, str] | None

Optional mapping of value field names to SQLite type strings (e.g. {"author": "TEXT", "year": "INTEGER"}). Fields in the schema get native typed columns; all other value fields go into the extra JSON overflow column. Defaults to None, which stores every value field as JSON only.

None
**kwargs Any

Additional keyword arguments to pass to sqlite3.connect.

{}
Example
>>> from persista.store import TypedSQLiteStore
>>> schema = {"author": "TEXT", "year": "INTEGER", "category": "TEXT"}
>>> with TypedSQLiteStore(":memory:", value_schema=schema) as store:
...     store.set_many(
...         {
...             "1": {
...                 "title": "Intro to Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "2": {
...                 "title": "Advanced Python",
...                 "author": "Alice",
...                 "category": "Programming",
...             },
...             "3": {"title": "History of Rome", "author": "Bob", "category": "History"},
...         }
...     )
...     len(store.filter(author="Alice"))
...     len(store.filter(author="Alice", category="Programming"))
...     len(store.filter(category="History"))
...
2
2
1
Note

:meth:from_uri reconstructs the store with an empty value_schema, so value fields that were stored in typed columns won't appear in :meth:get/:meth:filter results until the caller re-supplies the original value_schema to a fresh construction; the data itself isn't lost in the database, just not visible through the reconstructed store.

persista.store.normalize_on_conflict

normalize_on_conflict(on_conflict: str) -> OnConflict

Normalize and validate an on_conflict value.

Parameters:

Name Type Description Default
on_conflict str

The value to normalize. Matched case-insensitively, with leading/trailing whitespace stripped.

required

Returns:

Type Description
OnConflict

The normalized value, one of :data:ON_CONFLICT_VALUES.

Raises:

Type Description
ValueError

If the normalized value is not one of :data:ON_CONFLICT_VALUES.

Example
>>> from persista.store.validation import normalize_on_conflict
>>> normalize_on_conflict(" Overwrite ")
'overwrite'

persista.store.register_scheme

register_scheme(
    scheme: str, store_cls: type[BaseStore]
) -> None

Register a store class for a URI scheme used by :func:store_from_uri.

Parameters:

Name Type Description Default
scheme str

The URI scheme to associate with store_cls, e.g. "memory". Overwrites any class already registered for this scheme.

required
store_cls type[BaseStore]

The BaseStore subclass to dispatch to for scheme. Must implement from_uri.

required
Example
>>> from persista.store import InMemoryStore
>>> from persista.store.registry import register_scheme
>>> register_scheme("memory", InMemoryStore)

persista.store.resolve_store

resolve_store(
    store: BaseStore | dict[str, Any],
) -> BaseStore

Resolve a :class:~persista.store.BaseStore instance from an existing object or a configuration dictionary.

If store is already a :class:~persista.store.BaseStore instance it is returned as-is. If it is a :class:dict, it is treated as an objectory factory configuration and instantiated via :func:objectory.factory. See :func:~coola.factory.resolve_object for details.

Parameters:

Name Type Description Default
store BaseStore | dict[str, Any]

Either a fully configured :class:~persista.store.BaseStore instance, or a :class:dict containing an objectory factory specification (must include a "_target_" key pointing to the fully-qualified class name).

required

Returns:

Type Description
BaseStore

A configured :class:~persista.store.BaseStore instance.

Raises:

Type Description
TypeError

If the resolved object is not a :class:~persista.store.BaseStore instance.

Example
>>> from persista.store import InMemoryStore, resolve_store
>>> # From an existing instance:
>>> store = resolve_store(InMemoryStore())
>>> # From a configuration dictionary:
>>> store = resolve_store({"_target_": "persista.store.InMemoryStore"})

persista.store.split_present_missing

split_present_missing(
    keys: list[str], flags: list[bool]
) -> tuple[list[str], list[str]]

Split keys into present and missing lists based on flags.

Parameters:

Name Type Description Default
keys list[str]

The keys to split.

required
flags list[bool]

The presence flags for each key, in the same order as keys, e.g. the output of :meth:~persista.store.base.BaseStore.contains_many.

required

Returns:

Type Description
list[str]

A (present, missing) tuple, each a list of keys in the

list[str]

same relative order as keys.

Example
>>> from persista.store.keys import split_present_missing
>>> split_present_missing(["a", "b", "c"], [True, False, True])
(['a', 'c'], ['b'])

persista.store.store_from_uri

store_from_uri(
    uri: str, *, read_only: bool = False
) -> BaseStore

Reconstruct a :class:~persista.store.BaseStore from a URI.

Dispatches on uri's scheme to the matching store class's :meth:~persista.store.base.BaseStore.from_uri. The returned store supports both sync and async access. Store classes whose scheme is shared with another class (TypedPostgresStore reuses PostgresStore's native postgresql:// scheme, PickleRedisStore reuses RedisStore's native redis:// scheme) aren't reachable through this dispatcher -- call TheClass.from_uri(uri) directly for those.

Parameters:

Name Type Description Default
uri str

A URI produced by some BaseStore subclass's to_uri().

required
read_only bool

Forwarded to the matched class's from_uri.

False

Returns:

Type Description
BaseStore

A new, already-open store instance.

Raises:

Type Description
ValueError

If uri's scheme is not registered.

Example
>>> import tempfile
>>> from persista.store import JsonFileStore, store_from_uri
>>> with tempfile.TemporaryDirectory() as tmpdir:
...     with JsonFileStore(tmpdir) as store:
...         store.set("key", {"value": 1})
...         uri = store.to_uri()
...     with store_from_uri(uri) as restored:
...         print(restored.get("key"))
...
{'value': 1}

persista.store.validate_batch_size

validate_batch_size(batch_size: int) -> None

Validate that a value is a valid batch_size strategy.

Parameters:

Name Type Description Default
batch_size int

The value to validate.

required

Raises:

Type Description
ValueError

If batch_size is invalid.

Example
>>> from persista.store.validation import validate_batch_size
>>> validate_batch_size(32)

persista.store.validate_field_name

validate_field_name(name: str) -> None

Validate that a value filter field name is safe to interpolate into a SQL fragment.

BaseStore.filter implementations build SQL by interpolating the field name directly (only the filter value is passed as a bound parameter), so an unrestricted field name is a SQL injection vector. Restricting it to a simple identifier shape closes that off.

Parameters:

Name Type Description Default
name str

The field name to validate.

required

Raises:

Type Description
ValueError

If name is not a valid identifier (letters, digits, underscores, not starting with a digit).

Example
>>> from persista.store.validation import validate_field_name
>>> validate_field_name("user_id")
>>> validate_field_name("bad name")
Traceback (most recent call last):
    ...
ValueError: Invalid filter field name: 'bad name'. Field names must match '^[A-Za-z_][A-Za-z0-9_]*$'

persista.store.validate_on_conflict

validate_on_conflict(on_conflict: str) -> None

Validate that a value is a valid on_conflict strategy.

Parameters:

Name Type Description Default
on_conflict str

The value to validate.

required

Raises:

Type Description
ValueError

If on_conflict is not one of :data:ON_CONFLICT_VALUES.

Example
>>> from persista.store.validation import validate_on_conflict
>>> validate_on_conflict("overwrite")

persista.store.factory

Contain factories for stores.

persista.store.factory.BaseStoreFactory

Bases: ABC

Abstract base class for :class:~persista.store.BaseStore factories.

Subclasses implement :meth:make_store to instantiate and return a configured :class:~persista.store.BaseStore object. This pattern decouples store creation from the rest of the codebase, making it easy to swap stores (e.g. in-memory, SQLite, DuckDB) without changing call sites.

Example
>>> from persista.store import InMemoryStore, BaseStore
>>> from persista.store.factory import BaseStoreFactory
>>> class MyStoreFactory(BaseStoreFactory):
...     def make_store(self) -> BaseStore:
...         return InMemoryStore()
...
>>> factory = MyStoreFactory()
>>> store = factory.make_store()

persista.store.factory.BaseStoreFactory.make_store abstractmethod

make_store() -> BaseStore

Create and return a configured BaseStore instance.

Returns:

Name Type Description
A BaseStore

class:~persista.store.BaseStore instance. The store

BaseStore

is not opened; call :meth:~persista.store.BaseStore.open

BaseStore

(or use it as a context manager) before using it.

persista.store.factory.ConfigurableStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A concrete BaseStore factory that accepts either a pre-built :class:~persista.store.BaseStore instance or a configuration dictionary.

When a dict is provided it is resolved at each :meth:make_store call via :func:~persista.store.resolve.resolve_store, which uses objectory to instantiate the configured class. When an instance is provided it is returned as-is.

Parameters:

Name Type Description Default
store BaseStore | dict[str, Any]

A fully configured :class:~persista.store.BaseStore instance, or a :class:dict containing an objectory factory specification (must include a "_target_" key pointing to the fully-qualified class name).

required
Example
>>> from persista.store import InMemoryStore
>>> from persista.store.factory import ConfigurableStoreFactory
>>> factory = ConfigurableStoreFactory(InMemoryStore())
>>> store = factory.make_store()

persista.store.factory.DuckDBStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.DuckDBStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
database Path | str

Path to the DuckDB file, or ":memory:" for an in-memory database.

':memory:'
**kwargs Any

Additional keyword arguments to pass to duckdb.connect.

{}
Example
>>> from persista.store.factory import DuckDBStoreFactory
>>> factory = DuckDBStoreFactory(":memory:")
>>> store = factory.make_store()

persista.store.factory.InMemoryStoreFactory

Bases: BaseStoreFactory, InlineDisplayMixin

A factory that creates a new :class:~persista.store.InMemoryStore instance on each call to :meth:make_store.

Example
>>> from persista.store.factory import InMemoryStoreFactory
>>> factory = InMemoryStoreFactory()
>>> store = factory.make_store()

persista.store.factory.JsonFileStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.JsonFileStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
path str | PathLike[str]

The directory where value files are stored.

required
**kwargs Any

Additional keyword arguments to pass to iden.io.save_json.

{}
Example
>>> import tempfile
>>> from persista.store.factory import JsonFileStoreFactory
>>> with tempfile.TemporaryDirectory() as tmpdir:
...     factory = JsonFileStoreFactory(tmpdir)
...     store = factory.make_store()
...

persista.store.factory.LmdbStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.LmdbStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
path str | PathLike[str]

The directory where the LMDB environment is stored.

required
map_size int

The maximum size in bytes of the memory map. Passed to lmdb.open.

_DEFAULT_MAP_SIZE
**kwargs Any

Additional keyword arguments to pass to lmdb.open.

{}
Example
>>> import tempfile
>>> from persista.store.factory import LmdbStoreFactory
>>> with tempfile.TemporaryDirectory() as tmpdir:
...     factory = LmdbStoreFactory(tmpdir)
...     store = factory.make_store()
...

persista.store.factory.NullStoreFactory

Bases: BaseStoreFactory, InlineDisplayMixin

A factory that creates a new :class:~persista.store.NullStore instance on each call to :meth:make_store.

Example
>>> from persista.store.factory import NullStoreFactory
>>> factory = NullStoreFactory()
>>> store = factory.make_store()

persista.store.factory.PickleFileStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.PickleFileStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
path str | PathLike[str]

The directory where value files are stored.

required
**kwargs Any

Additional keyword arguments to pass to iden.io.save_pickle.

{}
Example
>>> import tempfile
>>> from persista.store.factory import PickleFileStoreFactory
>>> with tempfile.TemporaryDirectory() as tmpdir:
...     factory = PickleFileStoreFactory(tmpdir)
...     store = factory.make_store()
...

persista.store.factory.PickleLmdbStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.PickleLmdbStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
path str | PathLike[str]

The directory where the LMDB environment is stored.

required
map_size int

The maximum size in bytes of the memory map. Passed to lmdb.open.

_DEFAULT_MAP_SIZE
**kwargs Any

Additional keyword arguments to pass to lmdb.open.

{}
Example
>>> import tempfile
>>> from persista.store.factory import PickleLmdbStoreFactory
>>> with tempfile.TemporaryDirectory() as tmpdir:
...     factory = PickleLmdbStoreFactory(tmpdir)
...     store = factory.make_store()
...

persista.store.factory.PickleRedisStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.PickleRedisStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
url str

The Redis connection URL passed to redis.Redis.from_url.

'redis://localhost:6379/0'
**kwargs Any

Additional keyword arguments to pass to redis.Redis.from_url.

{}
Example
>>> from persista.store.factory import PickleRedisStoreFactory
>>> factory = PickleRedisStoreFactory("redis://localhost:6379/0")
>>> store = factory.make_store()  # doctest: +SKIP

persista.store.factory.PickleSQLiteStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.PickleSQLiteStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
database Path | str

The database argument passed to sqlite3.connect (path, ":memory:", or file: URI).

':memory:'
**kwargs Any

Additional keyword arguments to pass to sqlite3.connect.

{}
Example
>>> from persista.store.factory import PickleSQLiteStoreFactory
>>> factory = PickleSQLiteStoreFactory(":memory:")
>>> store = factory.make_store()

persista.store.factory.PostgresStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.PostgresStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
conninfo str

The connection string/DSN passed to psycopg.connect.

required
table str

The name of the table backing this store.

'store'
**kwargs Any

Additional keyword arguments to pass to psycopg.connect.

{}
Example
>>> from persista.store.factory import PostgresStoreFactory
>>> factory = PostgresStoreFactory("postgresql://user:pass@localhost/dbname")
>>> store = factory.make_store()  # doctest: +SKIP

persista.store.factory.RedisStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.RedisStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
url str

The Redis connection URL passed to redis.Redis.from_url.

'redis://localhost:6379/0'
**kwargs Any

Additional keyword arguments to pass to redis.Redis.from_url.

{}
Example
>>> from persista.store.factory import RedisStoreFactory
>>> factory = RedisStoreFactory("redis://localhost:6379/0")
>>> store = factory.make_store()  # doctest: +SKIP

persista.store.factory.SQLiteStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.SQLiteStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
database Path | str

The database argument passed to sqlite3.connect (path, ":memory:", or file: URI).

':memory:'
**kwargs Any

Additional keyword arguments to pass to sqlite3.connect.

{}
Example
>>> from persista.store.factory import SQLiteStoreFactory
>>> factory = SQLiteStoreFactory(":memory:")
>>> store = factory.make_store()

persista.store.factory.StoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A concrete BaseStore factory that wraps a pre-built :class:~persista.store.BaseStore instance.

Use this when the store is already instantiated and you simply want to wrap it in the :class:~BaseStoreFactory interface — for example, when injecting a fixed store into a component that expects a factory.

Parameters:

Name Type Description Default
store BaseStore

A fully configured :class:~persista.store.BaseStore instance to return from :meth:make_store.

required
Example
>>> from persista.store import InMemoryStore
>>> from persista.store.factory import StoreFactory
>>> factory = StoreFactory(InMemoryStore())
>>> store = factory.make_store()

persista.store.factory.TypedDuckDBStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.TypedDuckDBStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
database Path | str

Path to the DuckDB file, or ":memory:" for an in-memory database.

':memory:'
value_schema dict[str, str] | None

Optional mapping of value field names to DuckDB type strings.

None
**kwargs Any

Additional keyword arguments to pass to duckdb.connect.

{}
Example
>>> from persista.store.factory import TypedDuckDBStoreFactory
>>> factory = TypedDuckDBStoreFactory(":memory:", value_schema={"author": "TEXT"})
>>> store = factory.make_store()

persista.store.factory.TypedPostgresStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.TypedPostgresStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
conninfo str

The connection string/DSN passed to psycopg.connect.

required
table str

The name of the table backing this store.

'store'
value_schema dict[str, str] | None

Optional mapping of value field names to Postgres type strings.

None
**kwargs Any

Additional keyword arguments to pass to psycopg.connect.

{}
Example
>>> from persista.store.factory import TypedPostgresStoreFactory
>>> factory = TypedPostgresStoreFactory(
...     "postgresql://user:pass@localhost/dbname", value_schema={"author": "TEXT"}
... )
>>> store = factory.make_store()  # doctest: +SKIP

persista.store.factory.TypedSQLiteStoreFactory

Bases: BaseStoreFactory, MultilineDisplayMixin

A factory that creates a new :class:~persista.store.TypedSQLiteStore instance on each call to :meth:make_store.

Parameters:

Name Type Description Default
database Path | str

The database argument passed to sqlite3.connect (path, ":memory:", or file: URI).

':memory:'
value_schema dict[str, str] | None

Optional mapping of value field names to SQLite type strings.

None
**kwargs Any

Additional keyword arguments to pass to sqlite3.connect.

{}
Example
>>> from persista.store.factory import TypedSQLiteStoreFactory
>>> factory = TypedSQLiteStoreFactory(":memory:", value_schema={"author": "TEXT"})
>>> store = factory.make_store()