Author: Amaury Forgeot d'Arc <[email protected]>
Branch: decimal-libmpdec
Changeset: r71454:0c0a9f75a3c7
Date: 2014-05-05 23:42 +0200
http://bitbucket.org/pypy/pypy/changeset/0c0a9f75a3c7/

Log:    Progress

diff --git a/pypy/module/_decimal/__init__.py b/pypy/module/_decimal/__init__.py
--- a/pypy/module/_decimal/__init__.py
+++ b/pypy/module/_decimal/__init__.py
@@ -5,6 +5,7 @@
 
 class Module(MixedModule):
     appleveldefs = {
+        'localcontext': 'app_context.localcontext',
         }
     
     interpleveldefs = {
diff --git a/pypy/module/_decimal/interp_context.py 
b/pypy/module/_decimal/interp_context.py
--- a/pypy/module/_decimal/interp_context.py
+++ b/pypy/module/_decimal/interp_context.py
@@ -16,17 +16,34 @@
 # initialized to new SignalDicts.
 # Once a SignalDict is tied to a context, it cannot be deleted.
 class W_SignalDictMixin(W_Root):
-    pass
+    def __init__(self, flag_ptr):
+        self.flag_ptr = flag_ptr
 
-def descr_new_signaldict(space, w_subtype):
-    w_result = space.allocate_instance(W_SignalDictMixin, w_subtype)
-    W_SignalDictMixin.__init__(w_result)
-    return w_result
+    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]))
+
+    def descr_setitem(self, space, w_key, w_value):
+        flag = interp_signals.exception_as_flag(space, w_key)
+        if space.is_true(w_value):
+            self.flag_ptr[0] |= flag
+        else:
+            self.flag_ptr[0] &= ~flag
+
+
+def new_signal_dict(space, flag_ptr):
+    w_dict = space.allocate_instance(W_SignalDictMixin,
+                                     state_get(space).W_SignalDict)
+    W_SignalDictMixin.__init__(w_dict, flag_ptr)
+    return w_dict
+
 
 W_SignalDictMixin.typedef = TypeDef(
     'SignalDictMixin',
-    __new__ = interp2app(descr_new_signaldict),
+    __getitem__ = interp2app(W_SignalDictMixin.descr_getitem),
+    __setitem__ = interp2app(W_SignalDictMixin.descr_setitem),
     )
+W_SignalDictMixin.typedef.acceptable_as_base_class = True
 
 
 class State:
@@ -54,8 +71,11 @@
         self.ctx = lltype.malloc(rmpdec.MPD_CONTEXT_PTR.TO, flavor='raw',
                                  zero=True,
                                  track_allocation=False)
-        self.w_flags = space.call_function(state_get(space).W_SignalDict)
-        self.capitals = 0
+        self.w_flags = new_signal_dict(
+            space, lltype.direct_fieldptr(self.ctx, 'c_status'))
+        self.w_traps = new_signal_dict(
+            space, lltype.direct_fieldptr(self.ctx, 'c_traps'))
+        self.capitals = 1
 
     def __del__(self):
         if self.ctx:
@@ -142,6 +162,7 @@
     'Context',
     copy=interp2app(W_Context.copy_w),
     flags=interp_attrproperty_w('w_flags', W_Context),
+    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),
     Emin=GetSetProperty(W_Context.get_emin, W_Context.set_emin),
diff --git a/pypy/module/_decimal/interp_decimal.py 
b/pypy/module/_decimal/interp_decimal.py
--- a/pypy/module/_decimal/interp_decimal.py
+++ b/pypy/module/_decimal/interp_decimal.py
@@ -5,6 +5,7 @@
 from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
 from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict,
     descr_set_dict, descr_del_dict)
+from pypy.objspace.std import unicodeobject
 from pypy.module._decimal import interp_context
 
 
@@ -80,7 +81,9 @@
 
 def decimal_from_unicode(space, w_subtype, w_value, context, exact=True,
                          strip_whitespace=True):
-    s = space.str_w(w_value)  # XXX numeric_as_ascii() is different
+    s = unicodeobject.unicode_to_decimal_w(space, w_value)
+    if '\0' in s:
+        s = ''  # empty string triggers ConversionSyntax.
     if strip_whitespace:
         s = s.strip()
     return decimal_from_cstring(space, w_subtype, s, context, exact=exact)
diff --git a/pypy/module/_decimal/interp_signals.py 
b/pypy/module/_decimal/interp_signals.py
--- a/pypy/module/_decimal/interp_signals.py
+++ b/pypy/module/_decimal/interp_signals.py
@@ -1,6 +1,6 @@
 from rpython.rlib import rmpdec
 from rpython.rlib.unroll import unrolling_iterable
-from pypy.interpreter.error import oefmt
+from pypy.interpreter.error import oefmt, OperationError
 
 SIGNAL_MAP = unrolling_iterable([
     ('InvalidOperation', rmpdec.MPD_IEEE_Invalid_operation),
@@ -31,9 +31,14 @@
     if w_exc is None:
         raise oefmt(space.w_RuntimeError,
                     "invalid error flag")
-    
-        
-    raise ValueError(hex(flags))
+    return OperationError(w_exc, space.w_None)
+
+def exception_as_flag(space, w_exc):
+    for name, flag in SIGNAL_MAP:
+        if space.is_w(w_exc, getattr(get(space), 'w_' + name)):
+            return flag
+    raise oefmt(space.w_KeyError,
+                "invalid error flag")
 
 
 class SignalState:
diff --git a/pypy/module/_decimal/test/test_decimal.py 
b/pypy/module/_decimal/test/test_decimal.py
--- a/pypy/module/_decimal/test/test_decimal.py
+++ b/pypy/module/_decimal/test/test_decimal.py
@@ -42,3 +42,51 @@
                     d = Decimal(i)
                     assert str(d) == str(i)
 
+    def test_explicit_from_string(self):
+        Decimal = self.decimal.Decimal
+        InvalidOperation = self.decimal.InvalidOperation
+        localcontext = self.decimal.localcontext
+
+        #empty
+        assert str(Decimal('')) == 'NaN'
+
+        #int
+        assert str(Decimal('45')) == '45'
+
+        #float
+        assert str(Decimal('45.34')) == '45.34'
+
+        #engineer notation
+        assert str(Decimal('45e2')) == '4.5E+3'
+
+        #just not a number
+        assert str(Decimal('ugly')) == 'NaN'
+
+        #leading and trailing whitespace permitted
+        assert str(Decimal('1.3E4 \n')) == '1.3E+4'
+        assert str(Decimal('  -7.89')) == '-7.89'
+        assert str(Decimal("  3.45679  ")) == '3.45679'
+
+        # unicode whitespace
+        for lead in ["", ' ', '\u00a0', '\u205f']:
+            for trail in ["", ' ', '\u00a0', '\u205f']:
+                assert str(Decimal(lead + '9.311E+28' + trail)) == '9.311E+28'
+
+        with localcontext() as c:
+            c.traps[InvalidOperation] = True
+            # Invalid string
+            raises(InvalidOperation, Decimal, "xyz")
+            # Two arguments max
+            raises(TypeError, Decimal, "1234", "x", "y")
+
+            # space within the numeric part
+            raises(InvalidOperation, Decimal, "1\u00a02\u00a03")
+            raises(InvalidOperation, Decimal, "\u00a01\u00a02\u00a0")
+
+            # unicode whitespace
+            raises(InvalidOperation, Decimal, "\u00a0")
+            raises(InvalidOperation, Decimal, "\u00a0\u00a0")
+
+            # embedded NUL
+            raises(InvalidOperation, Decimal, "12\u00003")
+
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to