Source code for nomad_pydantic.config
from __future__ import annotations
from pathlib import Path
from typing import Any
from hydra import compose, initialize_config_dir
from omegaconf import OmegaConf
from pydantic import BaseModel, ConfigDict, Field, model_validator
from nomad_pydantic.client import CommandResult, JobStatus, NomadClient
from nomad_pydantic.models import Job
[docs]
class NomadConfiguration(BaseModel):
"""A Nomad job together with its local JSON artifact and CLI settings."""
model_config = ConfigDict(validate_assignment=True)
job: Job
path: Path | None = None
working_dir: Path | None = None
command_timeout: float | None = Field(default=60, gt=0)
@model_validator(mode="after")
def default_paths(self) -> NomadConfiguration:
if self.working_dir is None:
self.working_dir = Path.cwd() / ".nomad-pydantic" / self.job.id
if self.path is None:
self.path = self.working_dir / f"{self.job.id}.json"
return self
[docs]
def to_cfg(self) -> str:
return self.job.to_json()
[docs]
def write(self, path: str | Path | None = None) -> Path:
destination = Path(path) if path is not None else self.path
if destination is None: # pragma: no cover - guarded by model validation
raise ValueError("configuration path is not set")
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(self.to_cfg() + "\n")
self.path = destination
return destination
[docs]
@classmethod
def from_file(cls, path: str | Path, **values: Any) -> NomadConfiguration:
source = Path(path)
return cls(job=Job.from_json(source.read_text()), path=source, **values)
[docs]
@classmethod
def load(
cls,
config_dir: str | Path,
config_name: str,
*,
overrides: list[str] | None = None,
**values: Any,
) -> NomadConfiguration:
"""Compose a Hydra YAML configuration and validate it."""
with initialize_config_dir(config_dir=str(Path(config_dir).resolve()), version_base=None):
composed = compose(config_name=config_name, overrides=overrides or [])
data = OmegaConf.to_container(composed, resolve=True)
if not isinstance(data, dict):
raise ValueError("Nomad configuration must be a mapping")
return cls.model_validate({**data, **values})
[docs]
def client(self, **values: Any) -> NomadClient:
return NomadClient(self, **values)
[docs]
def register(self, **values: Any) -> CommandResult:
return self.client(**values).register()
[docs]
def status(self, **values: Any) -> JobStatus:
return self.client(**values).status()
[docs]
def start(self, **values: Any) -> CommandResult:
return self.client(**values).start()
[docs]
def restart(self, **values: Any) -> CommandResult:
return self.client(**values).restart()
[docs]
def force_periodic(self, **values: Any) -> CommandResult:
return self.client(**values).force_periodic()
[docs]
def stop(self, *, purge: bool = False, **values: Any) -> CommandResult:
return self.client(**values).stop(purge=purge)