[Python-checkins] python/nondist/sandbox/decimal Decimal.py, 1.24, 1.25 test_Decimal.py, 1.19, 1.20

rhettinger at users.sourceforge.net rhettinger at users.sourceforge.net
Tue Jun 29 06:08:39 EDT 2004


Update of /cvsroot/python/python/nondist/sandbox/decimal
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10586

Modified Files:
	Decimal.py test_Decimal.py 
Log Message:
Prepare Decimal to move into the core.

* With agreement from the principal contributors, removed the BSD 
  license and added a PSF copyright.
* Remove version history.  CVS will track that now.
* Add a todo list.
* Made Decimal() == Decimal("0").
* Added pickle support for Decimal objects.
* Copy and deepcopy now return self (as all good immutables do).
* Run doctest on the docstrings.
* Group the test suites together so their results can be aggregated.
* Replaced variable names that shadowed imports or builtins (this
  excludes "divmod" which seemed to be the variable name).



Index: Decimal.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/decimal/Decimal.py,v
retrieving revision 1.24
retrieving revision 1.25
diff -C2 -d -r1.24 -r1.25
*** Decimal.py	25 Jun 2004 17:46:20 -0000	1.24
--- Decimal.py	29 Jun 2004 10:08:35 -0000	1.25
***************
*** 1,7 ****
! # Class Decimal, version 0.7.1
! # Written by Eric Price <eprice at tjhsst.edu>
! #    and Facundo Batista <facundo at taniquetil.com.ar>
! # Based on code written by Aahz (aahz at pobox.com)
! # Currently under BSD-style license (copyright 2003)
  """
  This is a stab at a decimal arithmetic module based on the decimal
--- 1,19 ----
! # Copyright (c) 2004 Python Software Foundation.
! # All rights reserved.
! 
! # Written by Eric Price <eprice at tjhsst.edu>
! #    and Facundo Batista <facundo at taniquetil.com.ar>
! #    and Raymond Hettinger <python at rcn.com>
! #    and Aahz (aahz at pobox.com)
! #    and Tim Peters
! 
! 
! # Todo:
! #    Add deepcopy and pickle support for contexts
! #    Rename to decimal.Decimal before moving into production
! #    Consider having a SimpleDecimal subclass implementing X3.274 semantics
! #    Add an __all__ attribute
! #    Improve docstrings and add more doctests
! 
  """
  This is a stab at a decimal arithmetic module based on the decimal
***************
*** 95,132 ****
  """
  
! # facundobatista:
! # 0.8.2  2004.06.24  Lot of small clean-ups from Raymond Hettinger.
! # 0.8.1  2004.06.23  Complies with immutability-near as discussed in c.l.py.
! # 0.8.0  2004.06.21  Using the updated Spec (and complies with new test cases) from
! #                    Cowlishaw. Deprecated trim and rescale. Changed __str__ and
! #                    __repr__ to return in sci format, added as_tuple(). Fixed the
! #                    initial examples. Extracted lt, gt and eq methods from context.
! #                    Added copy method to context.
! # 0.7.6  2004.06.20  More name changes. Extracted InsufficientStorage exception.
! #                    Added create_decimal to context.
! # 0.7.5  2004.06.19  Lots of name changes.
! # 0.7.4  2004.04.05  Added rdiv, rdivmod, rmod, rpow, rfloordiv special methods.
! #                    Fixed sub.
! # 0.7.3  2004.04.04  Added _convert_other method, for implicit constructions,
! #                    and more checks when constructing from tuples. Fixed
! #                    __sub__ to modify a copy of the instance.
! # 0.7.2  2004.04.02  Fixed __pow__ to run the example ok. Added from_float
! #                    method. Fixed isnan to accept empty strings.
! # 0.7.1  2004.03.08  Corrected initial examples
! 
! # eprice:
! # 0.7.0     2003.2.28  More changes.  Contexts done nicely, exponent limits
! # 0.6.0     2003.2.24  Many changes.  No exponent limits
! 
! # Aahz:
! # 0.0.8     2001.5.24  Fixed multiplication with trailing zeroes
! # 0.0.7     2001.5.23  Fixed string conversion to follow spec
! # 0.0.6     2001.5.20  Tim Peters's _floatToString()
! # 0.0.5     2001.5.20  Now with multiplication, round(), and conversions
! # 0.0.0     2001.5.18  First public release with just addition/subtraction
! 
! # To-do list:
! #
! # Cleanup, hunt and kill bugs
  
  import threading
--- 107,111 ----
  """
  
! # XXX Add an __all__ attribute
  
  import threading
