Files
cdsl-cad/cadfs_to_cdsl/operation_registry.py

89 lines
3.0 KiB
Python

"""Source-derived FeatureScript operation coverage inventory.
The registry records what the current source corpus actually contains. It is
deliberately independent from conversion diagnostics: an old output directory
cannot make an operation appear supported, and a planned operation cannot be
reported as observed merely because its name is listed in the roadmap.
"""
from __future__ import annotations
from collections import Counter, defaultdict
from pathlib import Path
from typing import Any, Iterable
from .dataset import Sample
from .featurescript_parser import parse_featurescript
REGISTRY_SCHEMA = "cadfs_to_cdsl.operation_registry.v1"
# These are roadmap work items, not parser aliases or support declarations.
P3_OPERATION_WORK_ITEMS = (
"draft",
"thicken",
"split",
"moveFace",
"deleteFace",
"replaceFace",
"transform",
"derive",
"import",
"bend_add",
)
def build_operation_registry(samples: Iterable[Sample]) -> dict[str, Any]:
"""Parse every available FeatureScript source and inventory feature calls.
Parse failures and missing FeatureScript modalities are recorded separately
instead of being treated as a zero-count result. Sample examples remain
bounded only for report size; the count is computed from every feature.
"""
counts: Counter[str] = Counter()
sample_ids: dict[str, set[str]] = defaultdict(set)
parse_failures: list[dict[str, str]] = []
source_sample_count = 0
for sample in samples:
source_path = sample.files.get("featurescript")
if not source_path:
continue
source_sample_count += 1
try:
model = parse_featurescript(Path(source_path).read_text(encoding="utf-8"), sample.sample_id)
except Exception as error:
parse_failures.append({"sample_id": sample.sample_id, "error": f"{type(error).__name__}: {error}"})
continue
for feature in model.features:
counts[feature.operation] += 1
sample_ids[feature.operation].add(sample.sample_id)
operations: dict[str, dict[str, Any]] = {}
for operation in sorted(counts):
operations[operation] = {
"state": "observed",
"feature_count": counts[operation],
"sample_count": len(sample_ids[operation]),
"sample_ids": sorted(sample_ids[operation]),
}
for operation in P3_OPERATION_WORK_ITEMS:
if operation in operations:
operations[operation]["roadmap_work_item"] = True
else:
operations[operation] = {
"state": "not_observed_in_current_source",
"feature_count": 0,
"sample_count": 0,
"sample_ids": [],
"roadmap_work_item": True,
}
return {
"schema": REGISTRY_SCHEMA,
"source_sample_count": source_sample_count,
"parse_failure_count": len(parse_failures),
"parse_failures": parse_failures,
"operations": operations,
}