aeat.core.decimal._coerce module¶
Canonical Decimal coercion helpers for the AEAT domain.
Consolidates three independent _coerce_decimal copies that previously
lived in _calc_sheets_pull, _row_set_assembly, and
invoices._models. All call-sites use coerce_decimal(),
coerce_decimal_strict(), or normalize_decimal_separators() from this
module rather than open-coding decimal parsing.
Variant analysis¶
_calc_sheets_pull— returnedDecimal | Nonewith no default. Callers checked forNoneexplicitly to detect empty cells._row_set_assembly— took a requireddefault: Decimalkeyword argument and always returnedDecimal. Callers passedDecimal("0").invoices._models— raisedTypeErroron unparseable input (strict pydantic-validator context).
Canonical resolution¶
coerce_decimal() uses coerce_decimal(value, *, default=None) -> Decimal | None.
A single default keyword argument covers all three patterns:
Pass
default=None(or omit it) for the nullable-cell pattern — callers check the return value and skip or handleNonethemselves.Pass
default=Decimal("0")for the aggregation pattern — guaranteedDecimalreturn, noNonecheck needed.Raise on
Nonefor the strict-validator pattern: pass no default and raiseTypeErrorwhen the return isNone— the validator itself turns that into apydantic.ValidationError.
The helper treats int inputs as valid (the _models.py variant did;
the other two would have produced Decimal(str(int)) anyway), allowing
callers that pass mixed int / str / Decimal worksheet values to work
without pre-conversion.
- coerce_decimal(value, *, default=None)[source]¶
Coerce value to a
Decimal, falling back to default.- Parameters:
- Return type:
- Returns:
Parsed decimal, or default when coercion fails.
Examples
>>> from decimal import Decimal >>> coerce_decimal("12.34") Decimal('12.34') >>> coerce_decimal(None) is None True >>> coerce_decimal(None, default=Decimal("0")) Decimal('0') >>> coerce_decimal("bad", default=Decimal("0")) Decimal('0') >>> coerce_decimal(42) Decimal('42')
- coerce_decimal_strict(value)[source]¶
Coerce value to
Decimal, raising on unparseable input.Unlike
coerce_decimal()— which swallows the parse failure and returns a default — this variant lets the underlyingInvalidOperation(orValueError) propagate, so callers that need to record which parse error occurred (e.g. a redaction-safe diagnostic that logstype(exc).__name__) can catch it themselves. The caller is responsible for the empty/Nonecase.- Parameters:
value (
object) – Raw input. AcceptsDecimal,int,float, orstr. Leading/trailing whitespace in a string is stripped by theDecimalconstructor.- Return type:
- Returns:
The parsed decimal.
- Raises:
decimal.InvalidOperation – When the string form is not a valid decimal.
ValueError – When the value cannot be coerced to a decimal.
- normalize_decimal_separators(text, *, strip_thousands)[source]¶
Normalise a European-formatted numeric string to a dot-decimal form.
Maps the decimal comma to a dot so the result is parsable by
Decimal. Whenstrip_thousandsisTruethe thousands dot is removed first (Spanish"1.234,56"->"1234.56"); whenFalseonly the comma is converted ("1234,56"->"1234.56"), for inputs already free of thousands separators.Single canonical home for the comma/dot separator normalisation that the sede, registry-export, renta-web-oracle, and PDF-label parsers previously open-coded inline. Each caller keeps its own surrounding validation, symbol-stripping, locale-detection, and error handling; only the separator transform is shared.