Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8d23829

Browse files
committed
Merged revisions 74279 via svnmerge from
svn+ssh://pythondev@www.python.org/python/branches/py3k ........ r74279 | mark.dickinson | 2009-08-02 11:14:23 +0100 (Sun, 02 Aug 2009) | 1 line Issue #6595: Allow Decimal constructor to accept non-European decimal digits, as recommended by the specification. ........
1 parent e634d87 commit 8d23829

4 files changed

Lines changed: 28 additions & 20 deletions

File tree

Doc/library/decimal.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,11 @@ Decimal objects
324324
numeric-value ::= decimal-part [exponent-part] | infinity
325325
numeric-string ::= [sign] numeric-value | [sign] nan
326326

327+
Other Unicode decimal digits are also permitted where ``digit``
328+
appears above. These include decimal digits from various other
329+
alphabets (for example, Arabic-Indic and Devanāgarī digits) along
330+
with the fullwidth digits ``'\uff10'`` through ``'\uff19'``.
331+
327332
If *value* is a :class:`tuple`, it should have three components, a sign
328333
(:const:`0` for positive or :const:`1` for negative), a :class:`tuple` of
329334
digits, and an integer exponent. For example, ``Decimal((0, (1, 4, 1, 4), -3))``

Lib/decimal.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -554,20 +554,16 @@ def __new__(cls, value="0", context=None):
554554
intpart = m.group('int')
555555
if intpart is not None:
556556
# finite number
557-
fracpart = m.group('frac')
557+
fracpart = m.group('frac') or ''
558558
exp = int(m.group('exp') or '0')
559-
if fracpart is not None:
560-
self._int = (intpart+fracpart).lstrip('0') or '0'
561-
self._exp = exp - len(fracpart)
562-
else:
563-
self._int = intpart.lstrip('0') or '0'
564-
self._exp = exp
559+
self._int = str(int(intpart+fracpart))
560+
self._exp = exp - len(fracpart)
565561
self._is_special = False
566562
else:
567563
diag = m.group('diag')
568564
if diag is not None:
569565
# NaN
570-
self._int = diag.lstrip('0')
566+
self._int = str(int(diag or '0')).lstrip('0')
571567
if m.group('signal'):
572568
self._exp = 'N'
573569
else:
@@ -5482,26 +5478,23 @@ def _convert_other(other, raiseit=False):
54825478
# 2. For finite numbers (not infinities and NaNs) the body of the
54835479
# number between the optional sign and the optional exponent must have
54845480
# at least one decimal digit, possibly after the decimal point. The
5485-
# lookahead expression '(?=[0-9]|\.[0-9])' checks this.
5486-
#
5487-
# As the flag UNICODE is not enabled here, we're explicitly avoiding any
5488-
# other meaning for \d than the numbers [0-9].
5481+
# lookahead expression '(?=\d|\.\d)' checks this.
54895482

54905483
import re
54915484
_parser = re.compile(r""" # A numeric string consists of:
54925485
# \s*
54935486
(?P<sign>[-+])? # an optional sign, followed by either...
54945487
(
5495-
(?=[0-9]|\.[0-9]) # ...a number (with at least one digit)
5496-
(?P<int>[0-9]*) # having a (possibly empty) integer part
5497-
(\.(?P<frac>[0-9]*))? # followed by an optional fractional part
5498-
(E(?P<exp>[-+]?[0-9]+))? # followed by an optional exponent, or...
5488+
(?=\d|\.\d) # ...a number (with at least one digit)
5489+
(?P<int>\d*) # having a (possibly empty) integer part
5490+
(\.(?P<frac>\d*))? # followed by an optional fractional part
5491+
(E(?P<exp>[-+]?\d+))? # followed by an optional exponent, or...
54995492
|
55005493
Inf(inity)? # ...an infinity, or...
55015494
|
55025495
(?P<signal>s)? # ...an (optionally signaling)
55035496
NaN # NaN
5504-
(?P<diag>[0-9]*) # with (possibly empty) diagnostic info.
5497+
(?P<diag>\d*) # with (possibly empty) diagnostic info.
55055498
)
55065499
# \s*
55075500
\Z

Lib/test/test_decimal.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,9 +425,6 @@ def test_explicit_from_string(self):
425425
self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
426426
self.assertEqual(str(Decimal(' -7.89')), '-7.89')
427427

428-
#but alternate unicode digits should not
429-
self.assertEqual(str(Decimal('\uff11')), 'NaN')
430-
431428
def test_explicit_from_tuples(self):
432429

433430
#zero
@@ -534,6 +531,15 @@ def test_explicit_context_create_decimal(self):
534531
d = nc.create_decimal(prevdec)
535532
self.assertEqual(str(d), '5.00E+8')
536533

534+
def test_unicode_digits(self):
535+
test_values = {
536+
'\uff11': '1',
537+
'\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
538+
'-nan\u0c68\u0c6a\u0c66\u0c66' : '-NaN2400',
539+
}
540+
for input, expected in test_values.items():
541+
self.assertEqual(str(Decimal(input)), expected)
542+
537543

538544
class DecimalImplicitConstructionTest(unittest.TestCase):
539545
'''Unit tests for Implicit Construction cases of Decimal.'''

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ C-API
4242
Library
4343
-------
4444

45+
- Issue #6595: The Decimal constructor now allows arbitrary Unicode
46+
decimal digits in input, as recommended by the standard. Previously
47+
it was restricted to accepting [0-9].
48+
4549
- Issues #5155, #5313, #5331: multiprocessing.Process._bootstrap was
4650
unconditionally calling "os.close(sys.stdin.fileno())" resulting in file
4751
descriptor errors

0 commit comments

Comments
 (0)