You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

67 lines
1.9 KiB

"""Simple manifest loader for mindmodel manifests.
Provides `load_manifest(path: str) -> dict` and `ManifestLoadError`.
Behavior:
- If PyYAML is installed, uses yaml.safe_load to parse the file.
- Otherwise falls back to the stdlib json parser.
- If the top-level document is a list it will be normalized to {"constraints": <list>}.
- Raises ManifestLoadError for missing file or parse errors.
"""
from typing import Any, Dict
import json
from pathlib import Path
class ManifestLoadError(Exception):
"""Raised when a manifest cannot be loaded or parsed."""
try:
import yaml # type: ignore
except Exception: # YAML not available
yaml = None # type: ignore
def _parse_with_yaml(text: str) -> Any:
# yamlsafe_load may return any Python structure
try:
return yaml.safe_load(text)
except Exception as exc: # pragma: no cover - defensive
raise ManifestLoadError(f"YAML parse error: {exc}") from exc
def _parse_with_json(text: str) -> Any:
try:
return json.loads(text)
except Exception as exc:
raise ManifestLoadError(f"JSON parse error: {exc}") from exc
def load_manifest(path: str) -> Dict[str, Any]:
"""Load a manifest from the given file path and normalize it to a dict.
If the top-level document is a list, it will be returned as {"constraints": list}.
Raises ManifestLoadError if the file does not exist or if parsing fails.
"""
p = Path(path)
if not p.exists():
raise ManifestLoadError(f"Manifest file not found: {path}")
text = p.read_text(encoding="utf-8")
if yaml is not None:
data = _parse_with_yaml(text)
else:
data = _parse_with_json(text)
# Normalize
if isinstance(data, list):
return {"constraints": data}
if isinstance(data, dict):
return data
# Unexpected top-level type, wrap it
return {"manifest": data}