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

inherits from TypeError. Cleanup in module initialization to make repeated
import failures robust.
This commit is contained in:
Stefan Krah 2012-03-23 14:46:48 +01:00
parent 4b0215fd99
commit b6405efd1b
4 changed files with 107 additions and 22 deletions

View File

@ -1577,7 +1577,7 @@ The following table summarizes the hierarchy of signals::
InvalidOperation
Rounded
Subnormal
FloatOperation
FloatOperation(DecimalException, exceptions.TypeError)
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View File

@ -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

View File

@ -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):

View File

@ -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 */
}