soev_retrieval.testing
The contract every VectorStore implementation must pass, and a scripted double for what is built on it.
Subclass VectorStoreContract in your own test tree and implement make_store (or override the store
fixture) so that the target TARGET holds exactly the chunks in CORPUS, each stored with its vector and
properties, under a schema matching SPEC. Every test then runs against your store. ScriptedVectorStore
is for tests of code that calls a store: it answers from a script and records what it was asked.
This package imports pytest. Install the testing extra of soev-retrieval to use it.
Contract suite
The suite tests a store against the contract of VectorStore, with a fixed corpus.
VectorStoreContract
classVectorStoreContractThe test suite that every VectorStore implementation must pass.
Subclass it in your own test tree, with a name that pytest collects. Implement make_store, or override the
store fixture, so that TARGET holds exactly the chunks of CORPUS under a schema that matches SPEC. Each
test then runs against your store. The tests are async and carry no asyncio marker, so run them with
pytest-asyncio in auto mode.
Example
from soev_retrieval.testing import CORPUS, TARGET, VectorStoreContract
class TestMyStore(VectorStoreContract):
async def make_store(self):
store = MyStore() # your own VectorStore implementation
for record in CORPUS:
# `add` is the write API of your own store: `VectorStore` has no write method.
await store.add(TARGET, record.id, record.document_id, record.vector, record.properties)
return storemethodmake_storeasync () -> VectorStoreReturn the store under test, with the chunks of CORPUS stored in TARGET.
Returns
VectorStoreThe store to test.
Raises:
NotImplementedError: The subclass implements neither this method nor thestorefixture.
methodstoreasync () -> VectorStoreGive each test the store that make_store returns.
Override it with a pytest.fixture named store to build the store from other fixtures.
Returns
VectorStoreThe store under test.
methodtest_near_vector_orders_by_similarityasync (store)Check that near_vector returns the most similar chunks first.
paramstoremethodtest_near_vector_respects_limitasync (store)Check that near_vector returns at most limit hits.
paramstoremethodtest_hits_carry_id_document_and_propertiesasync (store)Check that a hit carries the chunk id, the document id and the stored properties.
paramstoremethodtest_hit_properties_are_only_declared_fieldsasync (store)Check that a hit holds only the properties that fields declares.
paramstoremethodtest_fields_names_the_filterable_fieldsasync (store)Check that fields marks exactly the filterable fields of SPEC filterable, with their types.
paramstoremethodtest_unknown_target_is_refusedasync (store)Check that a search of an unknown target raises InvalidQueryError.
paramstoremethodtest_bm25_returns_only_chunks_with_the_termasync (store)Check that bm25 returns no chunk without a term of the query.
paramstoremethodtest_bm25_finds_every_chunk_with_the_termasync (store)Check that bm25 returns every chunk with a term of the query.
paramstoremethodtest_hybrid_ranks_the_chunk_matching_text_and_vector_firstasync (store)Check that hybrid ranks first the chunk that matches both the text and the vector.
paramstoremethodtest_hybrid_respects_limitasync (store)Check that hybrid returns at most limit hits.
paramstoremethodtest_hybrid_alpha_one_is_pure_vectorasync (store)Check that hybrid with alpha=1.0 ranks by the vector alone.
paramstoremethodtest_hybrid_alpha_zero_is_pure_keywordasync (store)Check that hybrid with alpha=0.0 ranks by the keyword match alone.
paramstoremethodtest_filter_eq_restricts_a_searchasync (store)Check that an eq filter restricts the candidates of a search.
paramstoremethodtest_filter_in_matches_any_listed_valueasync (store)Check that an in filter matches a chunk with any of the listed values.
paramstoremethodtest_filter_range_operatorsasync (store)Check that the gt and lte filters compare a number field.
paramstoremethodtest_filter_contains_any_on_a_list_fieldasync (store)Check that a contains_any filter matches a list field that holds any of the listed values.
paramstoremethodtest_filters_apply_to_hybrid_tooasync (store)Check that a filter restricts the candidates of hybrid.
paramstoremethodtest_unknown_field_is_refused_and_namedasync (store)Check that a filter on an unknown field raises InvalidQueryError that names the field.
paramstoremethodtest_unfilterable_field_is_refused_and_namedasync (store)Check that a filter on an unfilterable field raises InvalidQueryError that names the field.
paramstoremethodtest_unknown_operator_is_refused_and_namedasync (store)Check that an unknown operator raises InvalidQueryError that names the field of the filter.
paramstoremethodtest_operand_shape_is_refusedasync (store)Check that an operand of the wrong shape for its operator raises InvalidQueryError.
paramstoremethodtest_a_value_of_the_wrong_type_is_refused_and_namedasync (store)Check that an operand of the wrong type for its field raises InvalidQueryError that names it.
paramstoremethodtest_fetch_orders_by_a_fieldasync (store)Check that fetch sorts on order_by, in ascending and in descending order.
paramstoremethodtest_fetch_respects_limitasync (store)Check that fetch returns limit chunks when more chunks match.
paramstoremethodtest_fetch_returns_chunksasync (store)Check that fetch returns chunks with the chunk id, the document id and the stored properties.
paramstoremethodtest_filter_gt_on_a_date_fieldasync (store)Check that a gt filter compares a date field with ISO 8601 text.
paramstoremethodtest_every_filter_must_holdasync (store)Check that AllOf matches only the chunks for which every term holds.
paramstoremethodtest_any_of_matches_either_branchasync (store)Check that AnyOf matches the chunks for which any term holds.
paramstoremethodtest_not_excludes_what_its_term_matchesasync (store)Check that Not excludes the chunks that its term matches.
paramstoremethodtest_not_eq_matches_a_chunk_with_no_value_for_the_fieldasync (store)Check that Not of an eq filter matches a chunk without a value for the field.
paramstoremethodtest_an_expression_nestsasync (store)Check that a nested filter expression restricts a search.
paramstoremethodtest_an_or_inside_a_search_filters_the_candidatesasync (store)Check that an AnyOf filter restricts the candidates of hybrid.
paramstoremethodtest_nothing_matches_nothingasync (store)Check that NOTHING, alone or inside an AllOf, matches no chunk.
paramstoremethodtest_an_empty_all_of_matches_everythingasync (store)Check that an AllOf without terms matches every chunk.
paramstoremethodtest_a_bad_predicate_inside_an_expression_is_refused_and_namedasync (store)Check that a bad predicate inside an AnyOf raises InvalidQueryError that names its field.
paramstoreTARGET
constantTARGET = 'docs'The target that holds the contract corpus. A store under test must serve CORPUS under this name.
CORPUS
constantCORPUS: tuple[Record, ...]The four chunks that a store under test must hold in TARGET, each with its vector and its properties.
Chunk c2 has no published value, so the suite checks how a filter treats a missing value.
Record
dataclassRecord(id, document_id, vector, properties)One chunk of the contract corpus as it must be stored.
paramidstrThe id of the chunk. A hit or a chunk of the store must carry it as id.
paramdocument_idstrThe document that the chunk came from.
paramvectortuple[float, ...]The embedding to store with the chunk.
parampropertiesMapping[str, object]The stored fields of the chunk. A chunk can lack a field of SPEC.
SPEC
constantSPEC: FieldSpecThe stored fields of TARGET. A store under test must return a field spec for TARGET that matches it.
text is the only field that a filter cannot name. tags holds a sequence of keywords.
Scripted store
A scripted store tests code that calls a store, without a backend.
ScriptedVectorStore
classScriptedVectorStore(hits=(), *, chunks=(), errors=(), fields=None)A VectorStore that answers every search with hits and every fetch with chunks.
errors are raised one per call, in order, before any answer is given. fields is what fields() returns for
any target. calls records (verb, target, keyword arguments) for every call made.
A call that raises an error of errors is recorded in calls too.
paramhitsSequence[Hit]= ()The hits that each search returns. Change it to change the next answers.
paramchunksSequence[Chunk]= ()The chunks that each fetch returns. Change it to change the next answers.
paramerrorsSequence[Exception]= ()The errors to raise, one for each call, before the store answers again.
paramfieldsFieldSpec | None= NoneThe field spec that fields() returns, or None for an empty spec.
attributecallslist[tuple[str, str, dict[str, Any]]]One (verb, target, keyword arguments) tuple for each call, in call order.
methodhybridasync (target, *, query, vector=None, limit, where=None, alpha=None) -> Sequence[Hit]Record the call, then raise the next error of errors, or return hits.
paramtargetTargetThe target, recorded in calls.
paramquerystrRecorded in calls.
paramvectorSequence[float] | None= NoneRecorded in calls.
paramlimitintRecorded in calls. The store does not apply it.
paramwhereFilter | None= NoneRecorded in calls. The store does not apply it.
paramalphafloat | None= NoneRecorded in calls.
Returns
Sequence[Hit]A copy of hits.
Raises:
Exception: The next error oferrors, while any are left.
methodnear_vectorasync (target, *, vector, limit, where=None) -> Sequence[Hit]Record the call, then raise the next error of errors, or return hits.
paramtargetTargetThe target, recorded in calls.
paramvectorSequence[float]Recorded in calls.
paramlimitintRecorded in calls. The store does not apply it.
paramwhereFilter | None= NoneRecorded in calls. The store does not apply it.
Returns
Sequence[Hit]A copy of hits.
Raises:
Exception: The next error oferrors, while any are left.
methodbm25async (target, *, query, limit, where=None) -> Sequence[Hit]Record the call, then raise the next error of errors, or return hits.
paramtargetTargetThe target, recorded in calls.
paramquerystrRecorded in calls.
paramlimitintRecorded in calls. The store does not apply it.
paramwhereFilter | None= NoneRecorded in calls. The store does not apply it.
Returns
Sequence[Hit]A copy of hits.
Raises:
Exception: The next error oferrors, while any are left.
methodfetchasync (target, *, where=None, limit, order_by=None, descending=False) -> Sequence[Chunk]Record the call, then raise the next error of errors, or return chunks.
paramtargetTargetThe target, recorded in calls.
paramwhereFilter | None= NoneRecorded in calls. The store does not apply it.
paramlimitintRecorded in calls. The store does not apply it.
paramorder_bystr | None= NoneRecorded in calls. The store does not sort.
paramdescendingbool= FalseRecorded in calls.
Returns
Sequence[Chunk]A copy of chunks.
Raises:
Exception: The next error oferrors, while any are left.
methodfieldsasync (target) -> FieldSpecRecord the call, then raise the next error of errors, or return the scripted field spec.
paramtargetTargetThe target, recorded in calls. Every target gets the same spec.
Returns
FieldSpecThe fields that the store was made with.
Raises:
Exception: The next error oferrors, while any are left.