Spaces:
Running
Running
Download scripts/ci_validate.py from Samad14/bio-nexus-api: direct link, hf CLI and curl.
- Browser
- Download file 3.46 kB
-
https://huggingface.co/spaces/Samad14/bio-nexus-api/resolve/main/scripts/ci_validate.py
- Command line
-
hf download hf://spaces/Samad14/bio-nexus-api/scripts/ci_validate.py
-
curl -L -o ci_validate.py https://huggingface.co/spaces/Samad14/bio-nexus-api/resolve/main/scripts/ci_validate.py
3.46 kB
| """CI validation for the Benchmark + Engine registries (Component 7). | |
| Runs in GitHub Actions after the deterministic pytest suite. Kept dependency-free | |
| (no supabase client) so it fails fast on structural drift: | |
| - every catalog benchmark carries required registry fields (incl. C6 depth), | |
| - benchmark names are unique across the catalog, | |
| - every benchmark section is a known result section, | |
| - every registered engine describes() a complete contract, | |
| - every engine-declared benchmark reference exists in the catalog. | |
| """ | |
| from __future__ import annotations | |
| import sys | |
| from pathlib import Path | |
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) | |
| from app.engines import ENGINES | |
| from app.services.benchmarks import _RESULT_SECTIONS, load_benchmark_files | |
| REQUIRED_RECORD_FIELDS = ( | |
| "name", "category", "description", "input", "expected_output", | |
| "tolerance", "ground_truth", "citation", "source", "stage", | |
| "difficulty", "version", | |
| ) | |
| DESCRIBE_KEYS = ( | |
| "name", "version", "tool", "tool_version", "databases", "parameters", | |
| "citations", "benchmarks", "export_formats", "figure_formats", | |
| ) | |
| # Pipeline result sections plus standalone tool sections used by the catalog. | |
| KNOWN_SECTIONS = set(_RESULT_SECTIONS) | {"primers", "ngs", "docking", "md", "admet", "stats"} | |
| def check_catalog() -> list[str]: | |
| errors: list[str] = [] | |
| records = load_benchmark_files() | |
| if not records: | |
| return ["catalog is empty"] | |
| names: list[str] = [] | |
| for r in records: | |
| for field in REQUIRED_RECORD_FIELDS: | |
| if field not in r or r.get(field) is None: | |
| errors.append(f"{r.get('name', '<unnamed>')}: missing '{field}'") | |
| if r.get("difficulty") not in {"easy", "medium", "hard"}: | |
| errors.append(f"{r.get('name')}: bad difficulty {r.get('difficulty')!r}") | |
| if isinstance(r.get("version"), int) and r["version"] < 1: | |
| errors.append(f"{r.get('name')}: bad version {r.get('version')}") | |
| if r.get("section") and r["section"] not in KNOWN_SECTIONS: | |
| errors.append(f"{r.get('name')}: unknown section {r.get('section')}") | |
| names.append(r.get("name", "")) | |
| dups = {n for n in names if names.count(n) > 1} | |
| if dups: | |
| errors.append(f"duplicate benchmark names: {sorted(dups)}") | |
| return errors | |
| def check_engines() -> list[str]: | |
| errors: list[str] = [] | |
| if not ENGINES: | |
| return ["engine registry is empty"] | |
| catalog_names = {r["name"] for r in load_benchmark_files()} | |
| for name, engine in ENGINES.items(): | |
| if name != engine.name: | |
| errors.append(f"registry key {name} != engine.name {engine.name}") | |
| desc = engine.describe() | |
| for key in DESCRIBE_KEYS: | |
| if key not in desc: | |
| errors.append(f"{name}: describe() missing '{key}'") | |
| if not engine.export_formats or "json" not in engine.export_formats: | |
| errors.append(f"{name}: json export unsupported") | |
| for bm in engine.benchmarks: | |
| if bm not in catalog_names: | |
| errors.append(f"{name}: benchmark ref '{bm}' not in catalog") | |
| return errors | |
| def main() -> int: | |
| errors = check_catalog() + check_engines() | |
| if errors: | |
| print("VALIDATION FAILED:") | |
| for e in errors: | |
| print(f" - {e}") | |
| return 1 | |
| print("VALIDATION OK: catalog + engine registries consistent") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) |