Source code for mmirage.cli_utils.runtime

"""Runtime/path helpers for the MMIRAGE CLI."""

from __future__ import annotations

import argparse
import logging
import os
from pathlib import Path
from typing import Optional, Sequence

from mmirage.config.config import MMirageConfig

logger = logging.getLogger(__name__)


[docs] def non_empty_path(value: str) -> str: """Reject a path argument given as an empty or blank string. An empty value reads as "flag not passed" further down, which would turn a dry run into a real submission. """ if not value.strip(): raise argparse.ArgumentTypeError("expected a non-empty path") return value
[docs] def expand_path(path: str, project_root: Optional[str] = None) -> str: """Expand environment variables, user home and relative paths.""" expanded = Path(os.path.expandvars(os.path.expanduser(path))) if not expanded.is_absolute() and project_root: expanded = Path(project_root) / expanded return str(expanded.resolve())
[docs] def get_project_root(cfg: MMirageConfig) -> str: """Return the configured project root, or the current working directory.""" project_root = cfg.execution_params.project_root if project_root: return expand_path(project_root) return os.getcwd()
[docs] def create_directories(paths: Sequence[str]) -> None: """Create directories if they do not already exist.""" for path in paths: Path(path).mkdir(parents=True, exist_ok=True)
[docs] def validate_edf_env_path(cfg: MMirageConfig) -> None: """Validate the optional EDF environment file path.""" edf_env = cfg.execution_params.edf_env if not edf_env: return resolved = expand_path(edf_env, get_project_root(cfg)) if not Path(resolved).is_file(): raise FileNotFoundError(f"EDF environment file not found: {resolved}")
[docs] def add_file_logging(log_file: str, level: str) -> None: """Add a file handler so logs are also written to disk.""" resolved_log_file = Path(expand_path(log_file)) try: resolved_log_file.parent.mkdir(parents=True, exist_ok=True) except OSError as exc: logger.warning( "Unable to create log directory for %s: %s", resolved_log_file, exc ) return root_logger = logging.getLogger() for handler in root_logger.handlers: if ( isinstance(handler, logging.FileHandler) and Path(handler.baseFilename).resolve() == resolved_log_file ): return try: file_handler = logging.FileHandler( resolved_log_file, mode="a", encoding="utf-8" ) except OSError as exc: logger.warning("Unable to open log file %s: %s", resolved_log_file, exc) return file_handler.setLevel(getattr(logging, level.upper(), logging.INFO)) file_handler.setFormatter( logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s") ) root_logger.addHandler(file_handler)
[docs] def setup_runtime(cfg: MMirageConfig, log_level: str) -> None: """Initialize runtime-level logging.""" report_dir = Path( expand_path(cfg.execution_params.report_dir, get_project_root(cfg)) ) log_file = report_dir / f"{cfg.execution_params.job_name}.out" add_file_logging(str(log_file), log_level) logger.info("Writing logs to %s", log_file)