class NumberFormatError(ValueError):
"""Exception raised when a string cannot be parsed into a number."""
+ def __init__(self, message, suggestions=None):
+ super(NumberFormatError, self).__init__(message)
+ #: a list of properly formatted numbers derived from the invalid input
+ self.suggestions = suggestions
+
def parse_number(string, locale=LC_NUMERIC):
"""Parse localized number string into an integer.
parsed_alt = decimal.Decimal(string.replace(decimal_symbol, '')
.replace(group_symbol, '.'))
except decimal.InvalidOperation:
- raise NumberFormatError(
+ raise NumberFormatError((
"%r is not a properly formatted decimal number. Did you mean %r?" %
(string, proper)
- )
+ ), suggestions=[proper])
else:
proper_alt = format_decimal(parsed_alt, locale=locale, decimal_quantization=False)
- raise NumberFormatError(
+ raise NumberFormatError((
"%r is not a properly formatted decimal number. Did you mean %r? Or maybe %r?" %
(string, proper, proper_alt)
- )
+ ), suggestions=[proper, proper_alt])
return parsed
def test_parse_decimal_strict_mode(self):
# Numbers with a misplaced grouping symbol should be rejected
- with self.assertRaises(numbers.NumberFormatError):
+ with self.assertRaises(numbers.NumberFormatError) as info:
numbers.parse_decimal('11.11', locale='de', strict=True)
+ assert info.exception.suggestions == ['1.111', '11,11']
# Numbers with two misplaced grouping symbols should be rejected
- with self.assertRaises(numbers.NumberFormatError):
+ with self.assertRaises(numbers.NumberFormatError) as info:
numbers.parse_decimal('80.00.00', locale='de', strict=True)
+ assert info.exception.suggestions == ['800.000']
# Partially grouped numbers should be rejected
- with self.assertRaises(numbers.NumberFormatError):
+ with self.assertRaises(numbers.NumberFormatError) as info:
numbers.parse_decimal('2000,000', locale='en_US', strict=True)
+ assert info.exception.suggestions == ['2,000,000', '2,000']
# Numbers with duplicate grouping symbols should be rejected
- with self.assertRaises(numbers.NumberFormatError):
+ with self.assertRaises(numbers.NumberFormatError) as info:
numbers.parse_decimal('0,,000', locale='en_US', strict=True)
+ assert info.exception.suggestions == ['0']
# Properly formatted numbers should be accepted
assert str(numbers.parse_decimal('1.001', locale='de', strict=True)) == '1001'
# Trailing zeroes should be accepted