Commit b6405efd authored by 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.
parent 4b0215fd
......@@ -1577,7 +1577,7 @@ The following table summarizes the hierarchy of signals::
InvalidOperation
Rounded
Subnormal
FloatOperation
FloatOperation(DecimalException, exceptions.TypeError)
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
......
......@@ -391,7 +391,7 @@ class Underflow(Inexact, Rounded, Subnormal):
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.
If the signal is not trapped (default), mixing floats and Decimals is
......
......@@ -2378,6 +2378,46 @@ class PythonAPItests(unittest.TestCase):
self.assertRaises(TypeError, D("-1").copy_abs, 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):
decimal = C
class PyPythonAPItests(PythonAPItests):
......
......@@ -143,7 +143,10 @@ typedef struct {
/* Top level Exception; inherits from ArithmeticError */
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
static DecCondMap signal_map[] = {
{"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL},
......@@ -5403,9 +5406,38 @@ PyInit__decimal(void)
ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN));
/* Add exceptions that correspond to IEEE signals */
for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) {
ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname,
DecimalException, NULL));
for (i = SIGNAL_MAP_LEN-1; i >= 0; i--) {
PyObject *base;
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 */
Py_INCREF(cm->ex);
......@@ -5425,8 +5457,20 @@ PyInit__decimal(void)
/* Add remaining exceptions, inherit from InvalidOperation */
for (cm = cond_map+1; cm->name != NULL; cm++) {
ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname,
signal_map[0].ex, NULL));
PyObject *base;
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);
CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex));
}
......@@ -5472,6 +5516,7 @@ PyInit__decimal(void)
for (ssize_cm = ssize_constants; ssize_cm->name != NULL; ssize_cm++) {
ASSIGN_PTR(obj, PyLong_FromSsize_t(ssize_cm->val));
CHECK_INT(PyModule_AddObject(m, ssize_cm->name, obj));
obj = NULL;
}
/* Init int constants */
......@@ -5488,23 +5533,23 @@ PyInit__decimal(void)
error:
Py_XDECREF(obj); /* GCOV_NOT_REACHED */
Py_XDECREF(numbers); /* GCOV_NOT_REACHED */
Py_XDECREF(Number); /* GCOV_NOT_REACHED */
Py_XDECREF(Rational); /* GCOV_NOT_REACHED */
Py_XDECREF(collections); /* GCOV_NOT_REACHED */
Py_XDECREF(MutableMapping); /* GCOV_NOT_REACHED */
Py_XDECREF(SignalTuple); /* GCOV_NOT_REACHED */
Py_XDECREF(DecimalTuple); /* GCOV_NOT_REACHED */
Py_CLEAR(obj); /* GCOV_NOT_REACHED */
Py_CLEAR(numbers); /* GCOV_NOT_REACHED */
Py_CLEAR(Number); /* GCOV_NOT_REACHED */
Py_CLEAR(Rational); /* GCOV_NOT_REACHED */
Py_CLEAR(collections); /* GCOV_NOT_REACHED */
Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */
Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */
Py_CLEAR(DecimalTuple); /* GCOV_NOT_REACHED */
#ifdef WITHOUT_THREADS
Py_XDECREF(module_context); /* GCOV_NOT_REACHED */
Py_CLEAR(module_context); /* GCOV_NOT_REACHED */
#else
Py_XDECREF(default_context_template); /* GCOV_NOT_REACHED */
Py_XDECREF(tls_context_key); /* GCOV_NOT_REACHED */
Py_CLEAR(default_context_template); /* GCOV_NOT_REACHED */
Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */
#endif
Py_XDECREF(basic_context_template); /* GCOV_NOT_REACHED */
Py_XDECREF(extended_context_template); /* GCOV_NOT_REACHED */
Py_XDECREF(m); /* GCOV_NOT_REACHED */
Py_CLEAR(basic_context_template); /* GCOV_NOT_REACHED */
Py_CLEAR(extended_context_template); /* GCOV_NOT_REACHED */
Py_CLEAR(m); /* 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