Source code for aeat.domain.calculations.registry._validate_cross_revision_advisory
"""Advisory cross-revision drift summaries for non-overlapping revisions."""from__future__importannotationsfromcollectionsimportdefaultdictfromcollections.abcimportIterablefromdataclassesimportdataclassfrom._cross_revision_divergenceimport(CrossRevisionCasillaDivergence,_iter_cross_revision_casilla_divergences,)from._errorsimportRegistryValidationErrorfrom._idsimportCasillaIdfrom._schemaimportModeloDefinition__all__=("CrossRevisionCasillaDriftSummary","summarize_non_overlapping_cross_revision_casilla_drift",)
[docs]@dataclass(frozen=True,slots=True)classCrossRevisionCasillaDriftSummary:"""Grouped advisory drift inventory for non-overlapping revisions."""modelo_id:strleft_revision_id:strright_revision_id:strfield:strdrift_count:intexample_casilla_ids:tuple[CasillaId,...]continuidad_ids:tuple[str,...]=()evolution_kinds:tuple[str,...]=()covered_by_evolution_count:int=0uncovered_count:int=0
[docs]defsummarize_non_overlapping_cross_revision_casilla_drift(modelos:Iterable[ModeloDefinition],*,example_limit:int=5,)->tuple[CrossRevisionCasillaDriftSummary,...]:"""Return advisory drift summaries for repeated ids in non-overlapping revisions. The snapshot-build validator raises on overlapping revision windows because those revisions can apply to the same filing period. Annual non-overlapping forms, such as M100, can legally evolve or repurpose repeated numeric ids; this inventory keeps that drift visible without turning it into a load-time error before the schema has an explicit continuity/evolution contract. Args: modelos: Iterable of :class:`ModeloDefinition` instances to inspect for cross-revision casilla drift. example_limit: Maximum number of example casilla ids to include in each summary record. Returns: Tuple of :class:`CrossRevisionCasillaDriftSummary` records, one per drifted casilla id. """ifexample_limit<1:raiseRegistryValidationError("example_limit must be at least 1")grouped:dict[tuple[str,str,str,str],list[CrossRevisionCasillaDivergence]]=defaultdict(list)fordivergencein_iter_cross_revision_casilla_divergences(modelos):ifdivergence.revisions_overlap:continuekey=(divergence.modelo_id,divergence.left_revision_id,divergence.right_revision_id,divergence.field,)grouped[key].append(divergence)summaries:list[CrossRevisionCasillaDriftSummary]=[]for(modelo_id,left_revision_id,right_revision_id,field),divergencesinsorted(grouped.items()):casilla_ids=[divergence.casilla_idfordivergenceindivergences]examples=tuple(dict.fromkeys(casilla_ids[:example_limit]))continuidad_ids=tuple(sorted({continuidad_idfordivergenceindivergencesforcontinuidad_idin(divergence.left_continuidad_id,divergence.right_continuidad_id)ifcontinuidad_idisnotNone},),)evolution_kinds=tuple(sorted({divergence.evolution_kindfordivergenceindivergencesifdivergence.evolution_kindisnotNone}),)covered_by_evolution_count=sum(1fordivergenceindivergencesifdivergence.evolution_covers_field)summaries.append(CrossRevisionCasillaDriftSummary(modelo_id=modelo_id,left_revision_id=left_revision_id,right_revision_id=right_revision_id,field=field,drift_count=len(casilla_ids),example_casilla_ids=examples,continuidad_ids=continuidad_ids,evolution_kinds=evolution_kinds,covered_by_evolution_count=covered_by_evolution_count,uncovered_count=len(divergences)-covered_by_evolution_count,),)returntuple(summaries)