Source code for openalex_local._core.config

#!/usr/bin/env python3
# Timestamp: 2026-01-29
"""Configuration for openalex_local."""

import os as _os
from pathlib import Path as _Path
from typing import Optional as _Optional

# Default database locations (checked in order). Anchored on multiple
# roots so the DB is found regardless of which directory the caller
# (pytest, CLI, MCP server) is invoked from. Hardcoded user-specific
# paths (e.g. `/mnt/nas_ug/...`) were removed in favour of generic
# repo-anchored / CWD-relative / home-cache locations — set
# `OPENALEX_LOCAL_DB` explicitly when the DB lives somewhere else.
DEFAULT_DB_PATHS = [
    # CWD-relative — works when the user runs commands from the repo root.
    _Path.cwd() / "data" / "openalex.db",
    # Repo-relative — works regardless of CWD (e.g. when scitex-dev
    # invokes openalex-local from `~/proj/scitex-dev/`). Anchored on
    # this source file: <repo>/src/openalex_local/_core/config.py.
    _Path(__file__).resolve().parents[3] / "data" / "openalex.db",
    # Canonical scitex runtime location.
    _Path.home() / ".scitex" / "openalex-local" / "runtime" / "openalex.db",
    # Legacy user-state cache directory (back-compat, will be removed).
    _Path.home() / ".openalex_local" / "openalex.db",
]


def get_db_path() -> _Path:
    """Get database path from environment or auto-detect."""
    env_path = _os.environ.get("OPENALEX_LOCAL_DB")
    if env_path:
        path = _Path(env_path)
        if path.exists():
            return path
        raise FileNotFoundError(f"OPENALEX_LOCAL_DB path not found: {env_path}")

    for path in DEFAULT_DB_PATHS:
        if path.exists():
            return path

    raise FileNotFoundError(
        "OpenAlex database not found. Set OPENALEX_LOCAL_DB environment variable."
    )


DEFAULT_PORT = 31292
DEFAULT_HOST = "0.0.0.0"


[docs] class Config: """Configuration container.""" _db_path: _Optional[_Path] = None _api_url: _Optional[str] = None _mode: str = "auto" # "auto", "db", or "http"
[docs] @classmethod def get_db_path(cls) -> _Path: if cls._db_path is None: cls._db_path = get_db_path() return cls._db_path
[docs] @classmethod def set_db_path(cls, path: str) -> None: p = _Path(path) if not p.exists(): raise FileNotFoundError(f"Database not found: {path}") cls._db_path = p cls._mode = "db"
[docs] @classmethod def get_api_url(cls) -> str: if cls._api_url: return cls._api_url return _os.environ.get( "OPENALEX_LOCAL_API_URL", f"http://localhost:{DEFAULT_PORT}" )
[docs] @classmethod def set_api_url(cls, url: str) -> None: cls._api_url = url.rstrip("/") cls._mode = "http"
[docs] @classmethod def set_mode(cls, mode: str) -> None: """Set mode explicitly: 'db', 'http', or 'auto'.""" if mode not in ("auto", "db", "http"): raise ValueError(f"Invalid mode: {mode}. Use 'auto', 'db', or 'http'") cls._mode = mode
[docs] @classmethod def get_mode(cls) -> str: """ Get current mode. Returns: "db" if using direct database access "http" if using HTTP API """ if cls._mode == "auto": # Check environment variable for explicit mode env_mode = _os.environ.get("OPENALEX_LOCAL_MODE", "").lower() if env_mode in ("http", "remote", "api"): return "http" if env_mode in ("db", "local"): return "db" # Check if API URL is set explicitly if cls._api_url or _os.environ.get("OPENALEX_LOCAL_API_URL"): return "http" # Check if local database exists try: get_db_path() return "db" except FileNotFoundError: # No local DB, try http return "http" return cls._mode
[docs] @classmethod def reset(cls) -> None: cls._db_path = None cls._api_url = None cls._mode = "auto"
# EOF