Reject a database with no name or location

A blank name is falsy, so source routing reads it as absent, and a blank
location resolves to the working directory. `is_read_only` reports the
mode the client was opened with, which a client covering a set can answer
without a store.
This commit is contained in:
Yiorgis Gozadinos 2026-08-24 08:52:56 +03:00
parent e94623ec37
commit bc04dfdb7a
No known key found for this signature in database
3 changed files with 44 additions and 2 deletions

View file

@ -127,8 +127,12 @@ class HaikuRAG:
@property @property
def is_read_only(self) -> bool: def is_read_only(self) -> bool:
"""Whether the client is in read-only mode.""" """Whether the client is in read-only mode.
return self.store.is_read_only
The mode the client was opened with, which is the mode every database it
covers is opened with. A client covering a set has no store to ask.
"""
return self._read_only
@property @property
def embedder(self) -> "EmbedderWrapper": def embedder(self) -> "EmbedderWrapper":

View file

@ -123,6 +123,13 @@ class LanceDBConfig(ConfigModel):
"lancedb.uri and lancedb.databases are mutually exclusive: " "lancedb.uri and lancedb.databases are mutually exclusive: "
"use uri for one database, databases for several" "use uri for one database, databases for several"
) )
for name, location in self.databases.items():
# A blank name is falsy, so source routing reads it as absent; a
# blank location resolves to the working directory.
if not name.strip():
raise ValueError("lancedb.databases has an entry with no name")
if not location.strip():
raise ValueError(f"lancedb.databases[{name}] has no location")
return self return self

View file

@ -28,6 +28,23 @@ class TestConfig:
assert LanceDBConfig(uri="s3://b/one.lancedb").databases == {} assert LanceDBConfig(uri="s3://b/one.lancedb").databases == {}
class TestNamingIsRequired:
def test_a_blank_name_is_rejected(self):
"""An unnamed database is unreachable: every source check reads the
empty name as no name at all."""
with pytest.raises(ValidationError, match="entry with no name"):
LanceDBConfig(databases={"": "/tmp/a.lancedb"})
with pytest.raises(ValidationError, match="entry with no name"):
LanceDBConfig(databases={" ": "/tmp/a.lancedb"})
def test_a_blank_location_is_rejected(self):
"""A blank location resolves to the working directory."""
with pytest.raises(
ValidationError, match=r"databases\[alpha\] has no location"
):
LanceDBConfig(databases={"alpha": ""})
def _config(tmp_path, names) -> AppConfig: def _config(tmp_path, names) -> AppConfig:
return AppConfig( return AppConfig(
lancedb=LanceDBConfig( lancedb=LanceDBConfig(
@ -279,6 +296,20 @@ class TestLookupByIdentifier:
assert await rag.get_document_by_uri("test://nowhere") is None assert await rag.get_document_by_uri("test://nowhere") is None
class TestReadOnlyMode:
@pytest.mark.asyncio
async def test_a_client_covering_a_set_reports_its_mode(self, tmp_path):
"""A client covering a set has no store of its own to ask."""
config = _config(tmp_path, ["alpha", "beta"])
await _seed(config, "alpha", ["alpha one"])
await _seed(config, "beta", ["beta one"])
async with HaikuRAG(config=config, read_only=True) as rag:
assert rag.is_read_only is True
async with HaikuRAG(config=config) as rag:
assert rag.is_read_only is False
class TestDocumentsNameTheirDatabase: class TestDocumentsNameTheirDatabase:
"""A listing that spans databases is unreadable when the documents do not """A listing that spans databases is unreadable when the documents do not
say which one they came from, the same reason a search result carries one.""" say which one they came from, the same reason a search result carries one."""