chore: import upstream snapshot with attribution
Integ / changes (push) Has been skipped
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
Test (Python) / changes (push) Has been skipped
Test (TypeScript) / changes (push) Has been skipped
CLI exit codes / cli-gate (push) Has been cancelled
Test (Install) / test-install-gate (push) Has been cancelled
Integ / integ-gate (push) Has been cancelled
Test (Python) / test-python-gate (push) Has been cancelled
Test (TypeScript) / test-typescript-gate (push) Has been cancelled
Test (Install) / python-minimal (3.12) (push) Has been cancelled
Test (Install) / python-minimal (3.11) (push) Has been cancelled
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Has been cancelled
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Has been cancelled
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Has been cancelled
Integ / integ (push) Has been cancelled
Integ / integ-database (push) Has been cancelled
Integ / integ-database-ts (push) Has been cancelled
Integ / integ-data (push) Has been cancelled
Integ / integ-ssh (push) Has been cancelled
Integ / integ-ssh-ts (push) Has been cancelled
Test (Python) / audit (push) Has been cancelled
Test (TypeScript) / test (push) Has been cancelled
Test (TypeScript) / python-fs-shim (push) Has been cancelled
CLI exit codes / Python CLI (push) Has been cancelled
CLI exit codes / TypeScript CLI (push) Has been cancelled
CLI exit codes / Cross-language snapshot interop (push) Has been cancelled
Test (Python) / test (push) Has been cancelled
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Integ / integ-ts (push) Has been cancelled
Integ / integ-fuse (push) Has been cancelled
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Has been cancelled
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Has been cancelled
Test (Install) / python-extra (email, mirage.resource.email) (push) Has been cancelled
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Has been cancelled
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Has been cancelled
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Has been cancelled
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Has been cancelled
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Has been cancelled
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Has been cancelled
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Has been cancelled
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Has been cancelled
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Has been cancelled
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Has been cancelled
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Has been cancelled
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Has been cancelled
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Has been cancelled
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Has been cancelled
Test (Install) / ts-minimal (push) Has been cancelled
Integ / changes (push) Has been skipped
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
Test (Python) / changes (push) Has been skipped
Test (TypeScript) / changes (push) Has been skipped
CLI exit codes / cli-gate (push) Has been cancelled
Test (Install) / test-install-gate (push) Has been cancelled
Integ / integ-gate (push) Has been cancelled
Test (Python) / test-python-gate (push) Has been cancelled
Test (TypeScript) / test-typescript-gate (push) Has been cancelled
Test (Install) / python-minimal (3.12) (push) Has been cancelled
Test (Install) / python-minimal (3.11) (push) Has been cancelled
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Has been cancelled
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Has been cancelled
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Has been cancelled
Integ / integ (push) Has been cancelled
Integ / integ-database (push) Has been cancelled
Integ / integ-database-ts (push) Has been cancelled
Integ / integ-data (push) Has been cancelled
Integ / integ-ssh (push) Has been cancelled
Integ / integ-ssh-ts (push) Has been cancelled
Test (Python) / audit (push) Has been cancelled
Test (TypeScript) / test (push) Has been cancelled
Test (TypeScript) / python-fs-shim (push) Has been cancelled
CLI exit codes / Python CLI (push) Has been cancelled
CLI exit codes / TypeScript CLI (push) Has been cancelled
CLI exit codes / Cross-language snapshot interop (push) Has been cancelled
Test (Python) / test (push) Has been cancelled
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Integ / integ-ts (push) Has been cancelled
Integ / integ-fuse (push) Has been cancelled
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Has been cancelled
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Has been cancelled
Test (Install) / python-extra (email, mirage.resource.email) (push) Has been cancelled
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Has been cancelled
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Has been cancelled
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Has been cancelled
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Has been cancelled
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Has been cancelled
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Has been cancelled
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Has been cancelled
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Has been cancelled
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Has been cancelled
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Has been cancelled
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Has been cancelled
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Has been cancelled
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Has been cancelled
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Has been cancelled
Test (Install) / ts-minimal (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import hashlib
|
||||
|
||||
import lancedb
|
||||
import numpy as np
|
||||
import pyarrow as pa
|
||||
import pytest
|
||||
from lancedb.embeddings import EmbeddingFunction, get_registry
|
||||
from lancedb.pydantic import LanceModel, Vector
|
||||
|
||||
from mirage.accessor.lancedb import LanceDBAccessor
|
||||
from mirage.resource.lancedb.config import LanceDBConfig
|
||||
|
||||
_DIMS = 8
|
||||
_STUB_NAME = "stub-lancedb-test"
|
||||
|
||||
|
||||
def _vec(text: str) -> list[float]:
|
||||
digest = hashlib.sha256(text.encode()).digest()
|
||||
arr = np.frombuffer(digest[:_DIMS * 4], dtype=np.uint32).astype(np.float32)
|
||||
norm = float(np.linalg.norm(arr)) or 1.0
|
||||
return (arr / norm).tolist()
|
||||
|
||||
|
||||
class StubEmbedding(EmbeddingFunction):
|
||||
|
||||
def ndims(self) -> int:
|
||||
return _DIMS
|
||||
|
||||
def compute_query_embeddings(self, query, *args, **kwargs):
|
||||
if isinstance(query, str):
|
||||
return [_vec(query)]
|
||||
return [_vec(str(item)) for item in query]
|
||||
|
||||
def compute_source_embeddings(self, texts, *args, **kwargs):
|
||||
items = texts.to_pylist() if isinstance(texts,
|
||||
pa.Array) else list(texts)
|
||||
return [_vec(str(item)) for item in items]
|
||||
|
||||
|
||||
def _ensure_registered() -> None:
|
||||
registry = get_registry()
|
||||
try:
|
||||
registry.get(_STUB_NAME)
|
||||
except KeyError:
|
||||
registry.register(_STUB_NAME)(StubEmbedding)
|
||||
|
||||
|
||||
_ROWS = [
|
||||
{
|
||||
"id": 1,
|
||||
"label": "cat",
|
||||
"kind": "big",
|
||||
"name": "a big orange cat"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"label": "cat",
|
||||
"kind": "small",
|
||||
"name": "a small grey cat"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"label": "dog",
|
||||
"kind": "big",
|
||||
"name": "a big brown dog"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"label": "dog",
|
||||
"kind": "small",
|
||||
"name": "a small white dog"
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def lance_config(tmp_path) -> LanceDBConfig:
|
||||
_ensure_registered()
|
||||
func = get_registry().get(_STUB_NAME).create()
|
||||
|
||||
class Animal(LanceModel):
|
||||
id: int
|
||||
label: str
|
||||
kind: str
|
||||
name: str = func.SourceField()
|
||||
image_bytes: bytes
|
||||
vector: Vector(func.ndims()) = func.VectorField()
|
||||
|
||||
uri = str(tmp_path / "db")
|
||||
db = lancedb.connect(uri)
|
||||
table = db.create_table("animals", schema=Animal)
|
||||
table.add([{
|
||||
**row, "image_bytes": f"PNG-{row['id']}".encode()
|
||||
} for row in _ROWS])
|
||||
return LanceDBConfig(
|
||||
uri=uri,
|
||||
group_by=["label", "kind"],
|
||||
id_column="id",
|
||||
title_column="name",
|
||||
blob_column="image_bytes",
|
||||
blob_ext="png",
|
||||
text_column="name",
|
||||
vector_column="vector",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def accessor(lance_config) -> LanceDBAccessor:
|
||||
return LanceDBAccessor(lance_config)
|
||||
@@ -0,0 +1,92 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import pytest
|
||||
|
||||
from mirage.commands.builtin.lancedb import COMMANDS
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
def _find_command():
|
||||
for fn in COMMANDS:
|
||||
for rc in getattr(fn, "_registered_commands", []):
|
||||
if rc.name == "find" and rc.filetype is None:
|
||||
return fn
|
||||
raise AssertionError("factory find not registered for lancedb")
|
||||
|
||||
|
||||
def _spec(virtual: str) -> PathSpec:
|
||||
return PathSpec(virtual=virtual,
|
||||
directory=virtual,
|
||||
resource_path=virtual.strip("/"))
|
||||
|
||||
|
||||
async def _run(accessor, paths, *texts: str, **flags) -> list[str]:
|
||||
find = _find_command()
|
||||
stdout, _io = await find(accessor, paths, *texts, index=None, **flags)
|
||||
data = stdout if isinstance(stdout, bytes) else b""
|
||||
return data.decode().splitlines()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_plain_find_walks_groups_to_row_files(accessor):
|
||||
lines = await _run(accessor, [_spec("/")])
|
||||
assert "/animals/cat/big/1.md" in lines
|
||||
assert "/animals/cat/big/1.png" in lines
|
||||
assert "/animals/dog/small" in lines
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_name_selects_blob_files(accessor):
|
||||
lines = await _run(accessor, [_spec("/")], name="*.png")
|
||||
assert lines == [
|
||||
"/animals/cat/big/1.png",
|
||||
"/animals/cat/small/2.png",
|
||||
"/animals/dog/big/3.png",
|
||||
"/animals/dog/small/4.png",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_type_d_walks_without_stat_via_config_hint(accessor):
|
||||
lines = await _run(accessor, [_spec("/")], type="d")
|
||||
assert "/animals" in lines
|
||||
assert "/animals/cat" in lines
|
||||
assert "/animals/dog/small" in lines
|
||||
assert all(not line.endswith((".md", ".png")) for line in lines)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_depth_and_start_point(accessor):
|
||||
lines = await _run(accessor, [_spec("/animals/cat")], maxdepth="1")
|
||||
assert lines == [
|
||||
"/animals/cat",
|
||||
"/animals/cat/big",
|
||||
"/animals/cat/small",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_multi_start_points_in_operand_order(accessor):
|
||||
lines = await _run(
|
||||
accessor,
|
||||
[_spec("/animals/dog"), _spec("/animals/cat")],
|
||||
type="f",
|
||||
name="*.md")
|
||||
assert lines == [
|
||||
"/animals/dog/big/3.md",
|
||||
"/animals/dog/small/4.md",
|
||||
"/animals/cat/big/1.md",
|
||||
"/animals/cat/small/2.md",
|
||||
]
|
||||
@@ -0,0 +1,45 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import pytest
|
||||
|
||||
from mirage.core.lancedb.read import read
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
def _ps(path: str) -> PathSpec:
|
||||
return PathSpec(virtual=path,
|
||||
directory=path,
|
||||
resource_path=path.strip("/"))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read_card_renders_title_and_fields(accessor):
|
||||
data = (await read(accessor, _ps("/animals/cat/big/1.md"))).decode()
|
||||
assert "# a big orange cat" in data
|
||||
assert "label: cat" in data
|
||||
assert "blob: 1.png" in data
|
||||
assert "vector" not in data
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read_blob_returns_raw_bytes(accessor):
|
||||
data = await read(accessor, _ps("/animals/cat/big/1.png"))
|
||||
assert data == b"PNG-1"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read_missing_row_raises(accessor):
|
||||
with pytest.raises(FileNotFoundError):
|
||||
await read(accessor, _ps("/animals/cat/big/999.md"))
|
||||
@@ -0,0 +1,62 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import pytest
|
||||
|
||||
from mirage.core.lancedb.readdir import is_dir_name, readdir
|
||||
from mirage.resource.lancedb.config import LanceDBConfig
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
def _ps(path: str) -> PathSpec:
|
||||
return PathSpec(virtual=path,
|
||||
directory=path,
|
||||
resource_path=path.strip("/"))
|
||||
|
||||
|
||||
def _names(paths: list[str]) -> set[str]:
|
||||
return {p.rsplit("/", 1)[-1] for p in paths}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_root_lists_table(accessor):
|
||||
out = await readdir(accessor, _ps("/"))
|
||||
assert _names(out) == {"animals"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_table_lists_groups(accessor):
|
||||
out = await readdir(accessor, _ps("/animals"))
|
||||
assert _names(out) == {"cat", "dog"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_group_lists_next_level(accessor):
|
||||
out = await readdir(accessor, _ps("/animals/cat"))
|
||||
assert _names(out) == {"big", "small"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_leaf_lists_row_files(accessor):
|
||||
out = await readdir(accessor, _ps("/animals/cat/big"))
|
||||
assert _names(out) == {"1.md", "1.png"}
|
||||
|
||||
|
||||
def test_is_dir_name_classifies_row_files():
|
||||
cfg = LanceDBConfig(uri="mem://", blob_column="img", blob_ext="png")
|
||||
assert is_dir_name("/animals/cat", config=cfg) is True
|
||||
assert is_dir_name("/animals/cat/big/1.md", config=cfg) is False
|
||||
assert is_dir_name("/animals/cat/big/1.png", config=cfg) is False
|
||||
no_blob = LanceDBConfig(uri="mem://")
|
||||
assert is_dir_name("/animals/cat/big/1.png", config=no_blob) is True
|
||||
@@ -0,0 +1,47 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.core.lancedb.render import render_card
|
||||
from mirage.resource.lancedb.config import LanceDBConfig
|
||||
|
||||
|
||||
def _cfg() -> LanceDBConfig:
|
||||
return LanceDBConfig(uri="/tmp/db",
|
||||
id_column="id",
|
||||
title_column="name",
|
||||
blob_column="image_bytes",
|
||||
blob_ext="png",
|
||||
vector_column="vector")
|
||||
|
||||
|
||||
def test_render_card_basic():
|
||||
row = {
|
||||
"id": 3,
|
||||
"name": "a big brown dog",
|
||||
"label": "dog",
|
||||
"image_bytes": b"PNG-3",
|
||||
"vector": [0.1, 0.2],
|
||||
}
|
||||
out = render_card(row, _cfg()).decode()
|
||||
assert out.startswith("# a big brown dog")
|
||||
assert "label: dog" in out
|
||||
assert "blob: 3.png" in out
|
||||
assert "vector" not in out
|
||||
assert "PNG-3" not in out
|
||||
|
||||
|
||||
def test_render_card_includes_score():
|
||||
row = {"id": 3, "name": "x", "_distance": 0.25}
|
||||
out = render_card(row, _cfg()).decode()
|
||||
assert "score: 0.2500" in out
|
||||
@@ -0,0 +1,81 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
from mirage.core.lancedb.scope import ScopeLevel, detect_scope
|
||||
from mirage.resource.lancedb.config import LanceDBConfig
|
||||
from mirage.types import PathSpec
|
||||
|
||||
|
||||
def _cfg(**kw) -> LanceDBConfig:
|
||||
base = dict(uri="/tmp/db",
|
||||
group_by=["label", "kind"],
|
||||
id_column="id",
|
||||
title_column="name",
|
||||
blob_column="image_bytes",
|
||||
blob_ext="png",
|
||||
vector_column="vector")
|
||||
base.update(kw)
|
||||
return LanceDBConfig(**base)
|
||||
|
||||
|
||||
def _ps(path: str) -> PathSpec:
|
||||
return PathSpec(virtual=path,
|
||||
directory=path,
|
||||
resource_path=path.strip("/"))
|
||||
|
||||
|
||||
def test_root_multi_table():
|
||||
s = detect_scope(_ps("/"), _cfg())
|
||||
assert s.level == ScopeLevel.ROOT
|
||||
|
||||
|
||||
def test_table_group_dir():
|
||||
s = detect_scope(_ps("/animals"), _cfg())
|
||||
assert s.level == ScopeLevel.GROUP_DIR
|
||||
assert s.table == "animals"
|
||||
assert s.filters == {}
|
||||
|
||||
|
||||
def test_nested_group_dir():
|
||||
s = detect_scope(_ps("/animals/cat"), _cfg())
|
||||
assert s.level == ScopeLevel.GROUP_DIR
|
||||
assert s.filters == {"label": "cat"}
|
||||
|
||||
|
||||
def test_leaf_group_dir():
|
||||
s = detect_scope(_ps("/animals/cat/big"), _cfg())
|
||||
assert s.level == ScopeLevel.GROUP_DIR
|
||||
assert s.filters == {"label": "cat", "kind": "big"}
|
||||
|
||||
|
||||
def test_row_card():
|
||||
s = detect_scope(_ps("/animals/cat/big/3.md"), _cfg())
|
||||
assert s.level == ScopeLevel.ROW
|
||||
assert s.row_id == "3"
|
||||
assert s.blob is False
|
||||
assert s.filters == {"label": "cat", "kind": "big"}
|
||||
|
||||
|
||||
def test_row_blob():
|
||||
s = detect_scope(_ps("/animals/cat/big/3.png"), _cfg())
|
||||
assert s.level == ScopeLevel.ROW
|
||||
assert s.row_id == "3"
|
||||
assert s.blob is True
|
||||
|
||||
|
||||
def test_single_table_pin_elides_table():
|
||||
s = detect_scope(_ps("/cat/big"), _cfg(table="animals"))
|
||||
assert s.level == ScopeLevel.GROUP_DIR
|
||||
assert s.table == "animals"
|
||||
assert s.filters == {"label": "cat", "kind": "big"}
|
||||
@@ -0,0 +1,69 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import pytest
|
||||
|
||||
from mirage.core.lancedb.search import search_rows_output
|
||||
from mirage.types import PathSpec
|
||||
from mirage.utils.key_prefix import mount_key
|
||||
|
||||
|
||||
def _ps(path: str) -> PathSpec:
|
||||
return PathSpec(resource_path=mount_key(path, "/db"),
|
||||
virtual=path,
|
||||
directory=path)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_emits_canonical_path_with_score(accessor):
|
||||
out = (await search_rows_output(accessor,
|
||||
"a small white dog", [_ps("/db/animals")],
|
||||
top_k=2,
|
||||
threshold=0.0,
|
||||
mount_prefix="/db")).decode()
|
||||
first = out.splitlines()[0]
|
||||
assert first.startswith("/db/animals/dog/small/4.md:")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_body_matches_card(accessor):
|
||||
out = (await search_rows_output(accessor,
|
||||
"a small white dog", [_ps("/db/animals")],
|
||||
top_k=1,
|
||||
threshold=0.0,
|
||||
mount_prefix="/db")).decode()
|
||||
assert "# a small white dog" in out
|
||||
assert "label: dog" in out
|
||||
assert "score:" not in out
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_top_k_limits_results(accessor):
|
||||
out = (await search_rows_output(accessor,
|
||||
"a small white dog", [_ps("/db/animals")],
|
||||
top_k=1,
|
||||
threshold=0.0,
|
||||
mount_prefix="/db")).decode()
|
||||
headers = [ln for ln in out.splitlines() if ln.startswith("/db/")]
|
||||
assert len(headers) == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_empty_query_raises(accessor):
|
||||
with pytest.raises(ValueError):
|
||||
await search_rows_output(accessor,
|
||||
"", [_ps("/db/animals")],
|
||||
top_k=2,
|
||||
threshold=0.0,
|
||||
mount_prefix="/db")
|
||||
@@ -0,0 +1,51 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import pytest
|
||||
|
||||
from mirage.core.lancedb.stat import stat
|
||||
from mirage.types import FileType, PathSpec
|
||||
|
||||
|
||||
def _ps(path: str) -> PathSpec:
|
||||
return PathSpec(virtual=path,
|
||||
directory=path,
|
||||
resource_path=path.strip("/"))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_stat_group_dir_is_directory(accessor):
|
||||
s = await stat(accessor, _ps("/animals/cat"))
|
||||
assert s.type == FileType.DIRECTORY
|
||||
assert s.name == "cat"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_stat_card_is_text_with_size(accessor):
|
||||
s = await stat(accessor, _ps("/animals/cat/big/1.md"))
|
||||
assert s.type == FileType.TEXT
|
||||
assert s.size and s.size > 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_stat_blob_is_image(accessor):
|
||||
s = await stat(accessor, _ps("/animals/cat/big/1.png"))
|
||||
assert s.type == FileType.IMAGE_PNG
|
||||
assert s.size == len(b"PNG-1")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_stat_unknown_raises(accessor):
|
||||
with pytest.raises(FileNotFoundError):
|
||||
await stat(accessor, _ps("/animals/cat/big/1.weird/x"))
|
||||
@@ -0,0 +1,78 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import pytest
|
||||
|
||||
from mirage.resource.lancedb import LanceDBResource
|
||||
from mirage.types import MountMode
|
||||
from mirage.workspace import Workspace
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def ws(lance_config) -> Workspace:
|
||||
return Workspace({"/db/": LanceDBResource(lance_config)},
|
||||
mode=MountMode.READ)
|
||||
|
||||
|
||||
async def _out(ws: Workspace, cmd: str) -> str:
|
||||
result = await ws.execute(cmd)
|
||||
return await result.stdout_str()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ls_root_lists_table(ws):
|
||||
assert "animals" in await _out(ws, "ls /db/")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ls_table_lists_groups(ws):
|
||||
out = await _out(ws, "ls /db/animals")
|
||||
assert "cat" in out and "dog" in out
|
||||
assert "_search" not in out
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cat_card(ws):
|
||||
out = await _out(ws, "cat /db/animals/cat/big/1.md")
|
||||
assert "# a big orange cat" in out
|
||||
assert "label: cat" in out
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_tree_shows_hierarchy(ws):
|
||||
out = await _out(ws, "tree -L 2 /db/animals")
|
||||
assert "cat" in out and "dog" in out
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_returns_canonical_path_and_card(ws):
|
||||
out = await _out(ws, 'search "a small white dog" /db/animals')
|
||||
assert "/db/animals/dog/small/4.md" in out
|
||||
assert "# a small white dog" in out
|
||||
assert "score:" not in out
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_result_path_is_readable(ws):
|
||||
out = await _out(ws, 'search "a small white dog" /db/animals')
|
||||
line = out.splitlines()[0]
|
||||
path = line.split(":", 1)[0]
|
||||
card = await _out(ws, f"cat {path}")
|
||||
assert "# a small white dog" in card
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_grep_recursive_over_cards(ws):
|
||||
out = await _out(ws, "grep -rl cat /db/animals")
|
||||
assert ".md" in out
|
||||
Reference in New Issue
Block a user