Source code for axiom.paths
"""
core/paths.py
Centralised path management for Axiom AI.
Ensures cross-platform compatibility by using OS-specific standard directories.
"""
import os
import sys
from pathlib import Path
[docs]
def get_app_config_dir() -> Path:
"""Return the standard directory for application configuration files."""
if sys.platform == "win32":
# %APPDATA%\AxiomAI
base = os.environ.get("APPDATA")
if base:
return Path(base) / "AxiomAI"
# Fallback/Linux/macOS: ~/.config/AxiomAI
return Path.home() / ".config" / "AxiomAI"
[docs]
def get_app_cache_dir() -> Path:
"""Return the standard directory for non-essential data (logs, etc)."""
if sys.platform == "win32":
# %LOCALAPPDATA%\AxiomAI
base = os.environ.get("LOCALAPPDATA")
if base:
return Path(base) / "AxiomAI"
# Fallback/Linux/macOS: ~/.cache/AxiomAI
return Path.home() / ".cache" / "AxiomAI"
[docs]
def get_app_data_dir() -> Path:
"""Return the standard directory for user-created content (universes, saves)."""
# For AxiomAI, we keep universes in ~/AxiomAI to make them easy to find/backup for users
return Path.home() / "AxiomAI"
# Shared Constants (machine-global defaults, computed once)
CONFIG_DIR = get_app_config_dir()
CACHE_DIR = get_app_cache_dir()
DATA_DIR = get_app_data_dir()
# Specific Files/Subdirs
SETTINGS_FILE = CONFIG_DIR / "settings.json"
GLOBAL_DB_FILE = CONFIG_DIR / "global.db"
LOG_DIR = CACHE_DIR / "logs"
UNIVERSES_DIR = DATA_DIR / "universes"
SAVES_DIR = DATA_DIR / "saves"
VECTOR_DIR = DATA_DIR / "vector"
# ---------------------------------------------------------------------------
# Path injection (Pilier 1, Étape 5)
#
# Two independent roots can be overridden so the engine is embeddable:
# - data_dir : per-game data (vector store, logs).
# - config_dir : cross-cutting config (settings.json, global.db).
#
# Hybrid policy: if not configured, both fall back to the machine-global
# defaults above — so the GUI app is unchanged and an API key entered once is
# shared across universes. Embedders/tests opt into isolation explicitly, via
# configure(...) or the AXIOM_DATA_DIR / AXIOM_CONFIG_DIR environment variables.
# Resolution is lazy (getters below), never frozen at import.
# ---------------------------------------------------------------------------
_data_root_override: Path | None = None
_config_root_override: Path | None = None
[docs]
def reset() -> None:
"""Clear all injected overrides (back to defaults / env). Used by tests."""
global _data_root_override, _config_root_override
_data_root_override = None
_config_root_override = None
def _data_root() -> Path:
if _data_root_override is not None:
return _data_root_override
env = os.environ.get("AXIOM_DATA_DIR")
return Path(env) if env else DATA_DIR
def _config_root() -> Path:
if _config_root_override is not None:
return _config_root_override
env = os.environ.get("AXIOM_CONFIG_DIR")
return Path(env) if env else CONFIG_DIR
[docs]
def has_config_override() -> bool:
"""True if a config root was injected (via configure or env var)."""
return _config_root_override is not None or bool(os.environ.get("AXIOM_CONFIG_DIR"))
[docs]
def get_vector_dir() -> Path:
"""Vector store root, honouring an injected/env data_dir."""
return _data_root() / "vector"
[docs]
def get_saves_dir() -> Path:
"""Root of the separate saves, honours injected/env data_dir."""
return _data_root() / "saves"
[docs]
def get_assets_dir() -> Path:
"""Root of the generated images (`assets/<save_id>/turn_<n>.png`),
honours injected/env data_dir.
"""
return _data_root() / "assets"
[docs]
def get_log_dir() -> Path:
"""Log directory. Defaults to the machine-global cache root (legacy
location); under an injected/env data_dir, logs move to ``<data_dir>/logs``."""
if _data_root_override is not None or os.environ.get("AXIOM_DATA_DIR"):
return _data_root() / "logs"
return CACHE_DIR
[docs]
def get_config_dir() -> Path:
"""Config directory, honouring an injected/env config_dir."""
return _config_root()
def get_settings_file() -> Path:
return _config_root() / "settings.json"
def get_global_db_file() -> Path:
return _config_root() / "global.db"