576df2cddd
Files changed: - .gitea/workflows/ci.yml - CHANGES.md - README.md - VERSION - instructions/mcp-read-server.md - tools/CONTRACT.md - tools/README.md - tools/chemenu/api.py - tools/chemenu/commands/doctor.py - tools/chemenu/commands/lint.py - tools/chemenu/commands/search.py - tools/chemenu/commands/types_cmd.py - tools/chemenu/config.py - tools/chemenu/corpus_cache.py - tools/chemenu/errors.py - tools/chemenu/frontmatter_io.py - tools/chemenu/lint_core.py - tools/chemenu/mcp/__init__.py - tools/chemenu/mcp/__main__.py - tools/chemenu/mcp/server.py - tools/chemenu/page.py - tools/chemenu/search/filters.py - tools/chemenu/search/registry.py - tools/chemenu/search/ripgrep.py - tools/chemenu/search/service.py - tools/chemenu/tests/conftest.py - tools/chemenu/tests/test_api.py - tools/chemenu/tests/test_corpus_cache.py - tools/chemenu/tests/test_doctor.py - tools/chemenu/tests/test_frontmatter_io.py - tools/chemenu/tests/test_instructions_cmd.py - tools/chemenu/tests/test_mcp_server.py - tools/chemenu/tests/test_new_page.py - tools/chemenu/tests/test_search.py - tools/chemenu/type_resolver.py - tools/chemenu/types_core.py - tools/requirements-mcp.txt
53 lines
1.7 KiB
Python
53 lines
1.7 KiB
Python
"""Backend selection.
|
|
|
|
One registry entry today. It exists so that adding a semantic/vector backend is
|
|
a new module plus one line here - not a change to the command, the filters, or
|
|
the output shape. Selecting several at once fuses them through RRF.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Callable, Optional
|
|
|
|
from chemenu.errors import ValidationError
|
|
from chemenu.search.base import SearchBackend
|
|
from chemenu.search.ripgrep import RipgrepBackend
|
|
|
|
DEFAULT_BACKEND = "rg"
|
|
ENV_VAR = "WIKITOOL_SEARCH_BACKEND"
|
|
|
|
BACKENDS: dict[str, Callable[..., SearchBackend]] = {
|
|
"rg": RipgrepBackend,
|
|
}
|
|
|
|
|
|
class UnknownBackend(ValidationError):
|
|
pass
|
|
|
|
|
|
def resolve(
|
|
spec: str | None = None,
|
|
kb_dir: Optional[Path] = None,
|
|
root: Optional[Path] = None,
|
|
) -> list[SearchBackend]:
|
|
"""Resolve a backend spec into instances.
|
|
|
|
Precedence: explicit argument, then `WIKITOOL_SEARCH_BACKEND`, then the
|
|
default. A comma-separated spec selects several and fuses their rankings.
|
|
|
|
`kb_dir`/`root` are handed to the backend rather than left to its own
|
|
defaults. Without them a caller could pass a corpus to `run_search` and
|
|
still have the backend walk `config.KB_DIR` - the query answered from one
|
|
tree and the pages read from another, with nothing saying so.
|
|
"""
|
|
raw = spec or os.environ.get(ENV_VAR) or DEFAULT_BACKEND
|
|
names = [n.strip() for n in raw.split(",") if n.strip()]
|
|
unknown = [n for n in names if n not in BACKENDS]
|
|
if unknown:
|
|
raise UnknownBackend(
|
|
f"unknown search backend(s): {', '.join(unknown)}. "
|
|
f"Available: {', '.join(sorted(BACKENDS))}"
|
|
)
|
|
return [BACKENDS[name](kb_dir, root) for name in names]
|