Files
chemenu/tools/chemenu/search/registry.py
T
torben 576df2cddd
CI / verify (push) Successful in 52s
Release / release (push) Successful in 37s
feat: MCP-Leseserver, Bibliotheksgrenze, Haertung des Lesepfads, Publish-Remote-Gate scharf (2.4.0)
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
2026-09-02 07:19:32 +02:00

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]