Repository: python-babel/babel (python)

Issue:
parse_decimal is not works correctly when space symbol as grouping
```
from babel.numbers import format_decimal

format_decimal(12345.123, locale='ru')

'12\xa0345,123'
```
```
from babel.numbers import parse_decimal

parse_decimal('12 345,123', locale='ru')

babel/numbers.py", line 605, in parse_decimal
    .replace(get_decimal_symbol(locale), '.'))
decimal.InvalidOperation: [<class 'decimal.ConversionSyntax'>]
babel.numbers.NumberFormatError
```

There is a problem because ' '.replace('\xa0', '.') is not replace space to dot.

Pull request description:
parse_decimal(): Parse spaces as group separators if the group separator is nbsp
Fixes #637 

Patch:
diff --git a/babel/numbers.py b/babel/numbers.py
index e5650dd..3dcd730 100644
--- a/babel/numbers.py
+++ b/babel/numbers.py
@@ -673,6 +673,8 @@ def parse_decimal(string, locale=LC_NUMERIC, strict=False):
     Decimal('1099.98')
     >>> parse_decimal('1.099,98', locale='de')
     Decimal('1099.98')
+    >>> parse_decimal('12 345,123', locale='ru')
+    Decimal('12345.123')
 
     When the given string cannot be parsed, an exception is raised:
 
@@ -704,6 +706,15 @@ def parse_decimal(string, locale=LC_NUMERIC, strict=False):
     locale = Locale.parse(locale)
     group_symbol = get_group_symbol(locale)
     decimal_symbol = get_decimal_symbol(locale)
+
+    if not strict and (
+        group_symbol == u'\xa0' and  # if the grouping symbol is U+00A0 NO-BREAK SPACE,
+        group_symbol not in string and  # and the string to be parsed does not contain it,
+        ' ' in string  # but it does contain a space instead,
+    ):
+        # ... it's reasonable to assume it is taking the place of the grouping symbol.
+        string = string.replace(' ', group_symbol)
+
     try:
         parsed = decimal.Decimal(string.replace(group_symbol, '')
                                        .replace(decimal_symbol, '.'))
diff --git a/setup.cfg b/setup.cfg
index 4e877a3..12585f0 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -4,6 +4,8 @@ release = sdist bdist_wheel
 [tool:pytest]
 norecursedirs = venv* .* _* scripts {args}
 doctest_optionflags = ELLIPSIS NORMALIZE_WHITESPACE ALLOW_UNICODE IGNORE_EXCEPTION_DETAIL
+markers =
+    all_locales: parameterize test with all locales
 
 [bdist_wheel]
 universal = 1


Test patch:
diff --git a/tests/test_numbers.py b/tests/test_numbers.py
index 99aa96b..27649f8 100644
--- a/tests/test_numbers.py
+++ b/tests/test_numbers.py
@@ -679,3 +679,14 @@ def test_numberpattern_repr():
 def test_parse_static_pattern():
     assert numbers.parse_pattern('Kun')  # in the So locale in CLDR 30
     # TODO: static patterns might not be correctly `apply()`ed at present
+
+
+def test_parse_decimal_nbsp_heuristics():
+    # Re https://github.com/python-babel/babel/issues/637 –
+    #    for locales (of which there are many) that use U+00A0 as the group
+    #    separator in numbers, it's reasonable to assume that input strings
+    #    with plain spaces actually should have U+00A0s instead.
+    #    This heuristic is only applied when strict=False.
+    n = decimal.Decimal("12345.123")
+    assert numbers.parse_decimal("12 345.123", locale="fi") == n
+    assert numbers.parse_decimal(numbers.format_decimal(n, locale="fi"), locale="fi") == n