Commits

Amaury Forgeot d'Arc committed 8667f0d

Decimal: More tests, more constructors.

  • Participants
  • Parent commits c80a6eb
  • Branches decimal-libmpdec

Comments (0)

Files changed (5)

File pypy/module/_decimal/interp_context.py

 
     def descr_getitem(self, space, w_key):
         flag = interp_signals.exception_as_flag(space, w_key)
-        return space.wrap(bool(flag & self.flag_ptr[0]))
+        cur_flag = rffi.cast(lltype.Signed, self.flag_ptr[0])
+        return space.wrap(bool(flag & cur_flag))
 
     def descr_setitem(self, space, w_key, w_value):
         flag = interp_signals.exception_as_flag(space, w_key)
+        cur_flag = rffi.cast(lltype.Signed, self.flag_ptr[0])
         if space.is_true(w_value):
-            self.flag_ptr[0] |= flag
+            self.flag_ptr[0] = rffi.cast(rffi.UINT, cur_flag | flag)
         else:
-            self.flag_ptr[0] &= ~flag
+            self.flag_ptr[0] = rffi.cast(rffi.UINT, cur_flag & ~flag)
 
 
 def new_signal_dict(space, flag_ptr):

File pypy/module/_decimal/interp_decimal.py

         if self.data:
             lltype.free(self.data, flavor='raw')
 
+    def apply(self, context, w_subtype=None):
+        # Apply the context to the input operand. Return a new W_Decimal.
+        if subtype:
+            w_result = space.allocate_instance(W_Decimal, w_subtype)
+            W_Decimal.__init__(w_result, space)
+        else:
+            w_result = W_Decimal(space)
+        with lltype.scoped_alloc(rffi.CArrayPtr(rffi.UINT).TO, 1) as status_ptr:
+            rpmdec.mpd_qcopy(w_result.mpd, self.mpd, status_ptr)
+            context.addstatus(self.space, status_ptr[0])
+            rpmdec.mpd_qfinalize(w_result.mpd, context.ctx, status_ptr)
+            context.addstatus(self.space, status_ptr[0])
+        return w_result
+
     def descr_str(self, space):
         context = interp_context.getcontext(space)
         with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as cp_ptr:
                 rmpdec.mpd_free(cp)
         return space.wrap(result)  # Convert bytes to unicode
 
+    def descr_bool(self, space):
+        return space.wrap(not rmpdec.mpd_iszero(self.mpd))
+
     def compare(self, space, w_other, op):
         if not isinstance(w_other, W_Decimal):  # So far
             return space.w_NotImplemented
         # special
         is_special = True
         val = space.unicode_w(w_exponent)
-        if val == 'F':
+        if val == u'F':
             builder.append('Inf')
             is_infinite = True
-        elif val == 'n':
+        elif val == u'n':
             builder.append('Nan')
-        elif val == 'N':
+        elif val == u'N':
             builder.append('sNan')
         else:
             raise oefmt(space.w_ValueError,
 
     if not digits_w and not is_special:
         # empty tuple: zero coefficient, except for special numbers
-        strval += '0'
+        builder.append('0')
     for w_digit in digits_w:
         try:
             digit = space.int_w(w_digit)
     strval = builder.build()
     return decimal_from_cstring(space, w_subtype, strval, context, exact=exact)
 
+def decimal_from_decimal(space, w_subtype, w_value, context, exact=True):
+    assert isinstance(w_value, W_Decimal)
+    if exact:
+        if space.is_w(w_subtype, space.gettypeobject(W_Decimal.typedef)):
+            return w_value
+        w_result = space.allocate_instance(W_Decimal, w_subtype)
+        W_Decimal.__init__(w_result, space)
+        with interp_context.ConvContext(
+                space, w_result.mpd, context, exact) as (ctx, status_ptr):
+            rmpdec.mpd_qcopy(w_result.mpd, w_value.mpd, status_ptr)
+        return w_result
+    else:
+        if (rmpdec.mpd_isnan(w_value.mpd) and
+            w_value.mpd.digits > (context.ctx.prec - context.ctx.clamp)):
+            # Special case: too many NaN payload digits
+            context.addstatus(space, rmpdec.MPD_Conversion_syntax)
+            w_result = space.allocate_instance(W_Decimal, w_subtype)
+            W_Decimal.__init__(w_result, space)
+            rmpdec.mpd_setspecial(w_result.mpd, rmpdec.MPD_POS, rmpdec.MPD_NAN)
+        else:
+            return w_value.apply(context)
+        
+
 def decimal_from_object(space, w_subtype, w_value, context, exact=True):
     if w_value is None:
         return decimal_from_ssize(space, w_subtype, 0, context, exact=exact)
+    elif isinstance(w_value, W_Decimal):
+        return decimal_from_decimal(space, w_subtype, w_value, context,
+                                    exact=exact)
     elif space.isinstance_w(w_value, space.w_unicode):
         return decimal_from_unicode(space, w_subtype, w_value, context,
                                     exact=exact, strip_whitespace=exact)
     'Decimal',
     __new__ = interp2app(descr_new_decimal),
     __str__ = interp2app(W_Decimal.descr_str),
+    __bool__ = interp2app(W_Decimal.descr_bool),
     __eq__ = interp2app(W_Decimal.descr_eq),
     )

