Source code for pyccapt.control.core.read_files

"""File-loading helpers for the control package."""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

try:
    import tomllib
except ModuleNotFoundError:  # pragma: no cover - fallback for older Python
    import tomli as tomllib  # type: ignore[no-redef]


_DEVICE_TOGGLE_KEYS = {
    "tdc",
    "camera",
    "pump_ll",
    "pump_cll",
    "gates",
    "v_dc",
    "v_p",
    "signal_generator",
    "cryo",
    "gauges",
    "stage",
    "laser",
    "DAQ",
    "usb_lamp_switch",
    "thorlab_motor",
    "baking",
}

_ENABLED_VALUES = {"on", "enabled", "enable", "true", "yes", "1"}
_DISABLED_VALUES = {"off", "disabled", "disable", "false", "no", "0"}


[docs] def normalize_control_config(config: dict[str, Any]) -> dict[str, Any]: """Normalize supported control config toggle aliases to legacy values.""" normalized = dict(config) for key in _DEVICE_TOGGLE_KEYS: value = normalized.get(key) if isinstance(value, bool): normalized[key] = "on" if value else "off" continue if value is None: continue lowered = str(value).strip().lower() if lowered in _ENABLED_VALUES: normalized[key] = "on" elif lowered in _DISABLED_VALUES: normalized[key] = "off" return normalized
[docs] def read_json_file(json_file_path: str | Path) -> dict[str, Any]: """Read a JSON file and return its content as a dictionary. Args: json_file_path: Absolute or relative path to the JSON file. Returns: Parsed JSON content. Raises: FileNotFoundError: If the file does not exist. ValueError: If the file does not contain a JSON object. json.JSONDecodeError: If the file content is invalid JSON. """ path = Path(json_file_path).expanduser().resolve() if not path.exists(): raise FileNotFoundError(f"JSON file not found: {path}") with path.open("r", encoding="utf-8") as file_handle: data = json.load(file_handle) if not isinstance(data, dict): raise ValueError(f"Expected a JSON object in {path}, got {type(data).__name__}.") return data
[docs] def read_toml_file(toml_file_path: str | Path) -> dict[str, Any]: """Read a TOML file and return its content as a dictionary. Args: toml_file_path: Absolute or relative path to the TOML file. Returns: Parsed TOML content. Raises: FileNotFoundError: If the file does not exist. ValueError: If the file does not contain a TOML object. tomllib.TOMLDecodeError: If the file content is invalid TOML. """ path = Path(toml_file_path).expanduser().resolve() if not path.exists(): raise FileNotFoundError(f"TOML file not found: {path}") with path.open("rb") as file_handle: data = tomllib.load(file_handle) if not isinstance(data, dict): raise ValueError(f"Expected a TOML object in {path}, got {type(data).__name__}.") return data
[docs] def load_config_file(config_file_path: str | Path) -> dict[str, Any]: """Load a control configuration file from `.toml`. Args: config_file_path: Absolute or relative path to the config file. Returns: Parsed config dictionary. Raises: ValueError: If file extension is unsupported. """ path = Path(config_file_path).expanduser().resolve() suffix = path.suffix.lower() if suffix == ".toml": return normalize_control_config(read_toml_file(path)) if suffix == ".json": raise ValueError(f"JSON config is no longer supported for control runtime: {path}. Please migrate to config.toml.") raise ValueError(f"Unsupported config format for {path}. Use a .toml configuration file.")