cadrumo.domain.calculations.registry.binding_selector_utils module¶
Shared selector normalization and field-validator helpers for registry bindings.
- class BindingFixedExportSelector(**data)[source]¶
Bases:
BaseModelTyped fixed-width export projection carried by a binding selector.
- Parameters:
data (Any)
- record: str¶
- offset: OneBasedExportOffset¶
- length: int¶
- data_type: BindingExportDataType¶
- decimals: int | None¶
- field: str | None¶
- signed: bool¶
Whether the wire slot carries AEAT’s sign marker in its first position.
AEAT types a numeric design row
N(numérico CON signo) orNum(sin signo), and anNrow reserves position 1 for the marker:Nfor a negative value, a space otherwise. The two renderings differ for EVERY value, not only negatives – a 17-byte signed slot emits a space plus 16 magnitude digits where an unsigned one emits 17 digits – so a binding projecting into anNrow must declare this or the slot is malformed on the wire and refuses outright on a negative.
- class BindingRowExportSelector(**data)[source]¶
Bases:
BaseModelTyped row-field export projection carried by a binding selector.
data_typecarries the same fact here as onBindingFixedExportSelector: the scalar type of the value this binding contributes to the export. The two projections differ only in how the value is POSITIONED – a fixed projection names an absoluteoffset/length, a row projection takes its position from the repeated record’s row layout – so the type belongs on both and means one thing.Optional because the declaration is being adopted per family; absent leaves the consumer on whatever it used before.
- Parameters:
data (Any)
- record: str¶
- row_field: str¶
- data_type: BindingExportDataType | None¶
- class BindingRowSetSelector(**data)[source]¶
Bases:
BaseModelTyped row-set projection carried by a row-producing binding selector.
- Parameters:
data (Any)
- fact: Literal['row_field']¶
- row_field: str¶
- grouping: str¶
- record: str | None¶
- selector_as_dict(binding)[source]¶
Return the provider’s authored field mapping without its own discriminator.
The provider’s top-level
kindis excluded because it is the union tag, not a selector field: the per-family models this mapping is re-validated against accept it as a defaulted literal, and a family helper that reasoned over the tag as data would be reading the discriminator twice.A nested union member’s tag is restored instead of dropped, because that mapping has no other way to say which member it is; see
_restore_nested_discriminators().- Return type:
- Parameters:
binding (BindingDefinition)
- class BooleanBindingEncodedValue(**data)[source]¶
Bases:
BaseModelOne accepted decimal encoding of a boolean-casilla
manual_inputbinding.A
manual_inputbinding whose selector declaresdata_type = "boolean"(the Modelo 100 estimación-directa modality flag is the canonical case) is consumed by the registry formulas as a numeric1/0operand. The operator therefore supplies a decimal on the--bindingchannel, yet the accepted values and their meaning are opaque from the rawBindingDefinition. This record makes one accepted value explicit:encoded_valueis the decimal the operator types,boolean_meaningis the affirmative/negative sense it carries, andregistry_valueis the underlying casilla token the boolean maps to (the selector’s declaredtrue_value/false_value).- Parameters:
data (Any)
- encoded_value: str¶
- boolean_meaning: bool¶
- registry_value: str¶
- boolean_binding_encoded_values(binding)[source]¶
Return the decimal encoding of a boolean-casilla
manual_inputbinding.The result is empty for every binding that is not a boolean-casilla
manual_inputselector, so a caller can read a non-empty result as “this binding is a decimal-encoded boolean flag”. The encoding follows the registry convention that a boolean operand is consumed as1(true) /0(false); each sense is paired with the selector’s declaredtrue_value/false_valuecasilla token, so the mapping is derived from the binding definition, never hardcoded per modelo.- Return type:
- Returns:
Zero or two
BooleanBindingEncodedValuerows.- Raises:
RegistryValidationError – When
bindingis amanual_inputbinding whose selector does not validate againstManualInputProvider– a malformed selector must be a named failure, not a silently empty “not a boolean binding” result.- Parameters:
binding (BindingDefinition)
- class ManualInputRecordFieldSelector(**data)[source]¶
Bases:
BaseModelThe record-field shape of a validated
manual_inputbinding selector.ManualInputProvidermodels both the casilla shape and the record-field shape on one class because the two are mutually exclusive and sharedata_type; this narrower model is what a caller that only cares about the record-field shape (a fichero-BOE fixed-record projection) actually wants, withrecord/field/offset/lengthas the non-optional fields the source model’s own validator already guarantees oncerecordis notNone.- Parameters:
data (Any)
- record: str¶
- field: str¶
- offset: int¶
- length: int¶
- decimals: int | None¶
- manual_input_record_field_selector(binding)[source]¶
Return the record-field selector of a
manual_inputbinding, orNone.Nonecovers two DIFFERENT, both legitimate, cases a caller does not need to distinguish:bindingis not amanual_inputbinding at all, or it is amanual_inputbinding using the CASILLA shape (the operator types a value straight into a registry casilla, with no record/field position at all) rather than the record-field shape this accessor projects. Neither is a defect; a caller collecting record-field projections across a revision’s bindings is meant to skip both.- Return type:
- Returns:
The typed
ManualInputRecordFieldSelector, orNonewhenbindingdoes not declare a record-fieldmanual_inputselector.- Raises:
RegistryValidationError – When
bindingis amanual_inputbinding whose selector does not validate againstManualInputProvider– a malformed selector must be a named failure, not silently read as “not a record-field binding”.- Parameters:
binding (BindingDefinition)
- binding_export_selector(binding, *, revision)[source]¶
Return the typed export projection embedded in
binding.provider.Binding source-family selectors remain authoritative for business facts. Export record resolution only needs the official record-coordinate projection; this helper parses that projection once into a typed fixed-field or row-field selector instead of letting callers probe the raw selector map.
A binding is only export-eligible when its OWN revision declares at least one export layout; several unrelated source families (invoice, previous_filing) reuse the field name
recordfor their own, different concepts, so calling this on a binding belonging to a layout-less revision would misread a foreign field as an incomplete export claim. Every current caller already checksrevision.export_layoutsbefore calling; this is the same precondition enforced here too, so a future caller that forgets it fails with a named cause instead of a misattributed completeness error.- Raises:
RegistryValidationError – When
revisiondeclares no export layouts at all, or when the export projectionbindingdeclares is malformed or incomplete.- Parameters:
binding (BindingDefinition)
revision (ModeloRevision)
- Return type:
BindingFixedExportSelector | BindingRowExportSelector | None
Core types:
ModeloRevision.- Return type:
BindingFixedExportSelector|BindingRowExportSelector|None- Parameters:
binding (BindingDefinition)
revision (ModeloRevision)
- binding_row_set_selector(binding)[source]¶
Return the typed row-set projection embedded in
binding.provider.Source-family selectors remain the authority for fact-specific filters. Row-set consumers only need the common
fact = "row_field"projection that names the detail grouping and the emitted row field, so callers parse that projection once instead of probing the raw selector map.Only a
BindingAggregationOp.ROWSbinding is row-set-eligible; several unrelated source families (invoice, previous_filing) reuse the field namesrecord/grouping/factfor their own, different concepts, so calling this on a non-ROWSbinding would misread a foreign field as an incomplete row-set claim. Every current caller already checks the aggregation op before calling; this is the same precondition enforced here too, so a future caller that forgets it fails with a named cause instead of a misattributed completeness error.- Return type:
- Returns:
The parsed
BindingRowSetSelector, orNonewhen the binding selector does not declare a row-set projection.- Raises:
RegistryValidationError – When
bindingis not row-set-eligible (its resolved aggregation op is notrows), or when the row-set projection it declares is malformed or incomplete.- Parameters:
binding (BindingDefinition)
- provider_member(binding, provider_model)[source]¶
Return
binding.providernarrowed to the member its kind is registered for.The discriminated union already constructed the member from the authored row, so this is a narrowing rather than a re-validation: there is no authored input that reaches here holding a different class. A mismatch can therefore only mean the registration table and the union have drifted apart, which is refused loudly instead of being silently revalidated or skipped.
- Raises:
RegistryValidationError – The constructed member is not an instance of the model its kind is registered for.
- Return type:
TypeVar(ProviderT, bound=BaseModel)- Parameters:
binding (BindingDefinition)
provider_model (type[ProviderT])
- selector_against_model(binding, selector_model)[source]¶
Validate
binding.provideragainstselector_model, accumulating diagnostics.Projects the selector through
selector_as_dict()(the same normalised mapping the resolve-time helpers see, so the build gate is never stricter than runtime), validates against the strict pydantic model, and returns the underlying field message verbatim in a diagnostic naming the binding id, its source, and the violated model. The underlying pydantic error is preserved rather than flattened to a generic “malformed selector”, matching the shape the counterpart/withholding build-time lift already emits.Returns an empty list when the selector validates.
- Return type:
- Parameters:
binding (BindingDefinition)
selector_model (type[BaseModel])
- canonical_selector_key_hint(selector, selector_model)[source]¶
Return a canonical-key correction for a known legacy selector spelling.
- invariant_diagnostics(binding, label, check)[source]¶
Run a raise-style op/fact invariant
checkand collect its diagnostic.The detail-record, previous-filing, counterpart, withholding, invoice, and ledger families enforce their op/fact cross-invariants by raising
RegistryValidationError. This adapter runs the raisingcheckand converts the raised message into one accumulating diagnostic string naming the binding id, its source, and thelabelfamily, preserving the underlying field message. Returns an empty list when the invariant holds.- Return type:
- Parameters:
binding (BindingDefinition)
label (str)
check (Callable[[BindingDefinition], object])
- uppercase_alpha_code(field_label)[source]¶
Build a field validator that rejects a non-uppercase-alphabetic code.
Shared by the binding observation models whose ISO country / member-state / currency codes must be uppercase alphabetic;
field_labelnames the field in the raisedRegistryValidationError.
- optional_uppercase_alpha_code(field_label)[source]¶
Build the nullable counterpart of
uppercase_alpha_code().Delegates to that validator for anything present, so what “uppercase alphabetic” MEANS keeps one home and this adds only the nullability axis. A separate builder rather than a flag on the shared one, because most of the fields it guards are genuinely required and loosening it for them would make an absent code representable where nothing should represent one.
- M347_OPERATION_CLAVES: frozenset[str]¶
Modelo 347’s OWN clave de operacion vocabulary (RD 1065/2007 arts. 31/33, RD 1619/2012 disposicion adicional cuarta), disjoint from M349’s intracommunity clave set above – the letter A means a different thing in each. Confirmed against every bundled M347 diseno de registro (2008-2009, 2010, 2011, 2025-y-siguientes): none declares an “H” or “I” clave.
- intracommunity_clave_validator()[source]¶
Build the shared
intracommunity_clavefield validator.An invoice observation’s clave is optional, must be uppercase, and must be one of the closed AEAT clave de operación set.
- operation_clave_validator(*, field_label, claves)[source]¶
Build an optional, uppercase, closed-set clave-de-operacion field validator.
Generalises
intracommunity_clave_validator()to any closed clave vocabulary – a modelo’s clave letters mean nothing outside their own modelo’s set, so the closed set is a parameter, never a hand-listed literal at the call site.
- validate_rectification_fields(observation)[source]¶
Enforce the rectification-field coupling shared by the invoice families.
A rectification observation must declare
rectified_year,rectified_periodandrectified_base_previous; a non-rectification observation must declare none of them. The shared check raisesRegistryValidationErroron a violation.- Return type:
- Parameters:
observation (_RectifiableObservation)
- unique_tuple(label)[source]¶
Build a field validator that rejects duplicate entries in a tuple field.
Shared by the binding requirement models;
labelnames the offending tuple in the raisedRegistryValidationError("<label> entries must be unique").