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