"""Lookup context for per-revision validation.
Builds the ``RevisionValidationContext`` lookup tables from a
:class:`ModeloRevision`, aggregating id sets and by-id mappings used
across every per-section validator.
"""
from __future__ import annotations
from collections.abc import Iterable
from dataclasses import dataclass
from typing import Protocol
from ....core.casilla_id import CasillaId
from .casilla_membership import casillas_by_id, declared_casilla_ids
from .ids import BindingId
from .schema import (
BindingDefinition,
FormulaDefinition,
ModeloRevision,
)
from .schema_deadlines import DeadlineWindowDefinition, ModeloScheduleDefinition
from .schema_exports import ExportLayoutDefinition
from .schema_extraction import ExtractionProfileDefinition
from .schema_formula import ParameterDefinition
from .schema_revision_members import ApplicationLinkDefinition, ConstructDefinition, DependencyClassificationDefinition
from .schema_surfaces import CasillaDefinition
from .schema_verification import LiveCrossReferenceDecision, VerificationExpectationDefinition, WorkbookParityReference
from .validate_revision_identity import collect_record_id_lists
[docs]
class IdentifiedRecord(Protocol):
"""A record carrying a string id, which is all indexing by id requires."""
@property
def id(self) -> str:
"""Return the record's stable identifier."""
...
[docs]
def records_by_id[RecordT: IdentifiedRecord](records: Iterable[RecordT]) -> dict[str, RecordT]:
"""Index identified records by their stable identifiers."""
return {record.id: record for record in records}
ConstructMemberObject = (
CasillaDefinition
| FormulaDefinition
| ParameterDefinition
| BindingDefinition
| ExportLayoutDefinition
| ExtractionProfileDefinition
| LiveCrossReferenceDecision
| WorkbookParityReference
| VerificationExpectationDefinition
| ApplicationLinkDefinition
| DeadlineWindowDefinition
| ModeloScheduleDefinition
| DependencyClassificationDefinition
)
"""Every schema class the development compiler may look up as a construct
member. Every member of this union declares ``legal_refs`` and ``source_refs``
-- the single source of truth for the type that
``dev.registry.compiler.validate_revision_closure`` builds its construct member
objects from, so the two stay in lock-step rather than one drifting to a bare
``object``.
"""
[docs]
def collect_export_field_ids(revision: ModeloRevision) -> set[str]:
"""Collect field identifiers declared by every export layout.
Core types:
:class:`~cadrumo.domain.calculations.registry.schema.ModeloRevision`.
"""
return {field.id for layout in revision.export_layouts for record in layout.records for field in record.fields}
def _exported_casilla_ids(revision: ModeloRevision) -> set[CasillaId]:
return {
field.endpoint_casilla_id
for layout in revision.export_layouts
for record in layout.records
for field in record.fields
if field.endpoint_casilla_id is not None
}
[docs]
@dataclass(frozen=True)
class RevisionValidationContext:
"""Pre-indexed revision data shared by construct validators."""
ids_by_kind: dict[str, list[str]]
export_layout_ids: list[str]
extraction_profile_ids: list[str]
cross_reference_ids: list[str]
workbook_parity_ids: list[str]
verification_expectation_ids: list[str]
application_link_ids: list[str]
deadline_window_ids: list[str]
filing_schedule_ids: list[str]
casilla_by_id: dict[CasillaId, CasillaDefinition]
formula_by_id: dict[str, FormulaDefinition]
binding_by_id: dict[BindingId, BindingDefinition]
parameter_by_id: dict[str, ParameterDefinition]
export_layout_by_id: dict[str, ExportLayoutDefinition]
extraction_profile_by_id: dict[str, ExtractionProfileDefinition]
cross_reference_by_id: dict[str, LiveCrossReferenceDecision]
workbook_parity_by_id: dict[str, WorkbookParityReference]
verification_expectation_by_id: dict[str, VerificationExpectationDefinition]
application_link_by_id: dict[str, ApplicationLinkDefinition]
deadline_window_by_id: dict[str, DeadlineWindowDefinition]
filing_schedule_by_id: dict[str, ModeloScheduleDefinition]
construct_by_id: dict[str, ConstructDefinition]
dependency_classification_by_id: dict[str, DependencyClassificationDefinition]
casillas: set[CasillaId]
formulas: dict[str, FormulaDefinition]
bindings: set[BindingId]
parameters: set[str]
resolvable_values: set[BindingId | CasillaId | str]
exported_casillas: set[CasillaId]
[docs]
def build_revision_validation_context(revision: ModeloRevision) -> RevisionValidationContext:
"""Build lookup indexes needed to validate one modelo revision.
Core types:
:class:`~cadrumo.domain.calculations.registry.schema.ModeloRevision`.
"""
ids_by_kind = collect_record_id_lists(revision)
formula_by_id = records_by_id(revision.formulas)
binding_by_id = records_by_id(revision.bindings)
parameter_by_id = records_by_id(revision.parameters)
casillas = set(declared_casilla_ids(revision))
bindings = set(binding_by_id)
parameters = set(parameter_by_id)
return RevisionValidationContext(
ids_by_kind=ids_by_kind,
export_layout_ids=ids_by_kind["export layout"],
extraction_profile_ids=ids_by_kind["extraction profile"],
cross_reference_ids=ids_by_kind["cross-reference"],
workbook_parity_ids=ids_by_kind["workbook parity reference"],
verification_expectation_ids=ids_by_kind["verification expectation"],
application_link_ids=ids_by_kind["application link"],
deadline_window_ids=ids_by_kind["deadline window"],
filing_schedule_ids=ids_by_kind["filing schedule"],
casilla_by_id=casillas_by_id(revision),
formula_by_id=formula_by_id,
binding_by_id=binding_by_id,
parameter_by_id=parameter_by_id,
export_layout_by_id=records_by_id(revision.export_layouts),
extraction_profile_by_id=records_by_id(revision.extraction_profiles),
cross_reference_by_id=records_by_id(revision.live_cross_references),
workbook_parity_by_id=records_by_id(revision.workbook_parity_refs),
verification_expectation_by_id=records_by_id(revision.verification_expectations),
application_link_by_id=records_by_id(revision.application_links),
deadline_window_by_id=records_by_id(revision.deadline_windows),
filing_schedule_by_id=records_by_id(revision.filing_schedules),
construct_by_id=records_by_id(revision.constructs),
dependency_classification_by_id=records_by_id(revision.dependency_classifications),
casillas=casillas,
formulas=formula_by_id,
bindings=bindings,
parameters=parameters,
resolvable_values=casillas | bindings | parameters,
exported_casillas=_exported_casilla_ids(revision),
)