***************
*** 137,141 ****
  
  #Capitals:  1E+10, not 1e10
- 
  CAPITALS = 1
  
--- 116,119 ----
***************
*** 401,404 ****
--- 379,383 ----
          return context
  
+ 
  class Decimal(object):
      """Floating point class for decimal arithmetic."""
***************
*** 406,410 ****
      __slots__ = ('_exp','_int','_sign')
  
!     def __init__(self, value, context = None):
          """Initialize the Decimal class.
  
--- 385,389 ----
      __slots__ = ('_exp','_int','_sign')
  
!     def __init__(self, value="0", context=None):
          """Initialize the Decimal class.
  
***************
*** 420,423 ****
--- 399,403 ----
          if context is None:
              context = getcontext()
+ 
          # String?
          # REs insist on real strings, so we can too.
***************
*** 448,451 ****
--- 428,432 ----
              return
  
+         ### XXX Hmm, with precision=3, Decimal(12345) fails with Decimal('12345') works
          if isinstance(value, (int,long)):
              # checking that the int or long doesn't exceed precision
***************
*** 1795,1810 ****
              return ans
  
!         copy = self._fix(context=context)
!         if copy._isinfinity():
!             return copy
  
!         if not copy:
!             return Decimal( (copy._sign, (0,), 0) )
!         end = len(copy._int)
!         exp = copy._exp
!         while copy._int[end-1] == 0:
              exp += 1
              end -= 1
!         return Decimal( (copy._sign, copy._int[:end], exp) )
  
  
--- 1776,1791 ----
              return ans
  
!         dup = self._fix(context=context)
!         if dup._isinfinity():
!             return dup
  
!         if not dup:
!             return Decimal( (dup._sign, (0,), 0) )
!         end = len(dup._int)
!         exp = dup._exp
!         while dup._int[end-1] == 0:
              exp += 1
              end -= 1
!         return Decimal( (dup._sign, dup._int[:end], exp) )
  
  
***************
*** 2110,2113 ****
--- 2091,2104 ----
      exp = property(_get_exp)
  
+     # support for pickling, copy, and deepcopy
+     def __reduce__(self):
+         return (self.__class__, (str(self),))
+ 
+     def __copy__(self):
+         return self     # I'm immutable; therefore I am my own clone
+ 
+     def __deepcopy__(self, memo):
+         return self     # My components are also immutable
+ 
  
  # get rounding method function:
***************
*** 2202,2205 ****
--- 2193,2197 ----
          """Returns Etiny (= Emin - prec + 1)"""
          return long(self.Emin - self.prec + 1)
+ 
      def Etop(self):
          """Returns maximum exponent (= Emin - prec + 1)"""
***************
*** 2375,2379 ****
              curspot -= 1
  
!     def subtract(self, list):
          """Subtract a list from the current int (in place).
  
--- 2367,2371 ----
              curspot -= 1
  
!     def subtract(self, alist):
          """Subtract a list from the current int (in place).
  
***************
*** 2384,2392 ****
  
          self.int.reverse()
!         list.reverse()
  
          carry = 0
!         for x in xrange(len(list)):
!             self.int[x] -= list[x] + carry
              if self.int[x] < 0:
                  carry = 1
--- 2376,2384 ----
  
          self.int.reverse()
!         alist.reverse()
  
          carry = 0
!         for x in xrange(len(alist)):
!             self.int[x] -= alist[x] + carry
              if self.int[x] < 0:
                  carry = 1
***************
*** 2403,2407 ****
          self.int[last+1:]=[]
          self.int.reverse()
!         list.reverse()
          return
  
--- 2395,2399 ----
          self.int[last+1:]=[]
          self.int.reverse()
!         alist.reverse()
          return
  
***************
*** 2753,2755 ****
      return "%s%se%d" % (sign, str(top), e)
  
- 
--- 2745,2746 ----

Index: test_Decimal.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/decimal/test_Decimal.py,v
retrieving revision 1.19
retrieving revision 1.20
diff -C2 -d -r1.19 -r1.20
*** test_Decimal.py	25 Jun 2004 01:30:49 -0000	1.19
--- test_Decimal.py	29 Jun 2004 10:08:35 -0000	1.20
***************
*** 1,5 ****
! # Test Cases for Decimal module, version 0.1.1
! # Written by Eric Price <eprice at tjhsst.edu>
! #    and Facundo Batista <facundo at taniquetil.com.ar>
  """
  These are the test cases for the Decimal module.
--- 1,11 ----
! # Copyright (c) 2004 Python Software Foundation.
! # All rights reserved.
! 
! # Written by Eric Price <eprice at tjhsst.edu>
! #    and Facundo Batista <facundo at taniquetil.com.ar>
! #    and Raymond Hettinger <python at rcn.com>
! #    and Aahz (aahz at pobox.com)
! #    and Tim Peters
! 
  """
  These are the test cases for the Decimal module.
