diff options
author | Jonah Lawrence <jonah@freshidea.com> | 2023-01-25 11:17:24 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-25 20:17:24 +0200 |
commit | 79bcdf2640b400a56577d93e7fde026290c7a04c (patch) | |
tree | fdb496c29fbba053146f5b1cf56ca9b568b66d5c | |
parent | 2a4b78446f6553957d6181b9baad3ba2ecf4a2cc (diff) | |
download | babel-79bcdf2640b400a56577d93e7fde026290c7a04c.tar.gz |
Support for formatting NaN, Infinity (#955)
-rw-r--r-- | babel/numbers.py | 24 | ||||
-rw-r--r-- | tests/test_numbers.py | 10 |
2 files changed, 32 insertions, 2 deletions
diff --git a/babel/numbers.py b/babel/numbers.py index d107046..ee9a133 100644 --- a/babel/numbers.py +++ b/babel/numbers.py @@ -126,7 +126,10 @@ def get_currency_name( """ loc = Locale.parse(locale) if count is not None: - plural_form = loc.plural_form(count) + try: + plural_form = loc.plural_form(count) + except (OverflowError, ValueError): + plural_form = 'other' plural_names = loc._data['currency_names_plural'] if currency in plural_names: currency_plural_names = plural_names[currency] @@ -371,6 +374,17 @@ def get_group_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: return Locale.parse(locale).number_symbols.get('group', ',') +def get_infinity_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: + """Return the symbol used by the locale to represent infinity. + + >>> get_infinity_symbol('en_US') + u'∞' + + :param locale: the `Locale` object or locale identifier + """ + return Locale.parse(locale).number_symbols.get('infinity', '∞') + + def format_number(number: float | decimal.Decimal | str, locale: Locale | str | None = LC_NUMERIC) -> str: """Return the given number formatted for a specific locale. @@ -400,7 +414,8 @@ def get_decimal_precision(number: decimal.Decimal) -> int: # Copied from: https://github.com/mahmoud/boltons/pull/59 assert isinstance(number, decimal.Decimal) decimal_tuple = number.normalize().as_tuple() - if decimal_tuple.exponent >= 0: + # Note: DecimalTuple.exponent can be 'n' (qNaN), 'N' (sNaN), or 'F' (Infinity) + if not isinstance(decimal_tuple.exponent, int) or decimal_tuple.exponent >= 0: return 0 return abs(decimal_tuple.exponent) @@ -515,6 +530,8 @@ def _get_compact_format( """ if not isinstance(number, decimal.Decimal): number = decimal.Decimal(str(number)) + if number.is_nan() or number.is_infinite(): + return number, None format = None for magnitude in sorted([int(m) for m in compact_format["other"]], reverse=True): if abs(number) >= magnitude: @@ -1287,6 +1304,9 @@ class NumberPattern: return value + ret def _quantize_value(self, value: decimal.Decimal, locale: Locale | str | None, frac_prec: tuple[int, int], group_separator: bool) -> str: + # If the number is +/-Infinity, we can't quantize it + if value.is_infinite(): + return get_infinity_symbol(locale) quantum = get_decimal_quantum(frac_prec[1]) rounded = value.quantize(quantum) a, sep, b = f"{rounded:f}".partition(".") diff --git a/tests/test_numbers.py b/tests/test_numbers.py index c8a04d6..d6028b3 100644 --- a/tests/test_numbers.py +++ b/tests/test_numbers.py @@ -111,6 +111,16 @@ class FormatDecimalTestCase(unittest.TestCase): number = decimal.Decimal("7E-7") assert numbers.format_decimal(number, format="@@@", locale='en_US') == '0.000000700' + def test_nan_and_infinity(self): + assert numbers.format_decimal(decimal.Decimal('Infinity'), locale='en_US') == '∞' + assert numbers.format_decimal(decimal.Decimal('-Infinity'), locale='en_US') == '-∞' + assert numbers.format_decimal(decimal.Decimal('NaN'), locale='en_US') == 'NaN' + assert numbers.format_compact_decimal(decimal.Decimal('Infinity'), locale='en_US', format_type="short") == '∞' + assert numbers.format_compact_decimal(decimal.Decimal('-Infinity'), locale='en_US', format_type="short") == '-∞' + assert numbers.format_compact_decimal(decimal.Decimal('NaN'), locale='en_US', format_type="short") == 'NaN' + assert numbers.format_currency(decimal.Decimal('Infinity'), 'USD', locale='en_US') == '$∞' + assert numbers.format_currency(decimal.Decimal('-Infinity'), 'USD', locale='en_US') == '-$∞' + def test_group_separator(self): assert numbers.format_decimal(29567.12, locale='en_US', group_separator=False) == '29567.12' assert numbers.format_decimal(29567.12, locale='fr_CA', group_separator=False) == '29567,12' |