#!/usr/bin/env python3 """Index native Python API names from passing P6 runtime evidence.""" from __future__ import annotations import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] P6 = ROOT / "docs/p6" OUT = P6 / "python-api-runtime-evidence.json" def names(value): if isinstance(value, str): return [item.strip() for item in value.replace("\n", ",").split(",") if item.strip()] if isinstance(value, list): return [str(item).strip() for item in value if str(item).strip()] if isinstance(value, dict): result = [] for item in value.values(): result.extend(names(item)) return result return [] evidence = {} for path in sorted(P6.glob("*.json")): try: report = json.loads(path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError): continue result_value = report.get("result", report.get("status")) if not isinstance(result_value, str) or result_value not in {"pass", "passed", "completed"}: continue action = report.get("action") explicit_python = action == "python-api" or "python" in path.stem.lower() if not explicit_python: continue module = report.get("module") if not isinstance(module, str) or not module: stem = path.stem.lower() inferred = [("openscad", "OpenSCAD"), ("meshpart", "MeshPart"), ("points", "Points"), ("sketcher", "Sketcher"), ("techdraw", "TechDraw"), ("robot", "Robot"), ("measure", "Measure"), ("surface", "Surface"), ("spreadsheet", "Spreadsheet"), ("inspection", "Inspection"), ("sandbox", "Sandbox")] module = next((value for token, value in inferred if token in stem), None) if not isinstance(module, str) or not module: continue found = [] def walk(value, key=""): if isinstance(value, dict): for child_key, child in value.items(): if child_key.lower() in {"apinames", "pythonapi", "pythonapinames", "api_names"}: found.extend(names(child)) walk(child, child_key) elif isinstance(value, list): for child in value: walk(child, key) walk(report) for name in found: normalized = name.strip() if normalized: key = f"{module}:{normalized}" evidence.setdefault(key, []).append(str(path.relative_to(ROOT))) report = { "schema": "freecad-web-python-api-runtime-evidence/v1", "policy": "only passing python-api-named runtime artifacts are indexed; source-only inventory is excluded", "names": [{"module": key.split(":", 1)[0], "name": key.split(":", 1)[1], "artifacts": sorted(set(paths))} for key, paths in sorted(evidence.items())], "count": len(evidence), } OUT.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") print(json.dumps({"output": str(OUT.relative_to(ROOT)), "names": len(evidence)}, ensure_ascii=False))