Kaydet (Commit) b6405efd authored tarafından Stefan Krah's avatar Stefan Krah

Use the same exception hierarchy as decimal.py. FloatOperation now also

inherits from TypeError. Cleanup in module initialization to make repeated
import failures robust.
üst 4b0215fd
...@@ -1577,7 +1577,7 @@ The following table summarizes the hierarchy of signals:: ...@@ -1577,7 +1577,7 @@ The following table summarizes the hierarchy of signals::
InvalidOperation InvalidOperation
Rounded Rounded
Subnormal Subnormal
FloatOperation FloatOperation(DecimalException, exceptions.TypeError)
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
......
...@@ -391,7 +391,7 @@ class Underflow(Inexact, Rounded, Subnormal): ...@@ -391,7 +391,7 @@ class Underflow(Inexact, Rounded, Subnormal):
In all cases, Inexact, Rounded, and Subnormal will also be raised. In all cases, Inexact, Rounded, and Subnormal will also be raised.
""" """
class FloatOperation(DecimalException): class FloatOperation(DecimalException, TypeError):
"""Enable stricter semantics for mixing floats and Decimals. """Enable stricter semantics for mixing floats and Decimals.
If the signal is not trapped (default), mixing floats and Decimals is If the signal is not trapped (default), mixing floats and Decimals is
......
...@@ -2378,6 +2378,46 @@ class PythonAPItests(unittest.TestCase): ...@@ -2378,6 +2378,46 @@ class PythonAPItests(unittest.TestCase):
self.assertRaises(TypeError, D("-1").copy_abs, context=xc) self.assertRaises(TypeError, D("-1").copy_abs, context=xc)
self.assertRaises(TypeError, D("-1").copy_negate, context=xc) self.assertRaises(TypeError, D("-1").copy_negate, context=xc)
def test_exception_hierarchy(self):
decimal = self.decimal
DecimalException = decimal.DecimalException
InvalidOperation = decimal.InvalidOperation
FloatOperation = decimal.FloatOperation
DivisionByZero = decimal.DivisionByZero
Overflow = decimal.Overflow
Underflow = decimal.Underflow
Subnormal = decimal.Subnormal
Inexact = decimal.Inexact
Rounded = decimal.Rounded
Clamped = decimal.Clamped
self.assertTrue(issubclass(DecimalException, ArithmeticError))
self.assertTrue(issubclass(InvalidOperation, DecimalException))
self.assertTrue(issubclass(FloatOperation, DecimalException))
self.assertTrue(issubclass(FloatOperation, TypeError))
self.assertTrue(issubclass(DivisionByZero, DecimalException))
self.assertTrue(issubclass(DivisionByZero, ZeroDivisionError))
self.assertTrue(issubclass(Overflow, Rounded))
self.assertTrue(issubclass(Overflow, Inexact))
self.assertTrue(issubclass(Overflow, DecimalException))
self.assertTrue(issubclass(Underflow, Inexact))
self.assertTrue(issubclass(Underflow, Rounded))
self.assertTrue(issubclass(Underflow, Subnormal))
self.assertTrue(issubclass(Underflow, DecimalException))
self.assertTrue(issubclass(Subnormal, DecimalException))
self.assertTrue(issubclass(Inexact, DecimalException))
self.assertTrue(issubclass(Rounded, DecimalException))
self.assertTrue(issubclass(Clamped, DecimalException))
self.assertTrue(issubclass(decimal.ConversionSyntax, InvalidOperation))
self.assertTrue(issubclass(decimal.DivisionImpossible, InvalidOperation))
self.assertTrue(issubclass(decimal.DivisionUndefined, InvalidOperation))
self.assertTrue(issubclass(decimal.DivisionUndefined, ZeroDivisionError))
self.assertTrue(issubclass(decimal.InvalidContext, InvalidOperation))
class CPythonAPItests(PythonAPItests): class CPythonAPItests(PythonAPItests):
decimal = C decimal = C
class PyPythonAPItests(PythonAPItests): class PyPythonAPItests(PythonAPItests):
......
...@@ -143,7 +143,10 @@ typedef struct { ...@@ -143,7 +143,10 @@ typedef struct {
/* Top level Exception; inherits from ArithmeticError */ /* Top level Exception; inherits from ArithmeticError */
static PyObject *DecimalException = NULL; static PyObject *DecimalException = NULL;
/* Exceptions that correspond to IEEE signals; inherit from DecimalException */ /* Exceptions that correspond to IEEE signals */
#define SUBNORMAL 5
#define INEXACT 6
#define ROUNDED 7
#define SIGNAL_MAP_LEN 9 #define SIGNAL_MAP_LEN 9
static DecCondMap signal_map[] = { static DecCondMap signal_map[] = {
{"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL},
...@@ -5403,9 +5406,38 @@ PyInit__decimal(void) ...@@ -5403,9 +5406,38 @@ PyInit__decimal(void)
ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN));
/* Add exceptions that correspond to IEEE signals */ /* Add exceptions that correspond to IEEE signals */
for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) { for (i = SIGNAL_MAP_LEN-1; i >= 0; i--) {
ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, PyObject *base;
DecimalException, NULL));
cm = signal_map + i;
switch (cm->flag) {
case MPD_Float_operation:
base = PyTuple_Pack(2, DecimalException, PyExc_TypeError);
break;
case MPD_Division_by_zero:
base = PyTuple_Pack(2, DecimalException, PyExc_ZeroDivisionError);
break;
case MPD_Overflow:
base = PyTuple_Pack(2, signal_map[INEXACT].ex,
signal_map[ROUNDED].ex);
break;
case MPD_Underflow:
base = PyTuple_Pack(3, signal_map[INEXACT].ex,
signal_map[ROUNDED].ex,
signal_map[SUBNORMAL].ex);
break;
default:
base = PyTuple_Pack(1, DecimalException);
break;
}
if (base == NULL) {
goto error;
}
ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, base, NULL));
Py_DECREF(base);
/* add to module */ /* add to module */
Py_INCREF(cm->ex); Py_INCREF(cm->ex);
...@@ -5425,8 +5457,20 @@ PyInit__decimal(void) ...@@ -5425,8 +5457,20 @@ PyInit__decimal(void)
/* Add remaining exceptions, inherit from InvalidOperation */ /* Add remaining exceptions, inherit from InvalidOperation */
for (cm = cond_map+1; cm->name != NULL; cm++) { for (cm = cond_map+1; cm->name != NULL; cm++) {
ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, PyObject *base;
signal_map[0].ex, NULL)); if (cm->flag == MPD_Division_undefined) {
base = PyTuple_Pack(2, signal_map[0].ex, PyExc_ZeroDivisionError);
}
else {
base = PyTuple_Pack(1, signal_map[0].ex);
}
if (base == NULL) {
goto error;
}
ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, base, NULL));
Py_DECREF(base);
Py_INCREF(cm->ex); Py_INCREF(cm->ex);
CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex)); CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex));
} }
...@@ -5472,6 +5516,7 @@ PyInit__decimal(void) ...@@ -5472,6 +5516,7 @@ PyInit__decimal(void)
for (ssize_cm = ssize_constants; ssize_cm->name != NULL; ssize_cm++) { for (ssize_cm = ssize_constants; ssize_cm->name != NULL; ssize_cm++) {
ASSIGN_PTR(obj, PyLong_FromSsize_t(ssize_cm->val)); ASSIGN_PTR(obj, PyLong_FromSsize_t(ssize_cm->val));
CHECK_INT(PyModule_AddObject(m, ssize_cm->name, obj)); CHECK_INT(PyModule_AddObject(m, ssize_cm->name, obj));
obj = NULL;
} }
/* Init int constants */ /* Init int constants */
...@@ -5488,23 +5533,23 @@ PyInit__decimal(void) ...@@ -5488,23 +5533,23 @@ PyInit__decimal(void)
error: error:
Py_XDECREF(obj); /* GCOV_NOT_REACHED */ Py_CLEAR(obj); /* GCOV_NOT_REACHED */
Py_XDECREF(numbers); /* GCOV_NOT_REACHED */ Py_CLEAR(numbers); /* GCOV_NOT_REACHED */
Py_XDECREF(Number); /* GCOV_NOT_REACHED */ Py_CLEAR(Number); /* GCOV_NOT_REACHED */
Py_XDECREF(Rational); /* GCOV_NOT_REACHED */ Py_CLEAR(Rational); /* GCOV_NOT_REACHED */
Py_XDECREF(collections); /* GCOV_NOT_REACHED */ Py_CLEAR(collections); /* GCOV_NOT_REACHED */
Py_XDECREF(MutableMapping); /* GCOV_NOT_REACHED */ Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */
Py_XDECREF(SignalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */
Py_XDECREF(DecimalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(DecimalTuple); /* GCOV_NOT_REACHED */
#ifdef WITHOUT_THREADS #ifdef WITHOUT_THREADS
Py_XDECREF(module_context); /* GCOV_NOT_REACHED */ Py_CLEAR(module_context); /* GCOV_NOT_REACHED */
#else #else
Py_XDECREF(default_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(default_context_template); /* GCOV_NOT_REACHED */
Py_XDECREF(tls_context_key); /* GCOV_NOT_REACHED */ Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */
#endif #endif
Py_XDECREF(basic_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(basic_context_template); /* GCOV_NOT_REACHED */
Py_XDECREF(extended_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(extended_context_template); /* GCOV_NOT_REACHED */
Py_XDECREF(m); /* GCOV_NOT_REACHED */ Py_CLEAR(m); /* GCOV_NOT_REACHED */
return NULL; /* GCOV_NOT_REACHED */ return NULL; /* GCOV_NOT_REACHED */
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment