summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Groszer <agroszer@gmail.com>2019-02-19 13:33:52 +0100
committerGitHub <noreply@github.com>2019-02-19 13:33:52 +0100
commit62c8f9559a7b67252027a867ec699109a422e1bf (patch)
tree145f243917c51831b23daa5ba193565039cc9249
parenta706a1fcd827aa0094ef23b86ac47840c16be465 (diff)
parent9ffda633889708d5a14a24a9f5e3e486f63fcddb (diff)
downloadzope-i18n-62c8f9559a7b67252027a867ec699109a422e1bf.tar.gz
Merge pull request #39 from zopefoundation/adamg-fix-sep
Fix `NumberFormat` to respect the thousand grouping given by the pattern
-rw-r--r--CHANGES.rst3
-rw-r--r--src/zope/i18n/format.py59
-rw-r--r--src/zope/i18n/tests/test_formats.py318
3 files changed, 268 insertions, 112 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index ae2374d..e2085c4 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,7 +5,8 @@
4.6.2 (unreleased)
==================
-- Nothing changed yet.
+- Fix `NumberFormat` to respect the thousand grouping given by the pattern.
+ Triple grouping was hardcoded, which is not true for all locales.
4.6.1 (2018-10-24)
diff --git a/src/zope/i18n/format.py b/src/zope/i18n/format.py
index 96f5ef3..abc3e50 100644
--- a/src/zope/i18n/format.py
+++ b/src/zope/i18n/format.py
@@ -226,7 +226,6 @@ class NumberParseError(Exception):
class NumberFormat(object):
__doc__ = INumberFormat.__doc__
-
type = None
_pattern = None
_bin_pattern = None
@@ -368,6 +367,33 @@ class NumberFormat(object):
fraction = self.symbols['decimal'] + fraction
return fraction, roundInt
+ # taken from cpython lib/Locale.py
+ def _grouping_intervals(self, grouping):
+ last_interval = None
+ for interval in grouping:
+ # 0: re-use last group ad infinitum
+ if interval == 0:
+ if last_interval is None:
+ raise ValueError("invalid grouping")
+ while True:
+ yield last_interval
+ yield interval
+ last_interval = interval
+
+ def _group(self, integer, grouping):
+ # take a given chunk of digits and insert the group symbol
+ # grouping is usually: (3, 0) or (3, 2, 0)
+ digits = list(reversed(integer))
+ last_idx = 0
+ for group_length in self._grouping_intervals(grouping):
+ pos = last_idx + group_length
+ if pos >= len(digits):
+ break
+ digits.insert(pos, self.symbols['group'])
+ last_idx = pos + 1
+ res = ''.join(reversed(digits))
+ return res
+
def format(self, obj, pattern=None, rounding=True):
"See zope.i18n.interfaces.IFormat"
# Make or get binary form of datetime pattern
@@ -454,13 +480,8 @@ class NumberFormat(object):
integer = self._format_integer(str(int(math.fabs(obj))),
bin_pattern[INTEGER])
# Adding grouping
- if bin_pattern[GROUPING] == 1:
- help = ''
- for pos in range(1, len(integer)+1):
- if (pos-1)%3 == 0 and pos != 1:
- help = self.symbols['group'] + help
- help = integer[-pos] + help
- integer = help
+ if bin_pattern[GROUPING]:
+ integer = self._group(integer, bin_pattern[GROUPING])
pre_padding = len(bin_pattern[INTEGER]) - len(integer)
post_padding = len(bin_pattern[FRACTION]) - len(fraction)+1
number = integer + fraction
@@ -779,12 +800,10 @@ def parseNumberPattern(pattern):
fraction = ''
exponential = ''
suffix = ''
- grouping = 0
neg_pattern = None
SPECIALCHARS = "*.,#0;E'"
- length = len(pattern)
state = BEGIN
helper = ''
for pos, char in enumerate(pattern):
@@ -832,7 +851,8 @@ def parseNumberPattern(pattern):
if char == "#" or char == "0":
helper += char
elif char == ",":
- grouping = 1
+ # just add grouping markers to the integer pattern
+ helper += char
elif char == ".":
integer = helper
helper = ''
@@ -934,6 +954,23 @@ def parseNumberPattern(pattern):
if state == READ_EXPONENTIAL:
exponential = helper
+ # the integer pattern can have the grouping delimiters too, let's take care
+ # about those here and now
+ # convert to a tuple of length of groups, from right to left
+ # example: (3, 0) for the usual triple separated, (3, 2, 0) for Hindi
+ # practically trying to return the same as locale.localeconv()['grouping']
+ grouping = ()
+ if "," in integer:
+ last_index = -1
+ for index, char in enumerate(reversed(integer)):
+ if char == ",":
+ grouping += (index-last_index-1,)
+ last_index = index
+ # use last group ad infinitum
+ grouping += (0,)
+ # remove grouping markers from integer pattern
+ integer = integer.replace(",", "")
+
pattern = (padding_1, prefix, padding_2, integer, fraction, exponential,
padding_3, suffix, padding_4, grouping)
diff --git a/src/zope/i18n/tests/test_formats.py b/src/zope/i18n/tests/test_formats.py
index 99c4bf7..879a71a 100644
--- a/src/zope/i18n/tests/test_formats.py
+++ b/src/zope/i18n/tests/test_formats.py
@@ -694,247 +694,349 @@ class TestNumberPatternParser(_TestCase):
def testParseSimpleIntegerPattern(self):
self.assertEqual(
parseNumberPattern('###0'),
- ((None, '', None, '###0', '', '', None, '', None, 0),
- (None, '', None, '###0', '', '', None, '', None, 0)))
+ ((None, '', None, '###0', '', '', None, '', None, ()),
+ (None, '', None, '###0', '', '', None, '', None, ())))
def testParseScientificIntegerPattern(self):
self.assertEqual(
parseNumberPattern('###0E#0'),
- ((None, '', None, '###0', '', '#0', None, '', None, 0),
- (None, '', None, '###0', '', '#0', None, '', None, 0)))
+ ((None, '', None, '###0', '', '#0', None, '', None, ()),
+ (None, '', None, '###0', '', '#0', None, '', None, ())))
self.assertEqual(
parseNumberPattern('###0E+#0'),
- ((None, '', None, '###0', '', '+#0', None, '', None, 0),
- (None, '', None, '###0', '', '+#0', None, '', None, 0)))
+ ((None, '', None, '###0', '', '+#0', None, '', None, ()),
+ (None, '', None, '###0', '', '+#0', None, '', None, ())))
def testParsePosNegAlternativeIntegerPattern(self):
self.assertEqual(
parseNumberPattern('###0;#0'),
- ((None, '', None, '###0', '', '', None, '', None, 0),
- (None, '', None, '#0', '', '', None, '', None, 0)))
+ ((None, '', None, '###0', '', '', None, '', None, ()),
+ (None, '', None, '#0', '', '', None, '', None, ())))
def testParsePrefixedIntegerPattern(self):
self.assertEqual(
parseNumberPattern('+###0'),
- ((None, '+', None, '###0', '', '', None, '', None, 0),
- (None, '+', None, '###0', '', '', None, '', None, 0)))
+ ((None, '+', None, '###0', '', '', None, '', None, ()),
+ (None, '+', None, '###0', '', '', None, '', None, ())))
def testParsePosNegIntegerPattern(self):
self.assertEqual(
parseNumberPattern('+###0;-###0'),
- ((None, '+', None, '###0', '', '', None, '', None, 0),
- (None, '-', None, '###0', '', '', None, '', None, 0)))
+ ((None, '+', None, '###0', '', '', None, '', None, ()),
+ (None, '-', None, '###0', '', '', None, '', None, ())))
def testParseScientificPosNegIntegerPattern(self):
self.assertEqual(
parseNumberPattern('+###0E0;-###0E#0'),
- ((None, '+', None, '###0', '', '0', None, '', None, 0),
- (None, '-', None, '###0', '', '#0', None, '', None, 0)))
+ ((None, '+', None, '###0', '', '0', None, '', None, ()),
+ (None, '-', None, '###0', '', '#0', None, '', None, ())))
def testParseThousandSeparatorIntegerPattern(self):
self.assertEqual(
parseNumberPattern('#,##0'),
- ((None, '', None, '###0', '', '', None, '', None, 1),
- (None, '', None, '###0', '', '', None, '', None, 1)))
+ ((None, '', None, '###0', '', '', None, '', None, (3, 0)),
+ (None, '', None, '###0', '', '', None, '', None, (3, 0))))
def testParseSimpleDecimalPattern(self):
self.assertEqual(
parseNumberPattern('###0.00#'),
- ((None, '', None, '###0', '00#', '', None, '', None, 0),
- (None, '', None, '###0', '00#', '', None, '', None, 0)))
+ ((None, '', None, '###0', '00#', '', None, '', None, ()),
+ (None, '', None, '###0', '00#', '', None, '', None, ())))
def testParseScientificDecimalPattern(self):
self.assertEqual(
parseNumberPattern('###0.00#E#0'),
- ((None, '', None, '###0', '00#', '#0', None, '', None, 0),
- (None, '', None, '###0', '00#', '#0', None, '', None, 0)))
+ ((None, '', None, '###0', '00#', '#0', None, '', None, ()),
+ (None, '', None, '###0', '00#', '#0', None, '', None, ())))
def testParsePosNegAlternativeFractionPattern(self):
self.assertEqual(
parseNumberPattern('###0.00#;#0.0#'),
- ((None, '', None, '###0', '00#', '', None, '', None, 0),
- (None, '', None, '#0', '0#', '', None, '', None, 0)))
+ ((None, '', None, '###0', '00#', '', None, '', None, ()),
+ (None, '', None, '#0', '0#', '', None, '', None, ())))
def testParsePosNegFractionPattern(self):
self.assertEqual(
parseNumberPattern('+###0.0##;-###0.0##'),
- ((None, '+', None, '###0', '0##', '', None, '', None, 0),
- (None, '-', None, '###0', '0##', '', None, '', None, 0)))
+ ((None, '+', None, '###0', '0##', '', None, '', None, ()),
+ (None, '-', None, '###0', '0##', '', None, '', None, ())))
def testParseScientificPosNegFractionPattern(self):
self.assertEqual(
parseNumberPattern('+###0.0##E#0;-###0.0##E0'),
- ((None, '+', None, '###0', '0##', '#0', None, '', None, 0),
- (None, '-', None, '###0', '0##', '0', None, '', None, 0)))
+ ((None, '+', None, '###0', '0##', '#0', None, '', None, ()),
+ (None, '-', None, '###0', '0##', '0', None, '', None, ())))
def testParseThousandSeparatorFractionPattern(self):
self.assertEqual(
parseNumberPattern('#,##0.0#'),
- ((None, '', None, '###0', '0#', '', None, '', None, 1),
- (None, '', None, '###0', '0#', '', None, '', None, 1)))
+ ((None, '', None, '###0', '0#', '', None, '', None, (3, 0)),
+ (None, '', None, '###0', '0#', '', None, '', None, (3, 0))))
+
+ def testParseThousandSeparatorPatterns(self):
+ # the following patterns are present in the ICU XMLs:
+ self.assertEqual(
+ parseNumberPattern('#,##0.00;-#,##0.00'),
+ ((None, '', None, '###0', '00', '', None, '', None, (3, 0)),
+ (None, '-', None, '###0', '00', '', None, '', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('#,##,##0.###;-#,##,##0.###'),
+ ((None, '', None, '#####0', '###', '', None, '', None, (3, 2, 0)),
+ (None, '-', None, '#####0', '###', '', None, '', None, (3, 2, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('#,##0.##;-#,##0.##'),
+ ((None, '', None, '###0', '##', '', None, '', None, (3, 0)),
+ (None, '-', None, '###0', '##', '', None, '', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('#,##0.###;-#,##0.###'),
+ ((None, '', None, '###0', '###', '', None, '', None, (3, 0)),
+ (None, '-', None, '###0', '###', '', None, '', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('#,##0.###;(#,##0.###)'),
+ ((None, '', None, '###0', '###', '', None, '', None, (3, 0)),
+ (None, '(', None, '###0', '###', '', None, ')', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('#,##0.###;#,##0.###-'),
+ ((None, '', None, '###0', '###', '', None, '', None, (3, 0)),
+ (None, '', None, '###0', '###', '', None, '-', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('##,##,##0.###;-##,##,##0.###'),
+ ((None, '', None, '######0', '###', '', None, '', None, (3, 2, 0)),
+ (None, '-', None, '######0', '###', '', None, '', None, (3, 2, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('##,##0.##;-##,##0.##'),
+ ((None, '', None, '####0', '##', '', None, '', None, (3, 0)),
+ (None, '-', None, '####0', '##', '', None, '', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('###0.###;-###0.###'),
+ ((None, '', None, '###0', '###', '', None, '', None, ()),
+ (None, '-', None, '###0', '###', '', None, '', None, ())))
+
+ self.assertEqual(
+ parseNumberPattern('###0.###;###0.###-'),
+ ((None, '', None, '###0', '###', '', None, '', None, ()),
+ (None, '', None, '###0', '###', '', None, '-', None, ())))
+
+ self.assertEqual(
+ parseNumberPattern('#0.###;-#0.###'),
+ ((None, '', None, '#0', '###', '', None, '', None, ()),
+ (None, '-', None, '#0', '###', '', None, '', None, ())))
+
+ self.assertEqual(
+ parseNumberPattern('#,##0.###;#,##0.###'),
+ ((None, '', None, '###0', '###', '', None, '', None, (3, 0)),
+ (None, '', None, '###0', '###', '', None, '', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('###0.###;-###0.###'),
+ ((None, '', None, '###0', '###', '', None, '', None, ()),
+ (None, '-', None, '###0', '###', '', None, '', None, ())))
+
+ self.assertEqual(
+ parseNumberPattern('#,##0.00;-#,##0.00'),
+ ((None, '', None, '###0', '00', '', None, '', None, (3, 0)),
+ (None, '-', None, '###0', '00', '', None, '', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('#,##0.00;(#,##0.00)'),
+ ((None, '', None, '###0', '00', '', None, '', None, (3, 0)),
+ (None, '(', None, '###0', '00', '', None, ')', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('#,##0.00;-#,##0.00'),
+ ((None, '', None, '###0', '00', '', None, '', None, (3, 0)),
+ (None, '-', None, '###0', '00', '', None, '', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('##,##,##0.00;-##,##,##0.00'),
+ ((None, '', None, '######0', '00', '', None, '', None, (3, 2, 0)),
+ (None, '-', None, '######0', '00', '', None, '', None, (3, 2, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('###0.00;-###0.00'),
+ ((None, '', None, '###0', '00', '', None, '', None, ()),
+ (None, '-', None, '###0', '00', '', None, '', None, ())))
+
+ self.assertEqual(
+ parseNumberPattern('#,##0;-#,##0'),
+ ((None, '', None, '###0', '', '', None, '', None, (3, 0)),
+ (None, '-', None, '###0', '', '', None, '', None, (3, 0))))
+
+ self.assertEqual(
+ parseNumberPattern('###0.00;-###0.00'),
+ ((None, '', None, '###0', '00', '', None, '', None, ()),
+ (None, '-', None, '###0', '00', '', None, '', None, ())))
def testParsePadding1WithoutPrefixPattern(self):
self.assertEqual(
parseNumberPattern('* ###0'),
- ((' ', '', None, '###0', '', '', None, '', None, 0),
- (' ', '', None, '###0', '', '', None, '', None, 0)))
+ ((' ', '', None, '###0', '', '', None, '', None, ()),
+ (' ', '', None, '###0', '', '', None, '', None, ())))
self.assertEqual(
parseNumberPattern('* ###0.0##'),
- ((' ', '', None, '###0', '0##', '', None, '', None, 0),
- (' ', '', None, '###0', '0##', '', None, '', None, 0)))
+ ((' ', '', None, '###0', '0##', '', None, '', None, ()),
+ (' ', '', None, '###0', '0##', '', None, '', None, ())))
self.assertEqual(
parseNumberPattern('* ###0.0##;*_###0.0##'),
- ((' ', '', None, '###0', '0##', '', None, '', None, 0),
- ('_', '', None, '###0', '0##', '', None, '', None, 0)))
+ ((' ', '', None, '###0', '0##', '', None, '', None, ()),
+ ('_', '', None, '###0', '0##', '', None, '', None, ())))
def testParsePadding1WithPrefixPattern(self):
self.assertEqual(
parseNumberPattern('* +###0'),
- ((' ', '+', None, '###0', '', '', None, '', None, 0),
- (' ', '+', None, '###0', '', '', None, '', None, 0)))
+ ((' ', '+', None, '###0', '', '', None, '', None, ()),
+ (' ', '+', None, '###0', '', '', None, '', None, ())))
self.assertEqual(
parseNumberPattern('* +###0.0##'),
- ((' ', '+', None, '###0', '0##', '', None, '', None, 0),
- (' ', '+', None, '###0', '0##', '', None, '', None, 0)))
+ ((' ', '+', None, '###0', '0##', '', None, '', None, ()),
+ (' ', '+', None, '###0', '0##', '', None, '', None, ())))
self.assertEqual(
parseNumberPattern('* +###0.0##;*_-###0.0##'),
- ((' ', '+', None, '###0', '0##', '', None, '', None, 0),
- ('_', '-', None, '###0', '0##', '', None, '', None, 0)))
+ ((' ', '+', None, '###0', '0##', '', None, '', None, ()),
+ ('_', '-', None, '###0', '0##', '', None, '', None, ())))
def testParsePadding1Padding2WithPrefixPattern(self):
self.assertEqual(
parseNumberPattern('* +* ###0'),
- ((' ', '+', ' ', '###0', '', '', None, '', None, 0),
- (' ', '+', ' ', '###0', '', '', None, '', None, 0)))
+ ((' ', '+', ' ', '###0', '', '', None, '', None, ()),
+ (' ', '+', ' ', '###0', '', '', None, '', None, ())))
self.assertEqual(
parseNumberPattern('* +* ###0.0##'),
- ((' ', '+', ' ', '###0', '0##', '', None, '', None, 0),
- (' ', '+', ' ', '###0', '0##', '', None, '', None, 0)))
+ ((' ', '+', ' ', '###0', '0##', '', None, '', None, ()),
+ (' ', '+', ' ', '###0', '0##', '', None, '', None, ())))
self.assertEqual(
parseNumberPattern('* +* ###0.0##;*_-*_###0.0##'),
- ((' ', '+', ' ', '###0', '0##', '', None, '', None, 0),
- ('_', '-', '_', '###0', '0##', '', None, '', None, 0)))
+ ((' ', '+', ' ', '###0', '0##', '', None, '', None, ()),
+ ('_', '-', '_', '###0', '0##', '', None, '', None, ())))
- def testParsePadding3WithoutSufffixPattern(self):
+ def testParsePadding3WithoutSuffixPattern(self):
self.assertEqual(
parseNumberPattern('###0* '),
- ((None, '', None, '###0', '', '', ' ', '', None, 0),
- (None, '', None, '###0', '', '', ' ', '', None, 0)))
+ ((None, '', None, '###0', '', '', ' ', '', None, ()),
+ (None, '', None, '###0', '', '', ' ', '', None, ())))
self.assertEqual(
parseNumberPattern('###0.0##* '),
- ((None, '', None, '###0', '0##', '', ' ', '', None, 0),
- (None, '', None, '###0', '0##', '', ' ', '', None, 0)))
+ ((None, '', None, '###0', '0##', '', ' ', '', None, ()),
+ (None, '', None, '###0', '0##', '', ' ', '', None, ())))
self.assertEqual(
parseNumberPattern('###0.0##* ;###0.0##*_'),
- ((None, '', None, '###0', '0##', '', ' ', '', None, 0),
- (None, '', None, '###0', '0##', '', '_', '', None, 0)))
+ ((None, '', None, '###0', '0##', '', ' ', '', None, ()),
+ (None, '', None, '###0', '0##', '', '_', '', None, ())))
def testParsePadding3InScientificPattern(self):
self.assertEqual(
parseNumberPattern('###0E#0* '),
- ((None, '', None, '###0', '', '#0', ' ', '', None, 0),
- (None, '', None, '###0', '', '#0', ' ', '', None, 0)))
+ ((None, '', None, '###0', '', '#0', ' ', '', None, ()),
+ (None, '', None, '###0', '', '#0', ' ', '', None, ())))
self.assertEqual(
parseNumberPattern('###0.0##E0* '),
- ((None, '', None, '###0', '0##', '0', ' ', '', None, 0),
- (None, '', None, '###0', '0##', '0', ' ', '', None, 0)))
+ ((None, '', None, '###0', '0##', '0', ' ', '', None, ()),
+ (None, '', None, '###0', '0##', '0', ' ', '', None, ())))
self.assertEqual(
parseNumberPattern('###0.0##E#0* ;###0.0##E0*_'),
- ((None, '', None, '###0', '0##', '#0', ' ', '', None, 0),
- (None, '', None, '###0', '0##', '0', '_', '', None, 0)))
+ ((None, '', None, '###0', '0##', '#0', ' ', '', None, ()),
+ (None, '', None, '###0', '0##', '0', '_', '', None, ())))
def testParsePadding3WithSufffixPattern(self):
self.assertEqual(
parseNumberPattern('###0* /'),
- ((None, '', None, '###0', '', '', ' ', '/', None, 0),
- (None, '', None, '###0', '', '', ' ', '/', None, 0)))
+ ((None, '', None, '###0', '', '', ' ', '/', None, ()),
+ (None, '', None, '###0', '', '', ' ', '/', None, ())))
self.assertEqual(
parseNumberPattern('###0.0#* /'),
- ((None, '', None, '###0', '0#', '', ' ', '/', None, 0),
- (None, '', None, '###0', '0#', '', ' ', '/', None, 0)))
+ ((None, '', None, '###0', '0#', '', ' ', '/', None, ()),
+ (None, '', None, '###0', '0#', '', ' ', '/', None, ())))
self.assertEqual(
parseNumberPattern('###0.0#* /;###0.0#*_/'),
- ((None, '', None, '###0', '0#', '', ' ', '/', None, 0),
- (None, '', None, '###0', '0#', '', '_', '/', None, 0)))
+ ((None, '', None, '###0', '0#', '', ' ', '/', None, ()),
+ (None, '', None, '###0', '0#', '', '_', '/', None, ())))
def testParsePadding3And4WithSuffixPattern(self):
self.assertEqual(
parseNumberPattern('###0* /* '),
- ((None, '', None, '###0', '', '', ' ', '/', ' ', 0),
- (None, '', None, '###0', '', '', ' ', '/', ' ', 0)))
+ ((None, '', None, '###0', '', '', ' ', '/', ' ', ()),
+ (None, '', None, '###0', '', '', ' ', '/', ' ', ())))
self.assertEqual(
parseNumberPattern('###0* /* ;###0*_/*_'),
- ((None, '', None, '###0', '', '', ' ', '/', ' ', 0),
- (None, '', None, '###0', '', '', '_', '/', '_', 0)))
+ ((None, '', None, '###0', '', '', ' ', '/', ' ', ()),
+ (None, '', None, '###0', '', '', '_', '/', '_', ())))
def testParseMultipleCharacterPrefix(self):
self.assertEqual(
parseNumberPattern('DM###0'),
- ((None, 'DM', None, '###0', '', '', None, '', None, 0),
- (None, 'DM', None, '###0', '', '', None, '', None, 0)))
+ ((None, 'DM', None, '###0', '', '', None, '', None, ()),
+ (None, 'DM', None, '###0', '', '', None, '', None, ())))
self.assertEqual(
parseNumberPattern('DM* ###0'),
- ((None, 'DM', ' ', '###0', '', '', None, '', None, 0),
- (None, 'DM', ' ', '###0', '', '', None, '', None, 0)))
+ ((None, 'DM', ' ', '###0', '', '', None, '', None, ()),
+ (None, 'DM', ' ', '###0', '', '', None, '', None, ())))
def testParseStringEscapedPrefix(self):
self.assertEqual(
parseNumberPattern("'DEM'###0"),
- ((None, 'DEM', None, '###0', '', '', None, '', None, 0),
- (None, 'DEM', None, '###0', '', '', None, '', None, 0)))
+ ((None, 'DEM', None, '###0', '', '', None, '', None, ()),
+ (None, 'DEM', None, '###0', '', '', None, '', None, ())))
self.assertEqual(
parseNumberPattern("D'EM'###0"),
- ((None, 'DEM', None, '###0', '', '', None, '', None, 0),
- (None, 'DEM', None, '###0', '', '', None, '', None, 0)))
+ ((None, 'DEM', None, '###0', '', '', None, '', None, ()),
+ (None, 'DEM', None, '###0', '', '', None, '', None, ())))
self.assertEqual(
parseNumberPattern("D'E'M###0"),
- ((None, 'DEM', None, '###0', '', '', None, '', None, 0),
- (None, 'DEM', None, '###0', '', '', None, '', None, 0)))
+ ((None, 'DEM', None, '###0', '', '', None, '', None, ()),
+ (None, 'DEM', None, '###0', '', '', None, '', None, ())))
def testParseStringEscapedSuffix(self):
self.assertEqual(
parseNumberPattern("###0'DEM'"),
- ((None, '', None, '###0', '', '', None, 'DEM', None, 0),
- (None, '', None, '###0', '', '', None, 'DEM', None, 0)))
+ ((None, '', None, '###0', '', '', None, 'DEM', None, ()),
+ (None, '', None, '###0', '', '', None, 'DEM', None, ())))
self.assertEqual(
parseNumberPattern("###0D'EM'"),
- ((None, '', None, '###0', '', '', None, 'DEM', None, 0),
- (None, '', None, '###0', '', '', None, 'DEM', None, 0)))
+ ((None, '', None, '###0', '', '', None, 'DEM', None, ()),
+ (None, '', None, '###0', '', '', None, 'DEM', None, ())))
self.assertEqual(
parseNumberPattern("###0D'E'M"),
- ((None, '', None, '###0', '', '', None, 'DEM', None, 0),
- (None, '', None, '###0', '', '', None, 'DEM', None, 0)))
+ ((None, '', None, '###0', '', '', None, 'DEM', None, ()),
+ (None, '', None, '###0', '', '', None, 'DEM', None, ())))
def testParseInvalidBegin(self):
with self.assertRaisesRegex(NumberPatternParseError,
"Wrong syntax at beginning"):
parseNumberPattern(".")
- def testParseFractionQuate(self):
+ def testParseFractionQuote(self):
pattern, neg_pattern = parseNumberPattern("0.'")
self.assertEqual(
- (None, '', None, '0', '', '', None, '', None, 0),
+ (None, '', None, '0', '', '', None, '', None, ()),
pattern)
self.assertEqual(
- (None, '', None, '0', '', '', None, '', None, 0),
+ (None, '', None, '0', '', '', None, '', None, ()),
neg_pattern)
def testParseExponentialQuote(self):
pattern, neg_pattern = parseNumberPattern("0E'")
self.assertEqual(
- (None, '', None, '0', '', '', None, '', None, 0),
+ (None, '', None, '0', '', '', None, '', None, ()),
pattern)
self.assertEqual(
- (None, '', None, '0', '', '', None, '', None, 0),
+ (None, '', None, '0', '', '', None, '', None, ()),
neg_pattern)
def testParseExponentialNumber(self):
pattern, neg_pattern = parseNumberPattern("0E1")
self.assertEqual(
- (None, '', None, '0', '', '', None, '1', None, 0),
+ (None, '', None, '0', '', '', None, '1', None, ()),
pattern)
self.assertEqual(
- (None, '', None, '0', '', '', None, '1', None, 0),
+ (None, '', None, '0', '', '', None, '1', None, ()),
neg_pattern)
class TestNumberFormat(_TestCase):
@@ -1199,14 +1301,30 @@ class TestNumberFormat(_TestCase):
'-2.3341E04')
def testFormatThousandSeparatorInteger(self):
- self.assertEqual(self.format.format(23341, '+#,##0;-#,##0'),
- '+23,341')
- self.assertEqual(self.format.format(-23341, '+#,##0;-#,##0'),
- '-23,341')
- self.assertEqual(self.format.format(41, '+#0,000;-#0,000'),
- '+0,041')
- self.assertEqual(self.format.format(-41, '+#0,000;-#0,000'),
- '-0,041')
+ self.assertEqual(
+ self.format.format(23341, '+#,##0;-#,##0'),
+ '+23,341')
+ self.assertEqual(
+ self.format.format(-23341, '+#,##0;-#,##0'),
+ '-23,341')
+ self.assertEqual(
+ self.format.format(41, '+#0,000;-#0,000'),
+ '+0,041')
+ self.assertEqual(
+ self.format.format(-41, '+#0,000;-#0,000'),
+ '-0,041')
+ self.assertEqual(
+ self.format.format(987654321, '+#,##0;-#,##0'),
+ '+987,654,321')
+ self.assertEqual(
+ self.format.format(-987654321, '+#,##0;-#,##0'),
+ '-987,654,321')
+ self.assertEqual(
+ self.format.format(987654321, '+#,##,#0,000;-#,##,#0,000'),
+ '+98,76,54,321')
+ self.assertEqual(
+ self.format.format(-987654321, '+#,##,#0,000;-#,##,#0,000'),
+ '-98,76,54,321')
def testFormatDecimal(self):
self.assertEqual(self.format.format(23341.02357, '###0.0#'),