Commits

Amaury Forgeot d'Arc committed e6fb259

add decimal.Context.__repr__

Comments (0)

Files changed (6)

pypy/module/_decimal/__init__.py

     interpleveldefs = {
         'Decimal': 'interp_decimal.W_Decimal',
         'Context': 'interp_context.W_Context',
+        'DefaultContext': 'interp_context.W_Context(space)',
         'getcontext': 'interp_context.getcontext',
         'setcontext': 'interp_context.setcontext',
         'DecimalException': 'interp_signals.get(space).w_DecimalException',

pypy/module/_decimal/interp_context.py

             raise oefmt(space.w_ValueError,
                         "valid range for Emax is [0, MAX_EMAX]")
 
+    def get_capitals(self, space):
+        return space.wrap(self.capitals)
+
+    def set_capitals(self, space, w_value):
+        self.capitals = space.int_w(w_value)
+
     def get_clamp(self, space):
         return space.wrap(rmpdec.mpd_getclamp(self.ctx))
 
         return interp_decimal.decimal_from_object(
             space, None, w_value, self, exact=False)
 
+    def descr_repr(self, space):
+        # Rounding string.
+        rounding = rffi.cast(lltype.Signed, self.ctx.c_round)
+        for name, value in ROUND_CONSTANTS:
+            if value == rounding:
+                round_string = name
+                break
+        else:
+            raise oefmt(space.w_RuntimeError,
+                        "bad rounding value")
+        flags = interp_signals.flags_as_string(self.ctx.c_status)
+        traps = interp_signals.flags_as_string(self.ctx.c_traps)
+        return space.wrap("Context(prec=%s, rounding=%s, Emin=%s, Emax=%s, "
+                          "capitals=%s, clamp=%s, flags=%s, traps=%s)" % (
+                self.ctx.c_prec, round_string,
+                self.ctx.c_emin, self.ctx.c_emax,
+                self.capitals, rffi.cast(lltype.Signed, self.ctx.c_clamp),
+                flags, traps))
+
 
 def descr_new_context(space, w_subtype, __args__):
     w_result = space.allocate_instance(W_Context, w_subtype)
     traps=interp_attrproperty_w('w_traps', W_Context),
     prec=GetSetProperty(W_Context.get_prec, W_Context.set_prec),
     rounding=GetSetProperty(W_Context.get_rounding, W_Context.set_rounding),
+    capitals=GetSetProperty(W_Context.get_capitals, W_Context.set_capitals),
     Emin=GetSetProperty(W_Context.get_emin, W_Context.set_emin),
     Emax=GetSetProperty(W_Context.get_emax, W_Context.set_emax),
     clamp=GetSetProperty(W_Context.get_clamp, W_Context.set_clamp),
     #
+    __repr__ = interp2app(W_Context.descr_repr),
+    #
     copy=interp2app(W_Context.copy_w),
     create_decimal=interp2app(W_Context.create_decimal_w),
     )

pypy/module/_decimal/interp_signals.py

-from rpython.rlib import rmpdec
+from collections import OrderedDict
+from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib import rmpdec, rstring
 from rpython.rlib.unroll import unrolling_iterable
 from pypy.interpreter.error import oefmt, OperationError
 
     ('InvalidContext', rmpdec.MPD_Invalid_context),
     ])
 
+SIGNAL_STRINGS = OrderedDict([
+    (rmpdec.MPD_Clamped, "Clamped"),
+    (rmpdec.MPD_IEEE_Invalid_operation, "InvalidOperation"),
+    (rmpdec.MPD_Division_by_zero, "DivisionByZero"),
+    (rmpdec.MPD_Inexact, "Inexact"),
+    (rmpdec.MPD_Float_operation, "FloatOperation"),
+    (rmpdec.MPD_Overflow, "Overflow"),
+    (rmpdec.MPD_Rounded, "Rounded"),
+    (rmpdec.MPD_Subnormal, "Subnormal"),
+    (rmpdec.MPD_Underflow, "Underflow"),
+    ])
+
 def flags_as_exception(space, flags):
     w_exc = None
     err_list = []
     raise oefmt(space.w_KeyError,
                 "invalid error flag")
 
+def flags_as_string(flags):
+    builder = rstring.StringBuilder(30)
+    builder.append('[')
+    first = True
+    flags = rffi.cast(lltype.Signed, flags)
+    for (flag, value) in SIGNAL_STRINGS.items():
+        if flag & flags:
+            if not first:
+                builder.append(', ')
+                first = False
+            builder.append(value)
+    builder.append(']')
+    return builder.build()
+
 
 class SignalState:
     def __init__(self, space):

pypy/module/_decimal/test/test_context.py

+class AppTestContext:
+    spaceconfig = dict(usemodules=('_decimal',))
+
+    def setup_class(cls):
+        space = cls.space
+        cls.w_decimal = space.call_function(space.builtin.get('__import__'),
+                                            space.wrap("_decimal"))
+        cls.w_Decimal = space.getattr(cls.w_decimal, space.wrap("Decimal"))
+
+    def test_context_repr(self):
+        c = self.decimal.DefaultContext.copy()
+
+        c.prec = 425000000
+        c.Emax = 425000000
+        c.Emin = -425000000
+        c.rounding = self.decimal.ROUND_HALF_DOWN
+        c.capitals = 0
+        c.clamp = 1
+
+        d = self.decimal
+        OrderedSignals = [d.Clamped, d.Rounded, d.Inexact, d.Subnormal,
+                          d.Underflow, d.Overflow, d.DivisionByZero,
+                          d.InvalidOperation, d.FloatOperation]
+        for sig in OrderedSignals:
+            c.flags[sig] = False
+            c.traps[sig] = False
+
+        s = c.__repr__()
+        t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
+            "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
+            "flags=[], traps=[])"
+        assert s == t
+

pypy/module/_decimal/test/test_decimal.py

 import random
 
 class AppTestExplicitConstruction:
-    spaceconfig = dict(usemodules=('_decimal', '_random'))
+    spaceconfig = dict(usemodules=('_decimal',))
 
     def setup_class(cls):
         space = cls.space

rpython/rlib/rmpdec.py

     MPD_IEEE_CONTEXT_MAX_BITS = platform.ConstantInteger(
         'MPD_IEEE_CONTEXT_MAX_BITS')
     MPD_MAX_PREC = platform.ConstantInteger('MPD_MAX_PREC')
+    MPD_MAX_SIGNAL_LIST = platform.ConstantInteger('MPD_MAX_SIGNAL_LIST')
 
     # Flags
     MPD_POS = platform.ConstantInteger('MPD_POS')