Files
orisys-sensor-design/blender/scripts/validate.py
T
2026-09-16 21:04:28 +08:00

83 lines
2.4 KiB
Python

"""Blender headless scene validation (collections and naming).
Usage (from repo root):
blender -b sensors/finger/r01/source/geometry.blend -P blender/scripts/validate.py -- sensors/finger/r01
Note: this script loads design.yaml with PyYAML. Prefer installing PyYAML into
Blender's Python, or run metadata-only checks via: orisys-design validate <revision>
"""
from __future__ import annotations
import sys
from pathlib import Path
import bpy
try:
import yaml
except ImportError:
yaml = None
def _argv_after_double_dash() -> list[str]:
if "--" not in sys.argv:
return []
return sys.argv[sys.argv.index("--") + 1 :]
def _load_design(revision_dir: Path) -> dict:
if yaml is None:
raise RuntimeError(
"PyYAML is not installed in Blender's Python. "
"Run: orisys-design validate <revision> without --blender, "
"or pip install PyYAML into Blender's Python."
)
with (revision_dir / "design.yaml").open(encoding="utf-8") as handle:
data = yaml.safe_load(handle)
if not isinstance(data, dict):
raise ValueError("design.yaml must be a mapping")
return data
def main() -> int:
args = _argv_after_double_dash()
if not args:
print("validate.py: pass revision directory after --", file=sys.stderr)
return 2
revision_dir = Path(args[0]).resolve()
try:
design = _load_design(revision_dir)
except Exception as exc:
print(f"ERROR: {exc}", file=sys.stderr)
return 1
collections = design.get("collections", {})
objects = design.get("objects", {})
errors: list[str] = []
present = {col.name for col in bpy.data.collections}
for key, expected_name in collections.items():
if expected_name not in present:
errors.append(f"Missing collection {expected_name!r} (design key: {key})")
for key, expected_name in objects.items():
obj = bpy.data.objects.get(expected_name)
if obj is None:
errors.append(f"Missing object {expected_name!r} (design key: {key})")
if errors:
for message in errors:
print(f"ERROR: {message}", file=sys.stderr)
print(f"Present collections: {sorted(present)}", file=sys.stderr)
return 1
print(f"OK: Blender scene matches conventions for {revision_dir.name}")
return 0
if __name__ == "__main__":
raise SystemExit(main())