Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
**Changed**

Split `search/sql.py`, `search/run.py`, and `embedding/model.py` into one
module per non-trivial function, so the tree is clean at
`one-function-per-file`'s strictest threshold. Every symbol keeps its behavior;
`search.run._search` is now `search.search_rows.search_rows`, and the SQL
builders moved to modules named for them.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"command": "uv run --with-editable ../../packages/python python -m pytest tests/e2e/ -x -q",
"ran_at": 1788575701,
"exit_code": 0,
"commit": "8f07e97547e3c145e6e6635e89839b6318d25b7c",
"branch": "claude/1095-ofpf-embeddings"
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,3 @@ def load_model(model_id):
from model2vec import StaticModel

return StaticModel.from_pretrained(model_id)


def model_identifier(model_id, model):
config = getattr(model, "config", None) or {}
version = config.get("model2vec_version")
if version:
return f"{model_id}@{version}"
return model_id
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def model_identifier(model_id, model):
config = getattr(model, "config", None) or {}
version = config.get("model2vec_version")
if version:
return f"{model_id}@{version}"
return model_id
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from types import SimpleNamespace

from . import model_identifier as module


def describe_model_identifier():
def it_appends_the_model2vec_version_when_the_config_carries_one():
loaded = SimpleNamespace(config={"model2vec_version": "0.3.0"})
assert (
module.model_identifier("some/model-id", loaded)
== "some/model-id@0.3.0"
)

def it_is_the_model_id_alone_when_the_config_has_no_version():
loaded = SimpleNamespace(config={"normalize": False})
assert module.model_identifier("some/model-id", loaded) == "some/model-id"

def it_is_the_model_id_alone_when_the_config_is_none():
loaded = SimpleNamespace(config=None)
assert module.model_identifier("some/model-id", loaded) == "some/model-id"

def it_is_the_model_id_alone_when_there_is_no_config_attribute():
assert module.model_identifier("some/model-id", object()) == "some/model-id"

def it_treats_an_empty_version_as_absent():
loaded = SimpleNamespace(config={"model2vec_version": ""})
assert module.model_identifier("some/model-id", loaded) == "some/model-id"
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import sys
from types import SimpleNamespace
from unittest.mock import MagicMock, patch

from . import model
Expand All @@ -19,27 +18,3 @@ def it_loads_via_model2vec_from_pretrained():
"some/model-id"
)
assert loaded is model2vec.StaticModel.from_pretrained.return_value


def describe_model_identifier():
def it_appends_the_model2vec_version_when_the_config_carries_one():
loaded = SimpleNamespace(config={"model2vec_version": "0.3.0"})
assert (
model.model_identifier("some/model-id", loaded)
== "some/model-id@0.3.0"
)

def it_is_the_model_id_alone_when_the_config_has_no_version():
loaded = SimpleNamespace(config={"normalize": False})
assert model.model_identifier("some/model-id", loaded) == "some/model-id"

def it_is_the_model_id_alone_when_the_config_is_none():
loaded = SimpleNamespace(config=None)
assert model.model_identifier("some/model-id", loaded) == "some/model-id"

def it_is_the_model_id_alone_when_there_is_no_config_attribute():
assert model.model_identifier("some/model-id", object()) == "some/model-id"

def it_treats_an_empty_version_as_absent():
loaded = SimpleNamespace(config={"model2vec_version": ""})
assert model.model_identifier("some/model-id", loaded) == "some/model-id"
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from . import model
from .cache import make_cache
from .model_identifier import model_identifier
from .values import ProtocolError, decode_value

