]> granicus.if.org Git - python/commitdiff
Issue 1780: Allow leading and trailing whitespace in Decimal constructor,
authorMark Dickinson <dickinsm@gmail.com>
Sat, 12 Jan 2008 01:56:00 +0000 (01:56 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Sat, 12 Jan 2008 01:56:00 +0000 (01:56 +0000)
when constructing from a string. Disallow trailing newlines in
Context.create_decimal.

Doc/library/decimal.rst
Lib/decimal.py
Lib/test/test_decimal.py
Misc/NEWS

index eda09e47fb815482e011e5d007b7d432d7b003a6..7b8580685522a358eedb360bb8a2636fcba17bfe 100644 (file)
@@ -281,9 +281,10 @@ Decimal objects
 
    Construct a new :class:`Decimal` object based from *value*.
 
-   *value* can be an integer, string, tuple, or another :class:`Decimal` object. If
-   no *value* is given, returns ``Decimal("0")``.  If *value* is a string, it
-   should conform to the decimal numeric string syntax::
+   *value* can be an integer, string, tuple, or another :class:`Decimal`
+   object. If no *value* is given, returns ``Decimal("0")``.  If *value* is a
+   string, it should conform to the decimal numeric string syntax after leading
+   and trailing whitespace characters are removed::
 
       sign           ::=  '+' | '-'
       digit          ::=  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
@@ -313,6 +314,10 @@ Decimal objects
 
    Once constructed, :class:`Decimal` objects are immutable.
 
+   .. versionchanged:: 2.6
+      leading and trailing whitespace characters are permitted when
+      creating a Decimal instance from a string.
+
 Decimal floating point objects share many properties with the other built-in
 numeric types such as :class:`float` and :class:`int`.  All of the usual math
 operations and special methods apply.  Likewise, decimal objects can be copied,
@@ -973,6 +978,9 @@ method.  For example, ``C.exp(x)`` is equivalent to
       >>> Decimal("3.4445") + Decimal(0) + Decimal("1.0023")
       Decimal("4.44")
 
+   This method implements the to-number operation of the IBM
+   specification.  If the argument is a string, no leading or trailing
+   whitespace is permitted.
 
 .. method:: Context.Etiny()
 
index 8b548216143486ba7f21543adba4e6492c3759e0..7e24516179190773661707f5cd2a15419c303b23 100644 (file)
@@ -523,6 +523,8 @@ class Decimal(object):
         Decimal("314")
         >>> Decimal(Decimal(314))        # another decimal instance
         Decimal("314")
+        >>> Decimal('  3.14  \\n')        # leading and trailing whitespace okay
+        Decimal("3.14")
         """
 
         # Note that the coefficient, self._int, is actually stored as
@@ -538,7 +540,7 @@ class Decimal(object):
         # From a string
         # REs insist on real strings, so we can too.
         if isinstance(value, basestring):
-            m = _parser(value)
+            m = _parser(value.strip())
             if m is None:
                 if context is None:
                     context = getcontext()
@@ -3533,7 +3535,16 @@ class Context(object):
         return rounding
 
     def create_decimal(self, num='0'):
-        """Creates a new Decimal instance but using self as context."""
+        """Creates a new Decimal instance but using self as context.
+
+        This method implements the to-number operation of the
+        IBM Decimal specification."""
+
+        if isinstance(num, basestring) and num != num.strip():
+            return self._raise_error(ConversionSyntax,
+                                     "no trailing or leading whitespace is "
+                                     "permitted.")
+
         d = Decimal(num, context=self)
         if d._isnan() and len(d._int) > self.prec - self._clamp:
             return self._raise_error(ConversionSyntax,
@@ -5148,7 +5159,7 @@ _parser = re.compile(r"""     # A numeric string consists of:
         (?P<diag>\d*)         # with (possibly empty) diagnostic information.
     )
 #    \s*
-    $
+    \Z
 """, re.VERBOSE | re.IGNORECASE).match
 
 _all_zeros = re.compile('0*$').match
index 03cff604bb0a1b3e2d0211b0a909879e418a6d29..2135637e9d87bd40c3864b6d24da570b84917158 100644 (file)
@@ -429,6 +429,10 @@ class DecimalExplicitConstructionTest(unittest.TestCase):
         #just not a number
         self.assertEqual(str(Decimal('ugly')), 'NaN')
 
+        #leading and trailing whitespace permitted
+        self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
+        self.assertEqual(str(Decimal('  -7.89')), '-7.89')
+
     def test_explicit_from_tuples(self):
 
         #zero
@@ -517,6 +521,10 @@ class DecimalExplicitConstructionTest(unittest.TestCase):
         self.assertEqual(str(d), '456789')
         d = nc.create_decimal('456789')
         self.assertEqual(str(d), '4.57E+5')
+        # leading and trailing whitespace should result in a NaN;
+        # spaces are already checked in Cowlishaw's test-suite, so
+        # here we just check that a trailing newline results in a NaN
+        self.assertEqual(str(nc.create_decimal('3.14\n')), 'NaN')
 
         # from tuples
         d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
index e625c3c9cde39e6cb37e5498e2102f94c5192268..51d27315ff6eb5c9d421d49416e1707f961da3f0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -351,6 +351,10 @@ Core and builtins
 Library
 -------
 
+- Issue #1780: The Decimal constructor now accepts arbitrary leading
+  and trailing whitespace when constructing from a string.
+  Context.create_decimal no longer accepts trailing newlines.
+
 - Decimal.as_tuple(), difflib.find_longest_match() and inspect functions
   that returned a tuple now return a named tuple.