File pypy/module/_decimal/test/test_decimal.py

         d = Decimal((1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25))
         assert str(d) == '-4.34913534E-17'
 
+    def test_explicit_from_bool(self):
+        Decimal = self.decimal.Decimal
+
+        assert bool(Decimal(0)) is False
+        assert bool(Decimal(1)) is True
+        assert Decimal(False) == Decimal(0)
+        assert Decimal(True) == Decimal(1)
+
+    def test_explicit_from_Decimal(self):
+        Decimal = self.decimal.Decimal
+
+        #positive
+        d = Decimal(45)
+        e = Decimal(d)
+        assert str(e) == '45'
+
+        #very large positive
+        d = Decimal(500000123)
+        e = Decimal(d)
+        assert str(e) == '500000123'
+
+        #negative
+        d = Decimal(-45)
+        e = Decimal(d)
+        assert str(e) == '-45'
+
+        #zero
+        d = Decimal(0)
+        e = Decimal(d)
+        assert str(e) == '0'
+

File pypy/module/_decimal/test/test_ztranslation.py

 
 from pypy.objspace.fake.checkmodule import checkmodule
+from pypy.module._decimal import Module
 
 def test_checkmodule():
+    Module.interpleveldefs['__hack'] = (
+        'interp_decimal.unicodeobject.W_UnicodeObject(u"")')
     checkmodule('_decimal')
 

File rpython/rlib/rmpdec.py

                            libdir.join('memory.c'),
                            ],
     export_symbols=[
-        "mpd_qset_ssize", "mpd_qset_string",
+        "mpd_qset_ssize", "mpd_qset_string", "mpd_qcopy", "mpd_setspecial",
         "mpd_getprec", "mpd_getemin",  "mpd_getemax", "mpd_getround", "mpd_getclamp",
         "mpd_qsetprec", "mpd_qsetemin",  "mpd_qsetemax", "mpd_qsetround", "mpd_qsetclamp",
         "mpd_maxcontext",
         "mpd_to_sci_size",
+        "mpd_iszero", "mpd_isnan",
         "mpd_qcmp",
         ],
     compile_extra=compile_extra,
     # Flags
     MPD_POS = platform.ConstantInteger('MPD_POS')
     MPD_NEG = platform.ConstantInteger('MPD_NEG')
+    MPD_NAN = platform.ConstantInteger('MPD_NAN')
     MPD_STATIC = platform.ConstantInteger('MPD_STATIC')
     MPD_STATIC_DATA = platform.ConstantInteger('MPD_STATIC_DATA')
 
 mpd_qimport_u32 = external(
     'mpd_qimport_u32', [MPD_PTR, rffi.UINTP, rffi.SIZE_T,
                         rffi.UCHAR, rffi.UINT, MPD_CONTEXT_PTR, rffi.UINTP], rffi.SIZE_T)
+mpd_qcopy = external(
+    'mpd_qcopy', [MPD_PTR, MPD_PTR, rffi.UINTP], rffi.INT)
+mpd_setspecial = external(
+    'mpd_setspecial', [MPD_PTR, rffi.UCHAR, rffi.UCHAR], lltype.Void)
 
 # Context operations
 mpd_getprec = external(
     'mpd_to_sci_size', [rffi.CCHARPP, MPD_PTR, rffi.INT], rffi.SSIZE_T)
 
 # Operations
+mpd_iszero = external(
+    'mpd_iszero', [MPD_PTR], rffi.INT)
+mpd_isnan = external(
+    'mpd_isnan', [MPD_PTR], rffi.INT)
 mpd_qcmp = external(
     'mpd_qcmp', [MPD_PTR, MPD_PTR, rffi.UINTP], rffi.INT)