aboutsummaryrefslogtreecommitdiffstats
path: root/jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/numbers.py
diff options
context:
space:
mode:
Diffstat (limited to 'jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/numbers.py')
-rw-r--r--jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/numbers.py681
1 files changed, 681 insertions, 0 deletions
diff --git a/jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/numbers.py b/jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/numbers.py
new file mode 100644
index 0000000..3ab366c
--- /dev/null
+++ b/jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/numbers.py
@@ -0,0 +1,681 @@
+# -*- coding: utf-8 -*-
+"""
+ babel.numbers
+ ~~~~~~~~~~~~~
+
+ Locale dependent formatting and parsing of numeric data.
+
+ The default locale for the functions in this module is determined by the
+ following environment variables, in that order:
+
+ * ``LC_NUMERIC``,
+ * ``LC_ALL``, and
+ * ``LANG``
+
+ :copyright: (c) 2013 by the Babel Team.
+ :license: BSD, see LICENSE for more details.
+"""
+# TODO:
+# Padding and rounding increments in pattern:
+# - http://www.unicode.org/reports/tr35/ (Appendix G.6)
+import re
+from datetime import date as date_, datetime as datetime_
+
+from babel.core import default_locale, Locale, get_global
+from babel._compat import Decimal, InvalidOperation, ROUND_HALF_EVEN
+
+
+LC_NUMERIC = default_locale('LC_NUMERIC')
+
+
+def get_currency_name(currency, count=None, locale=LC_NUMERIC):
+ """Return the name used by the locale for the specified currency.
+
+ >>> get_currency_name('USD', locale='en_US')
+ u'US Dollar'
+
+ .. versionadded:: 0.9.4
+
+ :param currency: the currency code
+ :param count: the optional count. If provided the currency name
+ will be pluralized to that number if possible.
+ :param locale: the `Locale` object or locale identifier
+ """
+ loc = Locale.parse(locale)
+ if count is not None:
+ plural_form = loc.plural_form(count)
+ plural_names = loc._data['currency_names_plural']
+ if currency in plural_names:
+ return plural_names[currency][plural_form]
+ return loc.currencies.get(currency, currency)
+
+
+def get_currency_symbol(currency, locale=LC_NUMERIC):
+ """Return the symbol used by the locale for the specified currency.
+
+ >>> get_currency_symbol('USD', locale='en_US')
+ u'$'
+
+ :param currency: the currency code
+ :param locale: the `Locale` object or locale identifier
+ """
+ return Locale.parse(locale).currency_symbols.get(currency, currency)
+
+
+def get_territory_currencies(territory, start_date=None, end_date=None,
+ tender=True, non_tender=False,
+ include_details=False):
+ """Returns the list of currencies for the given territory that are valid for
+ the given date range. In addition to that the currency database
+ distinguishes between tender and non-tender currencies. By default only
+ tender currencies are returned.
+
+ The return value is a list of all currencies roughly ordered by the time
+ of when the currency became active. The longer the currency is being in
+ use the more to the left of the list it will be.
+
+ The start date defaults to today. If no end date is given it will be the
+ same as the start date. Otherwise a range can be defined. For instance
+ this can be used to find the currencies in use in Austria between 1995 and
+ 2011:
+
+ >>> from datetime import date
+ >>> get_territory_currencies('AT', date(1995, 1, 1), date(2011, 1, 1))
+ ['ATS', 'EUR']
+
+ Likewise it's also possible to find all the currencies in use on a
+ single date:
+
+ >>> get_territory_currencies('AT', date(1995, 1, 1))
+ ['ATS']
+ >>> get_territory_currencies('AT', date(2011, 1, 1))
+ ['EUR']
+
+ By default the return value only includes tender currencies. This
+ however can be changed:
+
+ >>> get_territory_currencies('US')
+ ['USD']
+ >>> get_territory_currencies('US', tender=False, non_tender=True,
+ ... start_date=date(2014, 1, 1))
+ ['USN', 'USS']
+
+ .. versionadded:: 2.0
+
+ :param territory: the name of the territory to find the currency fo
+ :param start_date: the start date. If not given today is assumed.
+ :param end_date: the end date. If not given the start date is assumed.
+ :param tender: controls whether tender currencies should be included.
+ :param non_tender: controls whether non-tender currencies should be
+ included.
+ :param include_details: if set to `True`, instead of returning currency
+ codes the return value will be dictionaries
+ with detail information. In that case each
+ dictionary will have the keys ``'currency'``,
+ ``'from'``, ``'to'``, and ``'tender'``.
+ """
+ currencies = get_global('territory_currencies')
+ if start_date is None:
+ start_date = date_.today()
+ elif isinstance(start_date, datetime_):
+ start_date = start_date.date()
+ if end_date is None:
+ end_date = start_date
+ elif isinstance(end_date, datetime_):
+ end_date = end_date.date()
+
+ curs = currencies.get(territory.upper(), ())
+ # TODO: validate that the territory exists
+
+ def _is_active(start, end):
+ return (start is None or start <= end_date) and \
+ (end is None or end >= start_date)
+
+ result = []
+ for currency_code, start, end, is_tender in curs:
+ if start:
+ start = date_(*start)
+ if end:
+ end = date_(*end)
+ if ((is_tender and tender) or
+ (not is_tender and non_tender)) and _is_active(start, end):
+ if include_details:
+ result.append({
+ 'currency': currency_code,
+ 'from': start,
+ 'to': end,
+ 'tender': is_tender,
+ })
+ else:
+ result.append(currency_code)
+
+ return result
+
+
+def get_decimal_symbol(locale=LC_NUMERIC):
+ """Return the symbol used by the locale to separate decimal fractions.
+
+ >>> get_decimal_symbol('en_US')
+ u'.'
+
+ :param locale: the `Locale` object or locale identifier
+ """
+ return Locale.parse(locale).number_symbols.get('decimal', u'.')
+
+
+def get_plus_sign_symbol(locale=LC_NUMERIC):
+ """Return the plus sign symbol used by the current locale.
+
+ >>> get_plus_sign_symbol('en_US')
+ u'+'
+
+ :param locale: the `Locale` object or locale identifier
+ """
+ return Locale.parse(locale).number_symbols.get('plusSign', u'+')
+
+
+def get_minus_sign_symbol(locale=LC_NUMERIC):
+ """Return the plus sign symbol used by the current locale.
+
+ >>> get_minus_sign_symbol('en_US')
+ u'-'
+
+ :param locale: the `Locale` object or locale identifier
+ """
+ return Locale.parse(locale).number_symbols.get('minusSign', u'-')
+
+
+def get_exponential_symbol(locale=LC_NUMERIC):
+ """Return the symbol used by the locale to separate mantissa and exponent.
+
+ >>> get_exponential_symbol('en_US')
+ u'E'
+
+ :param locale: the `Locale` object or locale identifier
+ """
+ return Locale.parse(locale).number_symbols.get('exponential', u'E')
+
+
+def get_group_symbol(locale=LC_NUMERIC):
+ """Return the symbol used by the locale to separate groups of thousands.
+
+ >>> get_group_symbol('en_US')
+ u','
+
+ :param locale: the `Locale` object or locale identifier
+ """
+ return Locale.parse(locale).number_symbols.get('group', u',')
+
+
+def format_number(number, locale=LC_NUMERIC):
+ u"""Return the given number formatted for a specific locale.
+
+ >>> format_number(1099, locale='en_US')
+ u'1,099'
+ >>> format_number(1099, locale='de_DE')
+ u'1.099'
+
+
+ :param number: the number to format
+ :param locale: the `Locale` object or locale identifier
+ """
+ # Do we really need this one?
+ return format_decimal(number, locale=locale)
+
+
+def format_decimal(number, format=None, locale=LC_NUMERIC):
+ u"""Return the given decimal number formatted for a specific locale.
+
+ >>> format_decimal(1.2345, locale='en_US')
+ u'1.234'
+ >>> format_decimal(1.2346, locale='en_US')
+ u'1.235'
+ >>> format_decimal(-1.2346, locale='en_US')
+ u'-1.235'
+ >>> format_decimal(1.2345, locale='sv_SE')
+ u'1,234'
+ >>> format_decimal(1.2345, locale='de')
+ u'1,234'
+
+ The appropriate thousands grouping and the decimal separator are used for
+ each locale:
+
+ >>> format_decimal(12345.5, locale='en_US')
+ u'12,345.5'
+
+ :param number: the number to format
+ :param format:
+ :param locale: the `Locale` object or locale identifier
+ """
+ locale = Locale.parse(locale)
+ if not format:
+ format = locale.decimal_formats.get(format)
+ pattern = parse_pattern(format)
+ return pattern.apply(number, locale)
+
+
+class UnknownCurrencyFormatError(KeyError):
+ """Exception raised when an unknown currency format is requested."""
+
+
+def format_currency(number, currency, format=None, locale=LC_NUMERIC,
+ currency_digits=True, format_type='standard'):
+ u"""Return formatted currency value.
+
+ >>> format_currency(1099.98, 'USD', locale='en_US')
+ u'$1,099.98'
+ >>> format_currency(1099.98, 'USD', locale='es_CO')
+ u'US$\\xa01.099,98'
+ >>> format_currency(1099.98, 'EUR', locale='de_DE')
+ u'1.099,98\\xa0\\u20ac'
+
+ The format can also be specified explicitly. The currency is
+ placed with the '¤' sign. As the sign gets repeated the format
+ expands (¤ being the symbol, ¤¤ is the currency abbreviation and
+ ¤¤¤ is the full name of the currency):
+
+ >>> format_currency(1099.98, 'EUR', u'\xa4\xa4 #,##0.00', locale='en_US')
+ u'EUR 1,099.98'
+ >>> format_currency(1099.98, 'EUR', u'#,##0.00 \xa4\xa4\xa4', locale='en_US')
+ u'1,099.98 euros'
+
+ Currencies usually have a specific number of decimal digits. This function
+ favours that information over the given format:
+
+ >>> format_currency(1099.98, 'JPY', locale='en_US')
+ u'\\xa51,100'
+ >>> format_currency(1099.98, 'COP', u'#,##0.00', locale='es_ES')
+ u'1.100'
+
+ However, the number of decimal digits can be overriden from the currency
+ information, by setting the last parameter to ``False``:
+
+ >>> format_currency(1099.98, 'JPY', locale='en_US', currency_digits=False)
+ u'\\xa51,099.98'
+ >>> format_currency(1099.98, 'COP', u'#,##0.00', locale='es_ES', currency_digits=False)
+ u'1.099,98'
+
+ If a format is not specified the type of currency format to use
+ from the locale can be specified:
+
+ >>> format_currency(1099.98, 'EUR', locale='en_US', format_type='standard')
+ u'\\u20ac1,099.98'
+
+ When the given currency format type is not available, an exception is
+ raised:
+
+ >>> format_currency('1099.98', 'EUR', locale='root', format_type='unknown')
+ Traceback (most recent call last):
+ ...
+ UnknownCurrencyFormatError: "'unknown' is not a known currency format type"
+
+ :param number: the number to format
+ :param currency: the currency code
+ :param format: the format string to use
+ :param locale: the `Locale` object or locale identifier
+ :param currency_digits: use the currency's number of decimal digits
+ :param format_type: the currency format type to use
+ """
+ locale = Locale.parse(locale)
+ if format:
+ pattern = parse_pattern(format)
+ else:
+ try:
+ pattern = locale.currency_formats[format_type]
+ except KeyError:
+ raise UnknownCurrencyFormatError("%r is not a known currency format"
+ " type" % format_type)
+ if currency_digits:
+ fractions = get_global('currency_fractions')
+ try:
+ digits = fractions[currency][0]
+ except KeyError:
+ digits = fractions['DEFAULT'][0]
+ frac = (digits, digits)
+ else:
+ frac = None
+ return pattern.apply(number, locale, currency=currency, force_frac=frac)
+
+
+def format_percent(number, format=None, locale=LC_NUMERIC):
+ """Return formatted percent value for a specific locale.
+
+ >>> format_percent(0.34, locale='en_US')
+ u'34%'
+ >>> format_percent(25.1234, locale='en_US')
+ u'2,512%'
+ >>> format_percent(25.1234, locale='sv_SE')
+ u'2\\xa0512\\xa0%'
+
+ The format pattern can also be specified explicitly:
+
+ >>> format_percent(25.1234, u'#,##0\u2030', locale='en_US')
+ u'25,123\u2030'
+
+ :param number: the percent number to format
+ :param format:
+ :param locale: the `Locale` object or locale identifier
+ """
+ locale = Locale.parse(locale)
+ if not format:
+ format = locale.percent_formats.get(format)
+ pattern = parse_pattern(format)
+ return pattern.apply(number, locale)
+
+
+def format_scientific(number, format=None, locale=LC_NUMERIC):
+ """Return value formatted in scientific notation for a specific locale.
+
+ >>> format_scientific(10000, locale='en_US')
+ u'1E4'
+
+ The format pattern can also be specified explicitly:
+
+ >>> format_scientific(1234567, u'##0E00', locale='en_US')
+ u'1.23E06'
+
+ :param number: the number to format
+ :param format:
+ :param locale: the `Locale` object or locale identifier
+ """
+ locale = Locale.parse(locale)
+ if not format:
+ format = locale.scientific_formats.get(format)
+ pattern = parse_pattern(format)
+ return pattern.apply(number, locale)
+
+
+class NumberFormatError(ValueError):
+ """Exception raised when a string cannot be parsed into a number."""
+
+
+def parse_number(string, locale=LC_NUMERIC):
+ """Parse localized number string into an integer.
+
+ >>> parse_number('1,099', locale='en_US')
+ 1099
+ >>> parse_number('1.099', locale='de_DE')
+ 1099
+
+ When the given string cannot be parsed, an exception is raised:
+
+ >>> parse_number('1.099,98', locale='de')
+ Traceback (most recent call last):
+ ...
+ NumberFormatError: '1.099,98' is not a valid number
+
+ :param string: the string to parse
+ :param locale: the `Locale` object or locale identifier
+ :return: the parsed number
+ :raise `NumberFormatError`: if the string can not be converted to a number
+ """
+ try:
+ return int(string.replace(get_group_symbol(locale), ''))
+ except ValueError:
+ raise NumberFormatError('%r is not a valid number' % string)
+
+
+def parse_decimal(string, locale=LC_NUMERIC):
+ """Parse localized decimal string into a decimal.
+
+ >>> parse_decimal('1,099.98', locale='en_US')
+ Decimal('1099.98')
+ >>> parse_decimal('1.099,98', locale='de')
+ Decimal('1099.98')
+
+ When the given string cannot be parsed, an exception is raised:
+
+ >>> parse_decimal('2,109,998', locale='de')
+ Traceback (most recent call last):
+ ...
+ NumberFormatError: '2,109,998' is not a valid decimal number
+
+ :param string: the string to parse
+ :param locale: the `Locale` object or locale identifier
+ :raise NumberFormatError: if the string can not be converted to a
+ decimal number
+ """
+ locale = Locale.parse(locale)
+ try:
+ return Decimal(string.replace(get_group_symbol(locale), '')
+ .replace(get_decimal_symbol(locale), '.'))
+ except InvalidOperation:
+ raise NumberFormatError('%r is not a valid decimal number' % string)
+
+
+PREFIX_END = r'[^0-9@#.,]'
+NUMBER_TOKEN = r'[0-9@#.,E+]'
+
+PREFIX_PATTERN = r"(?P<prefix>(?:'[^']*'|%s)*)" % PREFIX_END
+NUMBER_PATTERN = r"(?P<number>%s+)" % NUMBER_TOKEN
+SUFFIX_PATTERN = r"(?P<suffix>.*)"
+
+number_re = re.compile(r"%s%s%s" % (PREFIX_PATTERN, NUMBER_PATTERN,
+ SUFFIX_PATTERN))
+
+
+def parse_grouping(p):
+ """Parse primary and secondary digit grouping
+
+ >>> parse_grouping('##')
+ (1000, 1000)
+ >>> parse_grouping('#,###')
+ (3, 3)
+ >>> parse_grouping('#,####,###')
+ (3, 4)
+ """
+ width = len(p)
+ g1 = p.rfind(',')
+ if g1 == -1:
+ return 1000, 1000
+ g1 = width - g1 - 1
+ g2 = p[:-g1 - 1].rfind(',')
+ if g2 == -1:
+ return g1, g1
+ g2 = width - g1 - g2 - 2
+ return g1, g2
+
+
+def parse_pattern(pattern):
+ """Parse number format patterns"""
+ if isinstance(pattern, NumberPattern):
+ return pattern
+
+ def _match_number(pattern):
+ rv = number_re.search(pattern)
+ if rv is None:
+ raise ValueError('Invalid number pattern %r' % pattern)
+ return rv.groups()
+
+ # Do we have a negative subpattern?
+ if ';' in pattern:
+ pattern, neg_pattern = pattern.split(';', 1)
+ pos_prefix, number, pos_suffix = _match_number(pattern)
+ neg_prefix, _, neg_suffix = _match_number(neg_pattern)
+ else:
+ pos_prefix, number, pos_suffix = _match_number(pattern)
+ neg_prefix = '-' + pos_prefix
+ neg_suffix = pos_suffix
+ if 'E' in number:
+ number, exp = number.split('E', 1)
+ else:
+ exp = None
+ if '@' in number:
+ if '.' in number and '0' in number:
+ raise ValueError('Significant digit patterns can not contain '
+ '"@" or "0"')
+ if '.' in number:
+ integer, fraction = number.rsplit('.', 1)
+ else:
+ integer = number
+ fraction = ''
+
+ def parse_precision(p):
+ """Calculate the min and max allowed digits"""
+ min = max = 0
+ for c in p:
+ if c in '@0':
+ min += 1
+ max += 1
+ elif c == '#':
+ max += 1
+ elif c == ',':
+ continue
+ else:
+ break
+ return min, max
+
+ int_prec = parse_precision(integer)
+ frac_prec = parse_precision(fraction)
+ if exp:
+ frac_prec = parse_precision(integer + fraction)
+ exp_plus = exp.startswith('+')
+ exp = exp.lstrip('+')
+ exp_prec = parse_precision(exp)
+ else:
+ exp_plus = None
+ exp_prec = None
+ grouping = parse_grouping(integer)
+ return NumberPattern(pattern, (pos_prefix, neg_prefix),
+ (pos_suffix, neg_suffix), grouping,
+ int_prec, frac_prec,
+ exp_prec, exp_plus)
+
+
+class NumberPattern(object):
+
+ def __init__(self, pattern, prefix, suffix, grouping,
+ int_prec, frac_prec, exp_prec, exp_plus):
+ self.pattern = pattern
+ self.prefix = prefix
+ self.suffix = suffix
+ self.grouping = grouping
+ self.int_prec = int_prec
+ self.frac_prec = frac_prec
+ self.exp_prec = exp_prec
+ self.exp_plus = exp_plus
+ if '%' in ''.join(self.prefix + self.suffix):
+ self.scale = 2
+ elif u'‰' in ''.join(self.prefix + self.suffix):
+ self.scale = 3
+ else:
+ self.scale = 0
+
+ def __repr__(self):
+ return '<%s %r>' % (type(self).__name__, self.pattern)
+
+ def apply(self, value, locale, currency=None, force_frac=None):
+ frac_prec = force_frac or self.frac_prec
+ if not isinstance(value, Decimal):
+ value = Decimal(str(value))
+ value = value.scaleb(self.scale)
+ is_negative = int(value.is_signed())
+ if self.exp_prec: # Scientific notation
+ exp = value.adjusted()
+ value = abs(value)
+ # Minimum number of integer digits
+ if self.int_prec[0] == self.int_prec[1]:
+ exp -= self.int_prec[0] - 1
+ # Exponent grouping
+ elif self.int_prec[1]:
+ exp = int(exp / self.int_prec[1]) * self.int_prec[1]
+ if exp < 0:
+ value = value * 10**(-exp)
+ else:
+ value = value / 10**exp
+ exp_sign = ''
+ if exp < 0:
+ exp_sign = get_minus_sign_symbol(locale)
+ elif self.exp_plus:
+ exp_sign = get_plus_sign_symbol(locale)
+ exp = abs(exp)
+ number = u'%s%s%s%s' % \
+ (self._format_significant(value, frac_prec[0], frac_prec[1]),
+ get_exponential_symbol(locale), exp_sign,
+ self._format_int(str(exp), self.exp_prec[0],
+ self.exp_prec[1], locale))
+ elif '@' in self.pattern: # Is it a siginificant digits pattern?
+ text = self._format_significant(abs(value),
+ self.int_prec[0],
+ self.int_prec[1])
+ a, sep, b = text.partition(".")
+ number = self._format_int(a, 0, 1000, locale)
+ if sep:
+ number += get_decimal_symbol(locale) + b
+ else: # A normal number pattern
+ precision = Decimal('1.' + '1' * frac_prec[1])
+ rounded = value.quantize(precision, ROUND_HALF_EVEN)
+ a, sep, b = str(abs(rounded)).partition(".")
+ number = (self._format_int(a, self.int_prec[0],
+ self.int_prec[1], locale) +
+ self._format_frac(b or '0', locale, force_frac))
+ retval = u'%s%s%s' % (self.prefix[is_negative], number,
+ self.suffix[is_negative])
+ if u'¤' in retval:
+ retval = retval.replace(u'¤¤¤',
+ get_currency_name(currency, value, locale))
+ retval = retval.replace(u'¤¤', currency.upper())
+ retval = retval.replace(u'¤', get_currency_symbol(currency, locale))
+ return retval
+
+ #
+ # This is one tricky piece of code. The idea is to rely as much as possible
+ # on the decimal module to minimize the amount of code.
+ #
+ # Conceptually, the implementation of this method can be summarized in the
+ # following steps:
+ #
+ # - Move or shift the decimal point (i.e. the exponent) so the maximum
+ # amount of significant digits fall into the integer part (i.e. to the
+ # left of the decimal point)
+ #
+ # - Round the number to the nearest integer, discarding all the fractional
+ # part which contained extra digits to be eliminated
+ #
+ # - Convert the rounded integer to a string, that will contain the final
+ # sequence of significant digits already trimmed to the maximum
+ #
+ # - Restore the original position of the decimal point, potentially
+ # padding with zeroes on either side
+ #
+ def _format_significant(self, value, minimum, maximum):
+ exp = value.adjusted()
+ scale = maximum - 1 - exp
+ digits = str(value.scaleb(scale).quantize(Decimal(1), ROUND_HALF_EVEN))
+ if scale <= 0:
+ result = digits + '0' * -scale
+ else:
+ intpart = digits[:-scale]
+ i = len(intpart)
+ j = i + max(minimum - i, 0)
+ result = "{intpart}.{pad:0<{fill}}{fracpart}{fracextra}".format(
+ intpart=intpart or '0',
+ pad='',
+ fill=-min(exp + 1, 0),
+ fracpart=digits[i:j],
+ fracextra=digits[j:].rstrip('0'),
+ ).rstrip('.')
+ return result
+
+ def _format_int(self, value, min, max, locale):
+ width = len(value)
+ if width < min:
+ value = '0' * (min - width) + value
+ gsize = self.grouping[0]
+ ret = ''
+ symbol = get_group_symbol(locale)
+ while len(value) > gsize:
+ ret = symbol + value[-gsize:] + ret
+ value = value[:-gsize]
+ gsize = self.grouping[1]
+ return value + ret
+
+ def _format_frac(self, value, locale, force_frac=None):
+ min, max = force_frac or self.frac_prec
+ if len(value) < min:
+ value += ('0' * (min - len(value)))
+ if max == 0 or (min == 0 and int(value) == 0):
+ return ''
+ while len(value) > min and value[-1] == '0':
+ value = value[:-1]
+ return get_decimal_symbol(locale) + value