def format_decimal(
- number, format=None, locale=LC_NUMERIC, decimal_quantization=True):
+ number, format=None, locale=LC_NUMERIC, decimal_quantization=True, group_separator=True):
u"""Return the given decimal number formatted for a specific locale.
>>> format_decimal(1.2345, locale='en_US')
u'1.235'
>>> format_decimal(1.2346, locale='en_US', decimal_quantization=False)
u'1.2346'
+ >>> format_decimal(12345.67, locale='fr_CA', group_separator=False)
+ u'12345,67'
+ >>> format_decimal(12345.67, locale='en_US', group_separator=True)
+ u'12,345.67'
:param number: the number to format
:param format:
:param locale: the `Locale` object or locale identifier
:param decimal_quantization: Truncate and round high-precision numbers to
the format pattern. Defaults to `True`.
+ :param group_separator: Boolean to switch group separator on/off in a locale's
+ number format.
"""
locale = Locale.parse(locale)
if not format:
format = locale.decimal_formats.get(format)
pattern = parse_pattern(format)
return pattern.apply(
- number, locale, decimal_quantization=decimal_quantization)
+ number, locale, decimal_quantization=decimal_quantization, group_separator=group_separator)
class UnknownCurrencyFormatError(KeyError):
def format_currency(
number, currency, format=None, locale=LC_NUMERIC, currency_digits=True,
- format_type='standard', decimal_quantization=True):
+ format_type='standard', decimal_quantization=True, group_separator=True):
u"""Return formatted currency value.
>>> format_currency(1099.98, 'USD', locale='en_US')
...
UnknownCurrencyFormatError: "'unknown' is not a known currency format type"
+ >>> format_currency(101299.98, 'USD', locale='en_US', group_separator=False)
+ u'$101299.98'
+
+ >>> format_currency(101299.98, 'USD', locale='en_US', group_separator=True)
+ u'$101,299.98'
+
You can also pass format_type='name' to use long display names. The order of
the number and currency name, along with the correct localized plural form
of the currency name, is chosen according to locale:
:param format_type: the currency format type to use
:param decimal_quantization: Truncate and round high-precision numbers to
the format pattern. Defaults to `True`.
+ :param group_separator: Boolean to switch group separator on/off in a locale's
+ number format.
"""
if format_type == 'name':
return _format_currency_long_name(number, currency, format=format,
locale=locale, currency_digits=currency_digits,
- decimal_quantization=decimal_quantization)
+ decimal_quantization=decimal_quantization, group_separator=group_separator)
locale = Locale.parse(locale)
if format:
pattern = parse_pattern(format)
return pattern.apply(
number, locale, currency=currency, currency_digits=currency_digits,
- decimal_quantization=decimal_quantization)
+ decimal_quantization=decimal_quantization, group_separator=group_separator)
def _format_currency_long_name(
number, currency, format=None, locale=LC_NUMERIC, currency_digits=True,
- format_type='standard', decimal_quantization=True):
+ format_type='standard', decimal_quantization=True, group_separator=True):
# Algorithm described here:
# https://www.unicode.org/reports/tr35/tr35-numbers.html#Currencies
locale = Locale.parse(locale)
number_part = pattern.apply(
number, locale, currency=currency, currency_digits=currency_digits,
- decimal_quantization=decimal_quantization)
+ decimal_quantization=decimal_quantization, group_separator=group_separator)
return unit_pattern.format(number_part, display_name)
def format_percent(
- number, format=None, locale=LC_NUMERIC, decimal_quantization=True):
+ number, format=None, locale=LC_NUMERIC, decimal_quantization=True, group_separator=True):
"""Return formatted percent value for a specific locale.
>>> format_percent(0.34, locale='en_US')
>>> format_percent(23.9876, locale='en_US', decimal_quantization=False)
u'2,398.76%'
+ >>> format_percent(229291.1234, locale='pt_BR', group_separator=False)
+ u'22929112%'
+
+ >>> format_percent(229291.1234, locale='pt_BR', group_separator=True)
+ u'22.929.112%'
+
:param number: the percent number to format
:param format:
:param locale: the `Locale` object or locale identifier
:param decimal_quantization: Truncate and round high-precision numbers to
the format pattern. Defaults to `True`.
+ :param group_separator: Boolean to switch group separator on/off in a locale's
+ number format.
"""
locale = Locale.parse(locale)
if not format:
format = locale.percent_formats.get(format)
pattern = parse_pattern(format)
return pattern.apply(
- number, locale, decimal_quantization=decimal_quantization)
+ number, locale, decimal_quantization=decimal_quantization, group_separator=group_separator)
def format_scientific(
currency_digits=True,
decimal_quantization=True,
force_frac=None,
+ group_separator=True,
):
"""Renders into a string a number following the defined pattern.
if self.exp_prec:
value, exp, exp_sign = self.scientific_notation_elements(value, locale)
- # Adjust the precision of the fractionnal part and force it to the
- # currency's if neccessary.
+ # Adjust the precision of the fractional part and force it to the
+ # currency's if necessary.
if force_frac:
# TODO (3.x?): Remove this parameter
warnings.warn('The force_frac parameter to NumberPattern.apply() is deprecated.', DeprecationWarning)
# Render scientific notation.
if self.exp_prec:
number = ''.join([
- self._quantize_value(value, locale, frac_prec),
+ self._quantize_value(value, locale, frac_prec, group_separator),
get_exponential_symbol(locale),
exp_sign,
self._format_int(
# A normal number pattern.
else:
- number = self._quantize_value(value, locale, frac_prec)
+ number = self._quantize_value(value, locale, frac_prec, group_separator)
retval = ''.join([
self.prefix[is_negative],
gsize = self.grouping[1]
return value + ret
- def _quantize_value(self, value, locale, frac_prec):
+ def _quantize_value(self, value, locale, frac_prec, group_separator):
quantum = get_decimal_quantum(frac_prec[1])
rounded = value.quantize(quantum)
a, sep, b = "{:f}".format(rounded).partition(".")
- number = (self._format_int(a, self.int_prec[0],
- self.int_prec[1], locale) +
- self._format_frac(b or '0', locale, frac_prec))
+ integer_part = a
+ if group_separator:
+ integer_part = self._format_int(a, self.int_prec[0], self.int_prec[1], locale)
+ number = integer_part + self._format_frac(b or '0', locale, frac_prec)
return number
def _format_frac(self, value, locale, force_frac=None):
fmt = numbers.format_decimal(number, format="@@@", locale='en_US')
self.assertEqual('0.000000700', fmt)
+ def test_group_separator(self):
+ self.assertEqual('29567.12', numbers.format_decimal(29567.12,
+ locale='en_US', group_separator=False))
+ self.assertEqual('29567,12', numbers.format_decimal(29567.12,
+ locale='fr_CA', group_separator=False))
+ self.assertEqual('29567,12', numbers.format_decimal(29567.12,
+ locale='pt_BR', group_separator=False))
+ self.assertEqual(u'$1099.98', numbers.format_currency(1099.98, 'USD',
+ locale='en_US', group_separator=False))
+ self.assertEqual(u'101299,98\xa0€', numbers.format_currency(101299.98, 'EUR',
+ locale='fr_CA', group_separator=False))
+ self.assertEqual('101299.98 euros', numbers.format_currency(101299.98, 'EUR',
+ locale='en_US', group_separator=False, format_type='name'))
+ self.assertEqual(u'25123412\xa0%', numbers.format_percent(251234.1234, locale='sv_SE', group_separator=False))
+
+ self.assertEqual(u'29,567.12', numbers.format_decimal(29567.12,
+ locale='en_US', group_separator=True))
+ self.assertEqual(u'29\u202f567,12', numbers.format_decimal(29567.12,
+ locale='fr_CA', group_separator=True))
+ self.assertEqual(u'29.567,12', numbers.format_decimal(29567.12,
+ locale='pt_BR', group_separator=True))
+ self.assertEqual(u'$1,099.98', numbers.format_currency(1099.98, 'USD',
+ locale='en_US', group_separator=True))
+ self.assertEqual(u'101\u202f299,98\xa0\u20ac', numbers.format_currency(101299.98, 'EUR',
+ locale='fr_CA', group_separator=True))
+ self.assertEqual(u'101,299.98 euros', numbers.format_currency(101299.98, 'EUR',
+ locale='en_US', group_separator=True,
+ format_type='name'))
+ self.assertEqual(u'25\xa0123\xa0412\xa0%', numbers.format_percent(251234.1234, locale='sv_SE', group_separator=True))
+
class NumberParsingTestCase(unittest.TestCase):