Skip to content

fix: raise NumberFormatError for invalid string in NumberPattern.apply - #1411

Open
2025sl93041-gkb wants to merge 1 commit into
python-babel:masterfrom
2025sl93041-gkb:fix/numberformaterror-invalid-decimal
Open

2025sl93041-gkb wants to merge 1 commit into
python-babel:masterfrom
2025sl93041-gkb:fix/numberformaterror-invalid-decimal

Conversation

@2025sl93041-gkb

Copy link
Copy Markdown

Summary

Closes #702.

When any formatting function (format_decimal, format_currency,
format_percent, format_compact_decimal, etc.) received an invalid
string value (e.g. "not_a_number"), the internal
decimal.Decimal(str(value)) call would raise a raw
decimal.InvalidOperation — a third-party implementation detail from the
decimal standard library module — rather than Babel's own
NumberFormatError.

This is a leaky abstraction: callers who want to catch bad-value errors
need to import and handle decimal.InvalidOperation in addition to (or
instead of) NumberFormatError.

Root cause

NumberPattern.apply() (and the internal _get_compact_format()
helper) both do:

if not isinstance(value, decimal.Decimal):
    value = decimal.Decimal(str(value))

decimal.Decimal raises decimal.InvalidOperation for strings it
cannot parse. No surrounding try/except was present.

Fix

Wrap the conversion in a try/except block and re-raise as
NumberFormatError:

if not isinstance(value, decimal.Decimal):
    try:
        value = decimal.Decimal(str(value))
    except decimal.InvalidOperation as e:
        raise NumberFormatError(f"{value!r} is not a valid number") from e

Both NumberPattern.apply() and _get_compact_format() are fixed.

Test

Added test_number_pattern_apply_invalid_string_raises_number_format_error
in tests/test_numbers.py. The test calls NumberPattern.apply()
directly (via parse_pattern('0.###')) with a mock locale so it works
without requiring the full CLDR data build.

Wrap `decimal.Decimal(str(value))` in `NumberPattern.apply()` and
`_get_compact_format()` in a try/except to catch
`decimal.InvalidOperation` and re-raise as `NumberFormatError`.

Previously, passing an invalid string like `"not_a_number"` to any
formatting function (format_decimal, format_currency, format_percent,
format_compact_decimal) would propagate a raw
`decimal.InvalidOperation` exception. The public API contract
documents `NumberFormatError` as the error type for bad input; all
other invalid-value paths already raise it.

Closes python-babel#702

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inconsistent exceptions

1 participant