API Reference¶
The public surface is the typed Python facade. Each symbol below is rendered from its docstrings and type hints by mkdocstrings.
Store and handles¶
valise.Store ¶
Store(native: '_native.Store')
A single-file Valise store.
:meth:open is open-or-create; :meth:create fails if the path exists.
Declare collections with :meth:collection, then acquire a
:class:Writer to ingest and a :class:Reader to query.
Example::
store = Store.open("kb.vls")
store.collection("notes", Schema().text("body").vector("embedding", Vector(dim=768)))
with store.writer() as w:
w.put("notes", "doc-1", Record().text("body", "...").vector("embedding", emb))
w.commit()
hits = store.search("notes", Search().text("body", "...").vector("embedding", emb))
open
classmethod
¶
open(path: _PathLike, durability: Durability = Durability.BUFFERED) -> 'Store'
Open an existing store, creating it if absent (open-or-create).
create
classmethod
¶
create(path: _PathLike, durability: Durability = Durability.BUFFERED) -> 'Store'
Create a fresh store at path, failing if it already exists.
collection ¶
collection(name: str, schema: Schema) -> None
Create-or-open name, bind schema, and persist the schema
in-file (it rides the next commit) — a later :meth:open restores it,
so reopen needs no re-declaration.
Re-declaring is a no-op when identical and accepted when purely
additive; anything else raises :class:valise.SchemaMismatchError.
Names starting with ~ are reserved and rejected.
define_space ¶
define_space(name: str, spec: Union[Text, Vector]) -> Space
Define (or return the existing) shared space from a field spec —
Text() / Vector(dim=768, codec=Upq()) / … — then bind it in
any schema with Text(space=...) / Vector(space=...).
Re-defining an existing name is a no-op for an identical spec and an error for a divergent one.
spaces ¶
spaces() -> list[SpaceInfo]
All defined spaces — shared and ~auto/{collection}/{field} ones
(the latter flagged auto) — sorted by name.
collections ¶
collections() -> list[CollectionInfo]
All user collections (the hidden ~valise.schema store is never
listed).
partitioned ¶
partitioned(base: str, schema: Schema, by: Partition) -> Partitioned
Create-or-open a logical partitioned collection: records routed by
by into physical collections ("{base}:{period}") that share
one resolved schema.
reader ¶
reader() -> Reader
Acquire a :class:Reader (live, last-committed-wins per operation
— not a frozen snapshot).
search ¶
search(coll: str, search: Search) -> SearchResult
Run a search; returns a :class:SearchResult in one native call.
search_view ¶
search_view(view: View, search: Search) -> SearchResult
Search across a partitioned :class:View as one globally-fused
query; hits carry their per-hit partition collection.
compact ¶
compact(recalibrate: bool = False) -> CompactReport
Compact the store; returns a typed :class:CompactReport.
valise.Reader ¶
Reader(native: '_native.Reader')
A snapshot reader: get / get_many / search / search_view.
keys ¶
keys(coll: str) -> list[Key]
Every committed key in coll, in unspecified order.
The building block for a full scan: pair it with :meth:get_many to
walk a capsule end to end. Uncommitted records are excluded. Cost is
O(records in coll) and the result holds one key per record, so
chunk it for very large collections.
get_many ¶
get_many(coll: str, keys: list[Key]) -> list[Optional[Stored]]
Fetch many records in one native call.
Returns a list aligned with keys; missing entries are None. The
list comprehension wraps already-built native Stored objects — it
is not a per-record native round-trip.
search ¶
search(coll: str, search: Search) -> SearchResult
Run a search; returns a :class:SearchResult in one native call.
Example
import os, tempfile from valise import Store, Schema, Record, Search path = os.path.join(tempfile.mkdtemp(), "demo.vls") store = Store.open(path) store.collection("kb", Schema().text("body")) with store.writer() as w: ... w.put("kb", "a", Record().text("body", "the quick fox")) ... w.put("kb", "b", Record().text("body", "a lazy dog")) ... _ = w.commit() result = store.reader().search( ... "kb", Search().text("body", "fox").top_k(5) ... ) result[0].key 'a' len(result) 1 result.scores.dtype dtype('float32')
search_view ¶
search_view(view: View, search: Search) -> SearchResult
Search across a partitioned :class:valise.View as ONE globally-fused
multi-collection query; hits carry their per-hit partition collection.
valise.Writer ¶
Writer(native: '_native.Writer')
A serialized writer holding the single-writer lock until closed.
put ¶
put(coll: str, key: Key, record: Record) -> None
Stage a record under key (replacing any existing one).
put_auto ¶
put_auto(coll: str, record: Record) -> Key
Stage a record under an auto-generated key; returns the key.
put_into ¶
put_into(partitioned: Partitioned, key: Key, record: Record) -> None
Stage a record into a :class:valise.Partitioned logical collection.
The physical partition is derived from the record's created_at
(set via :meth:valise.Record.at; defaults to now).
put_many ¶
put_many(coll: str, keys: list[Key], vectors: ndarray, field: str = 'dense', texts: Optional[list[str]] = None, text_field: str = 'body') -> None
Bulk-stage len(keys) records in one native call.
vectors is a 2-D float32 ndarray [N, dim] borrowed zero-copy
by native; there is no per-row Python loop.
Raises:
| Type | Description |
|---|---|
ValueError
|
if |
Schema¶
valise.Schema ¶
Schema()
The set of named fields a collection's records may fill.
Built fluently and bound by :meth:valise.Store.collection::
Schema().text("body").vector("embedding", Vector(dim=768))
vector(name, 768) is accepted as an int shorthand for
vector(name, Vector(dim=768)).
text ¶
text(name: str, spec: Optional[Text] = None) -> 'Schema'
Add a text field. spec=None is the Rust default
(Text::english()). At most one text field per collection in v1.
vector ¶
vector(name: str, spec: Union[Vector, int]) -> 'Schema'
Add a vector field. The dimension is mandatory, so the spec is
always explicit: Vector(dim=768), the int shorthand 768, or a
shared binding Vector(space=...).
valise.Text
dataclass
¶
Text(lang: Optional[Lang] = None, space: Optional[Space] = None)
Text field spec: an inline analyzer choice or a shared-space binding.
Text() is the Rust default (Text::english(): NFKC, case-fold,
Porter2 stemming, Lucene stopwords). Text(lang=Lang.RAW) is the
pass-through whitespace tokenizer. Text(space=...) binds a shared
space from :meth:valise.Store.define_space (mutually exclusive with
lang).
valise.Vector ¶
Vector(dim: Optional[int] = None, *, metric: Optional[Metric] = None, codec: Optional[Codec] = None, calibrate: Optional[Calibrate] = None, space: Optional[Space] = None)
Vector field spec: an inline (dim, metric, codec, calibrate)
choice or a shared-space binding. Exactly one of dim/space.
Inline defaults are the Rust ones: cosine metric, Qam() codec,
Auto() calibration. dim must be a positive multiple of 64
(checked at declaration). On a shared binding (space=...) the
configuration arguments are rejected at declaration time —
metric/codec/calibration belong to the space and are configured at
:meth:valise.Store.define_space.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dim
|
Optional[int]
|
The vector dimension (inline spec). |
None
|
metric
|
Optional[Metric]
|
Distance metric, or |
None
|
codec
|
Optional[Codec]
|
:class: |
None
|
calibrate
|
Optional[Calibrate]
|
:class: |
None
|
space
|
Optional[Space]
|
A shared vector :class: |
None
|
valise.Qam
dataclass
¶
Qam(amp_bits: Optional[int] = None, phase_bits: Optional[int] = None)
QAM Lloyd-Max codec.
Qam() is the production default operating point (Rust
Codec::qam() = 5 amplitude + 6 phase bits). Pass both
amp_bits and phase_bits to move it (Rust Codec::qam_bits);
higher bits trade storage for recall.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amp_bits
|
Optional[int]
|
Bits per amplitude index, or |
None
|
phase_bits
|
Optional[int]
|
Bits per phase index, or |
None
|
valise.Upq
dataclass
¶
Upq(cells: Optional[int] = None, design: Optional[Design] = None)
UPQ (unrestricted polar quantization) codec.
Upq() is the default operating point (Rust Codec::upq() =
2048 cells, empirical ring design). Upq(cells=...) mirrors
Codec::upq_cells; a design requires an explicit cells
budget (mirror of Codec::upq_with).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cells
|
Optional[int]
|
Total joint cells per complex pair (power of two), or |
None
|
design
|
Optional[Design]
|
Ring-design source (:class: |
None
|
valise.Design ¶
Bases: _StrEnum
UPQ ring-design source (mirror of Rust UpqDesign).
valise.Auto
dataclass
¶
Auto(sample: Optional[int] = None)
Calibrate at the first commit that contains vectors for the field.
Auto() is the Rust default (Calibrate::auto(): fit from up to
50 000 staged vectors). Auto(sample=n) mirrors
Calibrate::auto_sample(n).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sample
|
Optional[int]
|
Sample-size cap, or |
None
|
valise.Now ¶
Now(vectors: ndarray)
Calibrate eagerly at declaration from a representative sample
(mirror of Rust Calibrate::now).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vectors
|
ndarray
|
A 2-D |
required |
valise.Space ¶
Space(native: '_native.Space')
An opaque handle to a defined space, returned by
:meth:valise.Store.define_space / :meth:valise.Store.space. Bind it in a
schema with Text(space=...) or Vector(space=...).
valise.Metric ¶
Bases: _StrEnum
Vector-space distance metric.
valise.Lang ¶
Bases: _StrEnum
Text-space analyzer language.
Records¶
valise.Record ¶
Record()
Typed record builder.
Accumulates text/vector fields and metadata for a single record. Each
method forwards one native call and returns self for chaining.
valise.Stored
dataclass
¶
Stored(key: Key, collection: str, created_at: int, text: Optional[str], vectors: list[tuple[str, ndarray]])
A stored record as returned by get / get_many.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
Key
|
The record key. |
collection |
str
|
The owning collection. |
created_at |
int
|
The record timestamp (unix seconds). |
text |
Optional[str]
|
The text field value, if any. |
vectors |
list[tuple[str, ndarray]]
|
An ordered list of |
Equality is structural (np.array_equal over each vector, so shape and
dtype count). Because it carries ndarrays, :class:Stored is unhashable —
like the list / ndarray payloads it holds.
Example
import os, tempfile from valise import Store, Schema, Record path = os.path.join(tempfile.mkdtemp(), "demo.vls") store = Store.open(path) store.collection("kb", Schema().text("body")) with store.writer() as w: ... w.put("kb", "a", Record().text("body", "the quick brown fox")) ... _ = w.commit() got = store.reader().get("kb", "a") got.text 'the quick brown fox' got.created_at >= 0 True got == store.reader().get("kb", "a") True
Search¶
valise.Search ¶
Search()
Typed hybrid-search query builder.
Wraps a single owned native Search builder. Each builder method makes
exactly one native call into that owned state and returns self for
chaining; the facade never re-walks the query in Python.
Defaults (all applied by Rust): BM25 text scorer, ACCURATE vector
rerank, RRF(60) fusion, top_k=10.
text ¶
text(field: str, query: str, scorer: TextScorer = Bm25()) -> 'Search'
Add a lexical (text) channel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field
|
str
|
The text field to query. |
required |
query
|
str
|
The query string. |
required |
scorer
|
TextScorer
|
A typed :data: |
Bm25()
|
Returns:
| Type | Description |
|---|---|
'Search'
|
|
vector ¶
vector(field: str, query: ndarray, rerank: Rerank = Rerank.ACCURATE) -> 'Search'
Add a vector (nearest-neighbor) channel. May be called multiple times for multi-vector / multimodal search; each becomes a fusion channel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field
|
str
|
The vector field to query. |
required |
query
|
ndarray
|
A 1-D |
required |
rerank
|
Rerank
|
Rerank fidelity (default |
ACCURATE
|
Returns:
| Type | Description |
|---|---|
'Search'
|
|
fuse ¶
fuse(fusion: Fusion) -> 'Search'
Set the channel-fusion strategy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fusion
|
Fusion
|
A typed :data: |
required |
Returns:
| Type | Description |
|---|---|
'Search'
|
|
recency ¶
recency(recency: Recency) -> 'Search'
Set the recency strategy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
recency
|
Recency
|
A typed :data: |
required |
Returns:
| Type | Description |
|---|---|
'Search'
|
|
valise.SearchResult ¶
SearchResult(keys: List[Key], scores: ndarray, collection: Union[str, List[str]])
The result of a search: parallel keys and scores.
Built from the native (keys: list, scores: np.ndarray[float32]) tuple
in one native call. Both are held as-is (zero new allocation); the
scores ndarray is the moved array, never copied. :class:Hit objects
are materialized lazily — on indexing or iteration — so there is no eager
per-hit loop over the result set.
For a single-collection :meth:valise.Store.search, collection is that
collection's name. For :meth:valise.Store.search_view, hits span
partitions: collection is None and the per-hit names are carried
on each :class:Hit (and by :attr:collections).
valise.Hit
dataclass
¶
Hit(key: Key, score: float, collection: str)
A single search hit.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
Key
|
The record key. |
score |
float
|
The fused relevance score. |
collection |
str
|
The collection the hit belongs to. |
valise.Rerank ¶
Bases: _StrEnum
Vector-search rerank fidelity. ACCURATE (full f32 rerank) is the
default, mirroring Rust Rerank::Accurate.
valise.TfMode ¶
Bases: _StrEnum
Term-frequency weighting mode for TF-IDF scoring.
valise.Bm25
dataclass
¶
Bm25(k1: Optional[float] = None, b: Optional[float] = None)
Okapi BM25 lexical scorer — the default of :meth:Search.text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k1
|
Optional[float]
|
Term-frequency saturation, or |
None
|
b
|
Optional[float]
|
Length normalization, or |
None
|
valise.TfidfCosine
dataclass
¶
TfidfCosine(tf_mode: TfMode = TfMode.LOG)
TF-IDF cosine-similarity lexical scorer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tf_mode
|
TfMode
|
Term-frequency weighting mode. |
LOG
|
valise.TfidfCosineApprox
dataclass
¶
TfidfCosineApprox(tf_mode: TfMode = TfMode.LOG)
Cheaper sqrt(doclen)-normalized TF-IDF cosine approximation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tf_mode
|
TfMode
|
Term-frequency weighting mode. |
LOG
|
valise.Rrf
dataclass
¶
Rrf(k: Optional[int] = None)
Reciprocal-rank fusion — the default with ≥2 channels.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
Optional[int]
|
The RRF rank constant, or |
None
|
valise.Weighted
dataclass
¶
Weighted(text: float, vector: float)
Linear weighted fusion of the text and vector channels (each channel
min-max normalized to [0, 1] first).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
float
|
Weight applied to the text channel. |
required |
vector
|
float
|
Weight applied to every vector channel. |
required |
valise.Range
dataclass
¶
Range(from_: int, to: int)
Hard recency filter to the inclusive [from_, to] unix-second
window (candidates outside it are pruned before fusion).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_
|
int
|
Inclusive lower bound (unix seconds). Named |
required |
to
|
int
|
Inclusive upper bound (unix seconds). |
required |
valise.HalfLife
dataclass
¶
HalfLife(days: float)
Exponential recency decay with the given half-life (soft post-fusion
multiplier score * 0.5 ** (age / half_life)).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
days
|
float
|
The decay half-life in days. |
required |
valise.RrfChannel
dataclass
¶
RrfChannel(half_life_days: float, weight: float)
Recency as an additional RRF channel (candidates ranked newest first,
contributing weight / (k + rank + 1)). Requires :class:Rrf fusion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
half_life_days
|
float
|
The recency half-life in days. |
required |
weight
|
float
|
The channel weight. |
required |
Partitions¶
valise.Partition ¶
Bases: Enum
How records are routed to physical partitions (mirror of Rust
Partition::ByDay / ByMonth).
valise.Window ¶
Window()
A window of partitions for a view. Construct via the factory methods:
:meth:last_days, :meth:range, :meth:partitions.
range
classmethod
¶
range(from_: int, to: int) -> 'Window'
Partitions intersecting [from_, to] (inclusive unix seconds).
partitions
classmethod
¶
partitions(suffixes: Sequence[str]) -> 'Window'
Explicit period suffixes (e.g. "2026-05-25"), resolved against
the existing "{base}:{suffix}" collections.
valise.Partitioned ¶
Partitioned(native: '_native.Partitioned')
A logical partitioned collection (cheap handle; see module docs).
view ¶
view(window: Window, now: Optional[int] = None) -> View
Resolve the partitions intersecting window to a :class:View.
now (unix seconds) overrides the reference time of
Window.last_days for deterministic results; it is ignored by the
other window kinds.
forget_before ¶
forget_before(cutoff: int) -> int
Soft-forget: tombstone every record in partitions whose entire
period precedes cutoff (unix seconds). Returns the number of
frames tombstoned. Bytes are reclaimed at compaction.
Acquires the single writer internally — do not call while holding
an open :class:valise.Writer.
valise.View ¶
View(native: '_native.View')
A resolved set of physical partition collections. Pass to
:meth:valise.Store.search_view / :meth:valise.Reader.search_view.
Maintenance and options¶
valise.Stats
dataclass
¶
Stats(frames_total: int, frames_active: int, vectors_total: int, vectors_active: int, file_bytes: int, tombstone_ratio: float)
Store-level statistics (user data only — the hidden ~valise.schema
doc frames are excluded).
Attributes:
| Name | Type | Description |
|---|---|---|
frames_total |
int
|
Total frames ever written. |
frames_active |
int
|
Live (non-tombstoned) frames. |
vectors_total |
int
|
Total vectors ever written. |
vectors_active |
int
|
Live vectors. |
file_bytes |
int
|
On-disk file size in bytes. |
tombstone_ratio |
float
|
Fraction of frames that are tombstones. |
needs_compaction ¶
needs_compaction(threshold: float) -> bool
Whether :attr:tombstone_ratio meets/exceeds threshold
(e.g. 0.3). Mirrors Rust StoreStats::needs_compaction.
valise.CompactReport
dataclass
¶
CompactReport(compacted: bool, frames_before: int, frames_after: int, vectors_before: int, vectors_after: int, bytes_before: int, bytes_after: int)
The result of a compaction.
Attributes:
| Name | Type | Description |
|---|---|---|
compacted |
bool
|
Whether a rewrite actually occurred. |
frames_before |
int
|
Frame count before compaction. |
frames_after |
int
|
Frame count after compaction. |
vectors_before |
int
|
Vector count before compaction. |
vectors_after |
int
|
Vector count after compaction. |
bytes_before |
int
|
File size before compaction. |
bytes_after |
int
|
File size after compaction. |
valise.Durability ¶
Bases: _StrEnum
Commit durability mode.
FULL_SYNC maps to the Rust Durability::FullSync (the strongest
hardware barrier, F_FULLFSYNC on macOS).
valise.CollectionInfo
dataclass
¶
CollectionInfo(name: str, id: int)
One row of :meth:valise.Store.collections (the hidden ~valise.schema
store is never listed).
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The collection name. |
id |
int
|
The engine collection id. |
valise.SpaceInfo
dataclass
¶
SpaceInfo(name: str, dim: Optional[int], auto: bool)
One row of :meth:valise.Store.spaces.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The space name. Auto spaces are named
|
dim |
Optional[int]
|
The vector dimension, or |
auto |
bool
|
|
Errors¶
ValiseError is the base of the hierarchy; catching it catches everything
this package raises.
valise.ValiseError ¶
Bases: Exception
valise.NotCalibratedError ¶
Bases: ValiseError
valise.SchemaMismatchError ¶
Bases: ValiseError
valise.CorruptionError ¶
Bases: ValiseError
valise.BusyError ¶
Bases: ValiseError
valise.UnsupportedError ¶
Bases: ValiseError
valise.ValidationError ¶
Bases: ValiseError