Source code for nexgen.command_line.cli_config

from pathlib import Path
from typing import Literal

import yaml
from pydantic import BaseModel, field_validator  # , ValidationError

from ..nxs_utils import Attenuator, Axis, Beam, DetectorType, Sample, Source
from ..nxs_utils.detector import (
    CetaDetector,
    EigerDetector,
    JungfrauDetector,
    SinglaDetector,
    TristanDetector,
)
from ..utils import coerce_to_path

JSON_EXT = ".json"
YAML_EXT = ".yaml"


[docs] class GonioConfig(BaseModel): axes: list[Axis] scan_axis: str | None = None # only really needed for events scan_type: Literal["rotation", "grid"] = "rotation" snaked_scan: bool = False
[docs] class InstrumentConfig(BaseModel): source: Source beam: Beam attenuator: Attenuator
[docs] class ModuleConfig(BaseModel): fast_axis: list[float] | tuple[float, float, float] slow_axis: list[float] | tuple[float, float, float]
[docs] class DetectorConfig(BaseModel): axes: list[Axis] params: DetectorType beam_center: list[float] | tuple[float, float] exposure_time: float module: ModuleConfig mode: Literal["images", "events"] = "images" @field_validator("params", mode="before") @classmethod def _parse_params(cls, params: dict | DetectorType): if isinstance(params, DetectorType): return params else: if "eiger" in params["description"].lower(): return EigerDetector(**params) elif "tristan" in params["description"].lower(): return TristanDetector(**params) elif "jungfrau" in params["description"].lower(): return JungfrauDetector(**params) elif "singla" in params["description"].lower(): return SinglaDetector(**params) elif "ceta" in params["description"].lower(): return CetaDetector(**params) else: raise ValueError("Unknown detector type")
[docs] class CoordSystemConfig(BaseModel): convention: str = "mcstas" origin: list[float] | tuple[float, float, float] | None = None vectors: list[tuple[float, float, float]] | None = None
[docs] class CliConfig(BaseModel): """General configuration model for command line tools.""" gonio: GonioConfig instrument: InstrumentConfig det: DetectorConfig sample: Sample | None = None coord_system: CoordSystemConfig | None = None
[docs] @classmethod def from_file(cls, filename: str | Path): config_file = coerce_to_path(filename) if config_file.suffix == JSON_EXT: _raw_params = config_file.read_text() config = cls.model_validate_json(_raw_params) elif config_file.suffix == YAML_EXT: with open(config_file) as fh: _raw_params = yaml.load(fh, yaml.Loader) config = cls(**_raw_params) else: raise IOError("Please pass a valid json or yaml file.") return config