Coverage for orchestrant/paths.py: 93%
41 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-19 11:22 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-19 11:22 +0000
1"""Where an installed OrchestrANT finds its data and writes its logs."""
3from __future__ import annotations
5import os
6import sys
7from pathlib import Path
10MODEL_NAME = "deim_dfine_n_coco.onnx"
11# A checkout has no model until this runs; the packages carry theirs.
12FETCH_COMMAND = "python scripts/fetch_models.py"
15def bundle_data_dir() -> Path | None:
16 """The data directory of a packaged install; None in a checkout or a plain venv."""
17 env = os.getenv("ORCHESTRANT_DATA_DIR")
18 if env:
19 return Path(env)
20 # A bundle keeps the interpreter in <root>/runtime and its data in <root>/share/orchestrant.
21 candidate = Path(sys.prefix).parent / "share" / "orchestrant"
22 return candidate if candidate.is_dir() else None
25def model_search_paths(name: str = MODEL_NAME) -> list[Path]:
26 """The places the default model is looked for, in order."""
27 paths: list[Path] = []
28 env = os.getenv("ORCHESTRANT_MODEL")
29 if env:
30 paths.append(Path(env))
31 data = bundle_data_dir()
32 if data is not None:
33 paths.append(data / "models" / name)
34 paths.append(Path("resources") / "models" / name)
35 # An editable install started from outside its checkout.
36 paths.append(Path(__file__).resolve().parents[1] / "resources" / "models" / name)
37 return paths
40def default_model_path(name: str = MODEL_NAME) -> Path:
41 """The first default model that exists, else the first candidate, so an error names it."""
42 paths = model_search_paths(name)
43 return next((path for path in paths if path.is_file()), paths[0])
46def missing_model_message(model: Path | str) -> str:
47 """The error for a model that is not there, naming how to fetch the default one."""
48 return f"model not found: {model}; fetch the default one with: {FETCH_COMMAND}"
51def default_log_dir() -> Path:
52 """A packaged install logs to the user's state dir, because its install dir may be read-only."""
53 env = os.getenv("ORCHESTRANT_LOG_DIR")
54 if env:
55 return Path(env)
56 if bundle_data_dir() is None:
57 return Path("logs")
58 if sys.platform == "win32":
59 local = os.getenv("LOCALAPPDATA")
60 base = Path(local) if local else Path.home() / "AppData" / "Local"
61 return base / "OrchestrANT" / "logs"
62 state = os.getenv("XDG_STATE_HOME")
63 base = Path(state) if state else Path.home() / ".local" / "state"
64 return base / "orchestrant" / "logs"