***************
*** 15,43 ****
  """
  
- # 0.2.1  2004.06.23  fb: Added immutability test for operations.
- # 0.2.0  2004.06.21  fb: Using the new test cases from Cowlishaw. Deprecated trim
- #                    test case and use of result in inexact test case. Added
- #                    as_tuple() test case.
- # 0.1.9  2004.06.20  fb: More fixes because of the name changes. Added test case for
- #                    context.create_decimal().
- # 0.1.8  2004.06.19  fb: Adjusted threading test case. Taken out the immutability
- #                    test. Added tearDown method to DecimalTest class. Some fixes 
- #                    because of the name changes.
- # 0.1.7  2004.04.05  fb: Adjusted several test cases. Eliminated interaction
- #                    with float in comparations and min/max test cases.
- # 0.1.6  2004.04.04  fb: Extended explicit construction test case from tuples.
- # 0.1.5  2004.04.02  fb: Adjusted explicit construction test cases.
- # 0.1.4  2004.03.28  fb: Added Use of Context and Decimal Usability test cases.
- #                    Corrected tests using try/except/else.
- # 0.1.3  2004.03.23  fb: Added arithmetic operators test and corrected minor
- #                    method case issues.
- # 0.1.2  2004.03.20  fb: Added from_float to explicit construction test cases
- #                    and all implicit construction test cases. Also upgraded
- #                    method names to new GvR definiton.
- # 0.1.1  2004.03.11  fb: Added Explicit Construction tests
- # 0.1.0  2004.03.11  fb: Placed the structure to run separate test groups
- #
- # fb = facundobatista
- 
  from __future__ import division
  
--- 21,24 ----
***************
*** 45,51 ****
  import glob
  import os, sys
  
  from Decimal import *
! from test.test_support import TestSkipped, run_unittest
  
  
--- 26,33 ----
  import glob
  import os, sys
+ import pickle, copy
  
  from Decimal import *
! from test.test_support import TestSkipped, run_unittest, run_doctest
  
  
***************
*** 90,94 ****
  
  # Name adapter to be able to change the Decimal and Context
! # interface without changing the test files from Cowlishaw 
  nameAdapter = {'toeng':'to_eng_string',
                 'tosci':'to_sci_string',
--- 72,76 ----
  
  # Name adapter to be able to change the Decimal and Context
! # interface without changing the test files from Cowlishaw
  nameAdapter = {'toeng':'to_eng_string',
                 'tosci':'to_sci_string',
***************
*** 144,148 ****
                  #Exception raised where there shoudn't have been one.
                  self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
!                 
          return
  
--- 126,130 ----
                  #Exception raised where there shoudn't have been one.
                  self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
! 
          return
  
***************
*** 200,204 ****
          fname = nameAdapter.get(funct, funct)
          if fname == 'rescale':
!             return 
          funct = getattr(self.context, fname)
          vals = []
--- 182,186 ----
          fname = nameAdapter.get(funct, funct)
          if fname == 'rescale':
!             return
          funct = getattr(self.context, fname)
          vals = []
***************
*** 234,238 ****
                          else:
                              self.fail("Did not raise %s in %s" % (error, s))
!                         self.context.trap_enablers[error] = 0                
                  v = self.context.create_decimal(v)
              else:
--- 216,220 ----
                          else:
                              self.fail("Did not raise %s in %s" % (error, s))
!                         self.context.trap_enablers[error] = 0
                  v = self.context.create_decimal(v)
              else:
***************
*** 241,245 ****
  
          ans = FixQuotes(ans)
!         
          if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
              for error in theirexceptions:
--- 223,227 ----
  
          ans = FixQuotes(ans)
! 
          if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
              for error in theirexceptions:
***************
*** 254,258 ****
                  else:
                      self.fail("Did not raise %s in %s" % (error, s))
!                 self.context.trap_enablers[error] = 0                
          try:
              result = str(funct(*vals))
--- 236,240 ----
                  else:
                      self.fail("Did not raise %s in %s" % (error, s))
!                 self.context.trap_enablers[error] = 0
          try:
              result = str(funct(*vals))
***************
*** 490,494 ****
      def test_empty(self):
          '''Explicit construction without parameters.'''
!         self.assertRaises(TypeError, Decimal)
  
      def test_from_None(self):
--- 472,476 ----
      def test_empty(self):
          '''Explicit construction without parameters.'''
!         self.assertEqual(Decimal(), Decimal("0"))
  
      def test_from_None(self):
***************
*** 510,514 ****
          d = Decimal(-45)
          self.assertEqual(str(d), '-45')
!         
          #zero
          d = Decimal(0)
--- 492,496 ----
          d = Decimal(-45)
          self.assertEqual(str(d), '-45')
! 
          #zero
          d = Decimal(0)
***************
*** 525,529 ****
          d = Decimal('45')
          self.assertEqual(str(d), '45')
!         
          #float
          d = Decimal('45.34')
--- 507,511 ----
          d = Decimal('45')
          self.assertEqual(str(d), '45')
! 
          #float
          d = Decimal('45.34')
***************
*** 548,552 ****
          d = Decimal.from_float(-32.0)
          self.assertEqual(str(d), '-32')
!         
          #zero
          d = Decimal.from_float(0.0)
--- 530,534 ----
          d = Decimal.from_float(-32.0)
          self.assertEqual(str(d), '-32')
! 
          #zero
          d = Decimal.from_float(0.0)
***************
*** 565,573 ****
          d = Decimal.from_float(2.2)
          self.assertEqual(str(d), '2.20000000000000017763568394002504646778106689453125')
!         
          #inexact float, rounded to some positions
          d = Decimal.from_float(2.2, 16)
          self.assertEqual(str(d), '2.2000000000000002')
!         
          #inexact float, rounded to less positions
          d = Decimal.from_float(2.2, 5)
--- 547,555 ----
          d = Decimal.from_float(2.2)
          self.assertEqual(str(d), '2.20000000000000017763568394002504646778106689453125')
! 
          #inexact float, rounded to some positions
          d = Decimal.from_float(2.2, 16)
          self.assertEqual(str(d), '2.2000000000000002')
! 
          #inexact float, rounded to less positions
          d = Decimal.from_float(2.2, 5)
***************
*** 584,588 ****
          d = Decimal( (1, (4, 5), 0) )
          self.assertEqual(str(d), '-45')
!         
          #float
          d = Decimal( (0, (4, 5, 3, 4), -2) )
--- 566,570 ----
          d = Decimal( (1, (4, 5), 0) )
          self.assertEqual(str(d), '-45')
! 
          #float
          d = Decimal( (0, (4, 5, 3, 4), -2) )
***************
*** 626,630 ****
          self.assertEqual(str(e), '-45')
          self.assertNotEqual(id(d), id(e))
!         
          #zero
          d = Decimal(0)
--- 608,612 ----
          self.assertEqual(str(e), '-45')
          self.assertNotEqual(id(d), id(e))
! 
          #zero
          d = Decimal(0)
***************
*** 688,692 ****
          else:
              self.fail('Did not raised an error!')
!             
      def test_from_int(self):
          '''Implicit construction with int or long.'''
--- 670,674 ----
          else:
              self.fail('Did not raised an error!')
! 
      def test_from_int(self):
          '''Implicit construction with int or long.'''
***************
*** 704,708 ****
          else:
              self.fail('Did not raised an error!')
!        
      def test_from_string(self):
          '''Implicit construction with string.'''
--- 686,690 ----
          else:
              self.fail('Did not raised an error!')
! 
      def test_from_string(self):
          '''Implicit construction with string.'''
***************
*** 1010,1014 ****
      def test_threading(self):
          '''Test the "threading isolation" of a Context.'''
!         
          self.synchro = threading.Event()
          self.finish1 = threading.Event()
--- 992,996 ----
      def test_threading(self):
          '''Test the "threading isolation" of a Context.'''
! 
          self.synchro = threading.Event()
          self.finish1 = threading.Event()
***************
*** 1073,1088 ****
          '''Test copy and deepcopy.'''
  
-         import copy
          d = Decimal('43.24')
- 
-         #copy
          c = copy.copy(d)
!         self.assertEqual(c, d)
!         self.assertNotEqual(id(c), id(d))
! 
!         #deepcopy
          dc = copy.deepcopy(d)
!         self.assertEqual(dc, d)
!         self.assertNotEqual(id(dc), id(d))
  
      def test_hash_method(self):
--- 1055,1063 ----
          '''Test copy and deepcopy.'''
  
          d = Decimal('43.24')
          c = copy.copy(d)
!         self.assertEqual(id(c), id(d))
          dc = copy.deepcopy(d)
!         self.assertEqual(id(dc), id(d))
  
      def test_hash_method(self):
***************
*** 1123,1127 ****
          #as true
          self.failUnless(Decimal('0.372'))
!         
      def test_tostring_methods(self):
          '''Test str and repr methods.'''
--- 1098,1102 ----
          #as true
          self.failUnless(Decimal('0.372'))
! 
      def test_tostring_methods(self):
          '''Test str and repr methods.'''
***************
*** 1134,1138 ****
          #repr
          self.assertEqual(repr(d), 'Decimal("15.32")')
!         
      def test_tonum_methods(self):
          '''Test float, int and long methods.'''
--- 1109,1113 ----
          #repr
          self.assertEqual(repr(d), 'Decimal("15.32")')
! 
      def test_tonum_methods(self):
          '''Test float, int and long methods.'''
***************
*** 1163,1167 ****
          d = Decimal( (1, (4, 5), 0) )
          self.assertEqual(d, eval(repr(d)))
!         
          #float
          d = Decimal( (0, (4, 5, 3, 4), -2) )
--- 1138,1142 ----
          d = Decimal( (1, (4, 5), 0) )
          self.assertEqual(d, eval(repr(d)))
! 
          #float
          d = Decimal( (0, (4, 5, 3, 4), -2) )
***************
*** 1182,1186 ****
          d = Decimal(-45)
          self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
!         
          #complicated string
          d = Decimal("-4.34913534E-17")
--- 1157,1161 ----
          d = Decimal(-45)
          self.assertEqual(d.as_tuple(), (1, (4, 5), 0) )
! 
          #complicated string
          d = Decimal("-4.34913534E-17")
***************
*** 1247,1251 ****
          self.assertEqual(d1._int, b1._int)
          self.assertEqual(d1._exp, b1._exp)
!         
          checkSameDec("__abs__")
          checkSameDec("__add__", True)
--- 1222,1226 ----
          self.assertEqual(d1._int, b1._int)
          self.assertEqual(d1._exp, b1._exp)
! 
          checkSameDec("__abs__")
          checkSameDec("__add__", True)
***************
*** 1289,1295 ****
          checkSameDec("to_integral")
  
  
  
! def test_main(which=None):
      """ Execute the tests.
  