MALFORMED_SHAPE = (
Expand Down Expand Up @@ -40,7 +41,7 @@ def _compute(self, digest, identifier):
def embed(self, text, model_id):
"""Return the vector for ``text``, and whether the cache served it."""
loaded = self._model(model_id)
identifier = model.model_identifier(model_id, loaded)
identifier = model_identifier(model_id, loaded)
digest = sha256(text.encode("utf-8")).hexdigest()
self._pending = (text, loaded)
self._computed = False
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
from contextlib import contextmanager
from hashlib import sha256
from unittest.mock import MagicMock, call, patch

Expand All @@ -7,6 +8,15 @@
HELLO_DIGEST = sha256(b"hello").hexdigest()


@contextmanager
def loading(identifier="m1"):
with patch.object(worker, "model") as model:
with patch.object(
worker, "model_identifier", return_value=identifier
) as identify:
yield model, identify


def make_worker():
with patch.object(worker, "make_cache") as make_cache:
built = worker.Worker()
Expand Down Expand Up @@ -81,20 +91,17 @@ def describe_embed():
def it_keys_the_cache_on_the_sha256_of_the_text_and_the_identifier():
built, _ = make_worker()
built._compute_cached = MagicMock(return_value=[1.0])
with patch.object(worker, "model") as model:
model.model_identifier.return_value = "m1@9.9"
with loading("m1@9.9") as (model, identify):
result = built.embed("hello", "m1")
model.load_model.assert_called_once_with("m1")
model.model_identifier.assert_called_once_with(
"m1", model.load_model.return_value
)
identify.assert_called_once_with("m1", model.load_model.return_value)
built._compute_cached.assert_called_once_with(HELLO_DIGEST, "m1@9.9")
assert result == ([1.0], True)

def it_reports_a_hit_when_compute_never_ran():
built, _ = make_worker()
built._compute_cached = MagicMock(return_value=[1.0])
with patch.object(worker, "model"):
with loading():
_, cached = built.embed("hello", "m1")
assert cached is True

Expand All @@ -106,7 +113,7 @@ def compute(digest, identifier):
return [1.0]

built._compute_cached = MagicMock(side_effect=compute)
with patch.object(worker, "model"):
with loading():
_, cached = built.embed("hello", "m1")
assert cached is False

Expand All @@ -116,22 +123,21 @@ def it_clears_a_previous_calls_miss_before_consulting_the_cache():
built, _ = make_worker()
built._computed = True
built._compute_cached = MagicMock(return_value=[1.0])
with patch.object(worker, "model"):
with loading():
_, cached = built.embed("hello", "m1")
assert cached is True

def it_stages_the_text_and_model_for_compute():
built, _ = make_worker()
built._compute_cached = MagicMock(return_value=[1.0])
with patch.object(worker, "model") as model:
with loading() as (model, _):
built.embed("hello", "m1")
assert built._pending == ("hello", model.load_model.return_value)

def it_hashes_the_utf8_bytes_of_the_text():
built, _ = make_worker()
built._compute_cached = MagicMock(return_value=[1.0])
with patch.object(worker, "model") as model:
model.model_identifier.return_value = "m1"
with loading("m1"):
built.embed("héllo", "m1")
expected = sha256("héllo".encode("utf-8")).hexdigest()
assert built._compute_cached.call_args == call(expected, "m1")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from .embed_call import embed_call
from .normalize_glob import normalize_glob
from .quote import quote


def build_search_sql(glob, query, limit, model=None):
outer = embed_call(quote(query), model)
inner = embed_call("content", model)
# A matched file that is unreadable, not valid UTF-8, or deleted mid-scan
# has NULL content, so its embedding is NULL too. Dropping those rows is
# what keeps the ranking honest: a NULL distance sorts FIRST ascending in
# SQLite, so unrankable files would otherwise take the top-k slots.
return (
f"SELECT path, vec_distance_cosine(emb, {outer}) AS distance"
f" FROM (SELECT path, {inner} AS emb FROM {quote(normalize_glob(glob))})"
f" WHERE emb IS NOT NULL"
f" ORDER BY distance LIMIT {int(limit):d}"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from unittest.mock import patch

from . import build_search_sql as module


def build(glob, query, limit, *args):
with patch.object(module, "quote", side_effect=lambda text: f"<{text}>"):
with patch.object(
module, "normalize_glob", side_effect=lambda g: f"N({g})"
):
with patch.object(
module, "embed_call", side_effect=lambda a, m: f"E({a},{m})"
) as embed:
return module.build_search_sql(glob, query, limit, *args), embed


def describe_build_search_sql():
def it_assembles_the_ranking_query_from_its_collaborators():
sql, _ = build("docs/**/*.md", "local models", 10, "my/model")
assert sql == (
"SELECT path, vec_distance_cosine(emb, E(<local models>,my/model))"
" AS distance"
" FROM (SELECT path, E(content,my/model) AS emb"
" FROM <N(docs/**/*.md)>)"
" WHERE emb IS NOT NULL"
" ORDER BY distance LIMIT 10"
)

def it_embeds_the_query_and_the_content_column_with_the_same_model():
_, embed = build("g", "q", 10, "my/model")
assert [args for args, _ in embed.call_args_list] == [
("<q>", "my/model"),
("content", "my/model"),
]

def it_defaults_the_model_to_none():
_, embed = build("g", "q", 10)
assert [args[1] for args, _ in embed.call_args_list] == [None, None]

def it_drops_rows_whose_embedding_is_null():
# A file that is unreadable or not valid UTF-8 has NULL content, so
# embed() returns NULL and vec_distance_cosine() does too. SQLite
# sorts NULLs first ascending, so without this guard those files take
# the top-k slots and then break the distance formatting.
sql, _ = build("g", "q", 10)
assert " WHERE emb IS NOT NULL ORDER BY distance" in sql

def it_coerces_the_limit_to_a_decimal_integer():
sql, _ = build("g", "q", "12")
assert sql.endswith("LIMIT 12")
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from .normalize_glob import normalize_glob
from .quote import quote


def count_corpus_sql(glob):
return f"SELECT COUNT(*) AS n FROM {quote(normalize_glob(glob))}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from unittest.mock import patch

from . import count_corpus_sql as module


def count(glob):
with patch.object(module, "quote", side_effect=lambda text: f"<{text}>"):
with patch.object(
module, "normalize_glob", side_effect=lambda g: f"N({g})"
) as normalize:
return module.count_corpus_sql(glob), normalize


def describe_count_corpus_sql():
def it_counts_the_files_the_normalized_quoted_glob_matches():
sql, normalize = count("docs/**/*.md")
assert sql == "SELECT COUNT(*) AS n FROM <N(docs/**/*.md)>"
normalize.assert_called_once_with("docs/**/*.md")
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from .quote import quote


def embed_call(argument, model):
if model is None:
return f"embed({argument})"
return f"embed({argument}, {quote(model)})"
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from unittest.mock import patch

from . import embed_call as module


def call(argument, model):
with patch.object(module, "quote", side_effect=lambda text: f"<{text}>"):
return module.embed_call(argument, model)


def describe_embed_call():
def it_omits_the_model_argument_when_model_is_none():
assert call("content", None) == "embed(content)"

def it_quotes_the_model_id_as_the_second_argument():
assert call("content", "my/model") == "embed(content, <my/model>)"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
def no_rows_message(glob, matched, root):
if not matched:
return f"no files matched {glob!r} (searched from {root})"
return (
f"{glob!r} matched {matched} file(s), but none had text content to"
f" embed -- unreadable or not valid UTF-8 (searched from {root})"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from . import no_rows_message as module


def describe_no_rows_message():
def it_names_the_glob_and_the_root_when_no_file_matched():
message = module.no_rows_message("docs/**/*.md", 0, "/work")
assert message == (
"no files matched 'docs/**/*.md' (searched from /work)"
)

def it_says_files_matched_but_none_were_embeddable():
message = module.no_rows_message("docs/**/*.md", 3, "/work")
assert message == (
"'docs/**/*.md' matched 3 file(s), but none had text content to"
" embed -- unreadable or not valid UTF-8 (searched from /work)"
)

def it_reports_a_none_count_as_nothing_matched():
assert "no files matched" in module.no_rows_message("g", None, "/work")
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PATH_PREFIXES = ("./", "../", "/", "~/")


def normalize_glob(glob):
# The core only rescues path-shaped missing tables (./, ../, /, ~/); a
# bare relative glob like '**/*.md' would error with a "did you mean
# './...'" hint. Here GLOB is unambiguously a corpus glob, so spare the
# user the round trip.
if glob.startswith(PATH_PREFIXES):
return glob
return f"./{glob}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from . import normalize_glob as module


def describe_path_prefixes():
def it_is_exactly_the_four_prefixes_the_core_rescues():
assert module.PATH_PREFIXES == ("./", "../", "/", "~/")


def describe_normalize_glob():
def it_prefixes_a_bare_relative_glob_with_dot_slash():
assert module.normalize_glob("**/*.md") == "./**/*.md"

def it_keeps_a_dot_slash_glob():
assert module.normalize_glob("./notes/*.txt") == "./notes/*.txt"

def it_keeps_a_parent_relative_glob():
assert module.normalize_glob("../notes/*.txt") == "../notes/*.txt"

def it_keeps_an_absolute_glob():
assert module.normalize_glob("/tmp/notes/*.txt") == "/tmp/notes/*.txt"

def it_keeps_a_home_glob():
assert module.normalize_glob("~/notes/*.txt") == "~/notes/*.txt"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def quote(text):
escaped = text.replace("'", "''")
return f"'{escaped}'"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from . import quote as module


def describe_quote():
def it_wraps_text_in_single_quotes():
assert module.quote("hello") == "'hello'"

def it_doubles_embedded_single_quotes():
assert module.quote("O'Brien") == "'O''Brien'"

def it_keeps_an_injection_shaped_value_inside_the_literal():
assert module.quote("'; DROP TABLE x; --") == "'''; DROP TABLE x; --'"
Loading
Loading