Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
40 changes: 39 additions & 1 deletion src/paperqa/agents/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,37 @@ def build_index(
return run_or_ensure(coro=get_directory_index(settings=settings))


def pqa_root() -> Path:
"""Return the `.pqa` directory used for indexes and saved settings."""
if pqa_home := os.environ.get("PQA_HOME"):
return Path(pqa_home) / ".pqa"
return Path.home() / ".pqa"
Comment thread
krudo-taco marked this conversation as resolved.


def list_built_indexes(index_directory: str | os.PathLike) -> list[str]:
"""Return sorted names of built indexes under `index_directory`."""
directory = Path(index_directory)
if not directory.is_dir():
return []
return sorted(path.name for path in directory.iterdir() if path.is_dir())
Comment thread
krudo-taco marked this conversation as resolved.
Outdated


def show_pqa_paths(settings: Settings) -> None:
"""Print the `.pqa` directory, index directory, and built index names."""
configure_cli_logging(settings)
root = pqa_root()
index_directory = Path(settings.agent.index.index_directory)
logger.info(f"PQA directory: {root}")
logger.info(f"Index directory: {index_directory}")
indexes = list_built_indexes(index_directory)
if indexes:
logger.info("Indexes:")
for name in indexes:
logger.info(f" {name}")
else:
logger.info("Indexes: (none)")


def save_settings(settings: Settings, settings_path: str | os.PathLike) -> None:
"""Save the settings to a file."""
configure_cli_logging(settings)
Expand Down Expand Up @@ -216,6 +247,11 @@ def main() -> None:
)
build_parser.add_argument("directory", help="Directory to build index from")

subparsers.add_parser(
"where",
help="Print the `.pqa` directory, index directory, and built indexes",
)

# Create CliSettingsSource instance
cli_settings = CliSettingsSource[argparse.ArgumentParser](
Settings, root_parser=parser
Expand All @@ -241,8 +277,10 @@ def main() -> None:
search_query(args.query, args.index, settings)
case "index":
build_index(args.index, args.directory, settings)
case "where":
show_pqa_paths(settings)
case _:
commands = ", ".join({"view", "ask", "search", "index"})
commands = ", ".join({"view", "ask", "search", "index", "where"})
Comment thread
krudo-taco marked this conversation as resolved.
Outdated
brief_help = f"\nRun with commands: {{{commands}}}\n\n"
brief_help += "For more information, run with --help"
print(brief_help)
Expand Down
41 changes: 40 additions & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
import os
import sys
import zlib
Expand All @@ -8,7 +9,7 @@
from tenacity import Retrying, retry_if_exception_type, stop_after_attempt

from paperqa import Docs
from paperqa.agents import ask, build_index, main, search_query
from paperqa.agents import ask, build_index, list_built_indexes, main, search_query
from paperqa.agents.models import AnswerResponse
from paperqa.settings import Settings
from paperqa.utils import pqa_directory
Expand Down Expand Up @@ -48,6 +49,44 @@ def test_can_modify_settings(capsys, stub_data_dir: Path) -> None:
os.unlink(pqa_directory("settings") / "unit_test.json")


def test_cli_where_prints_pqa_directory_and_indexes(
caplog: pytest.LogCaptureFixture,
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("PQA_HOME", str(tmp_path))
index_dir = tmp_path / ".pqa" / "indexes"
(index_dir / "answers").mkdir(parents=True)
(index_dir / "nanomaterials").mkdir()
(index_dir / "notes.txt").write_text("not an index\n")

old_argv = sys.argv
try:
sys.argv = ["paperqa", "where"]
with caplog.at_level(logging.INFO, logger="paperqa.agents"):
main()
finally:
sys.argv = old_argv

text = "\n".join(caplog.messages)
assert f"PQA directory: {tmp_path / '.pqa'}" in text
assert f"Index directory: {index_dir}" in text
assert "Indexes:" in text
assert " answers" in text
assert " nanomaterials" in text
assert "notes.txt" not in text


def test_list_built_indexes_skips_files_and_missing_dirs(tmp_path: Path) -> None:
missing = tmp_path / "missing"
assert list_built_indexes(missing) == []

(tmp_path / "alpha").mkdir()
(tmp_path / "zeta").mkdir()
(tmp_path / "readme.txt").write_text("skip\n")
assert list_built_indexes(tmp_path) == ["alpha", "zeta"]


def test_cli_ask(agent_index_dir: Path, stub_data_dir: Path) -> None:
settings = Settings.from_name("debug")
settings.agent.index.index_directory = agent_index_dir
Expand Down