--- 1264,1276 ----
          checkSameDec("to_integral")
  
+ class DecimalPythonAPItests(unittest.TestCase):
  
+     def test_pickle(self):
+         d = Decimal('-3.141590000')
+         p = pickle.dumps(d)
+         e = pickle.loads(p)
+         self.assertEqual(d, e)
  
! def test_main(which=None, verbose=None):
      """ Execute the tests.
  
***************
*** 1298,1312 ****
      Otherwise, executes both of them.
      """
  
      if which == "Arithmetic" or which is None:
!         run_unittest(DecimalTest)
  
      if which == "Behaviour" or which is None:
!         run_unittest(DecimalExplicitConstructionTest)
!         run_unittest(DecimalImplicitConstructionTest)
!         run_unittest(DecimalArithmeticOperatorsTest)
!         run_unittest(DecimalUseOfContextTest)
!         run_unittest(DecimalUsabilityTest)
!         
      return
  
--- 1279,1300 ----
      Otherwise, executes both of them.
      """
+     test_classes = []
  
      if which == "Arithmetic" or which is None:
!         test_classes.extend([DecimalTest])
  
      if which == "Behaviour" or which is None:
!         test_classes.extend([
!             DecimalExplicitConstructionTest,
!             DecimalImplicitConstructionTest,
!             DecimalArithmeticOperatorsTest,
!             DecimalUseOfContextTest,
!             DecimalUsabilityTest,
!             DecimalPythonAPItests,
!         ])
! 
!     run_unittest(*test_classes)
!     import Decimal as DecimalModule
!     run_doctest(DecimalModule, verbose)
      return
  
***************
*** 1314,1320 ****
  if __name__ == '__main__':
      if len(sys.argv) == 1:
!         test_main()
      elif len(sys.argv) == 2:
!         test_main(sys.argv[1])
      else:
          raise ValueError, "test called with wrong arguments, use test_Decimal [Arithmetic|Behaviour]"
--- 1302,1308 ----
  if __name__ == '__main__':
      if len(sys.argv) == 1:
!         test_main(verbose=True)
      elif len(sys.argv) == 2:
!         test_main(sys.argv[1], verbose=True)
      else:
          raise ValueError, "test called with wrong arguments, use test_Decimal [Arithmetic|Behaviour]"




More information about the Python-checkins mailing list