summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Krah <skrah@bytereef.org>2012-03-23 13:46:48 (GMT)
committerStefan Krah <skrah@bytereef.org>2012-03-23 13:46:48 (GMT)
commitb6405efd1bf8031fc3f15fbeba4f0e048844a50d (patch)
treeb78f15d0ea428616cd0158317b56fac671f5921d
parent4b0215fd997cbdc714cb7515e121be96b9087cf4 (diff)
downloadcpython-b6405efd1bf8031fc3f15fbeba4f0e048844a50d.zip
cpython-b6405efd1bf8031fc3f15fbeba4f0e048844a50d.tar.gz
cpython-b6405efd1bf8031fc3f15fbeba4f0e048844a50d.tar.bz2
Use the same exception hierarchy as decimal.py. FloatOperation now also
inherits from TypeError. Cleanup in module initialization to make repeated import failures robust.
-rw-r--r--Doc/library/decimal.rst2
-rw-r--r--Lib/decimal.py2
-rw-r--r--Lib/test/test_decimal.py40
-rw-r--r--Modules/_decimal/_decimal.c85
4 files changed, 107 insertions, 22 deletions
diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst
index 1d987b8..3fa006b 100644
--- a/Doc/library/decimal.rst
+++ b/Doc/library/decimal.rst
@@ -1577,7 +1577,7 @@ The following table summarizes the hierarchy of signals::
InvalidOperation
Rounded
Subnormal
- FloatOperation
+ FloatOperation(DecimalException, exceptions.TypeError)
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/Lib/decimal.py b/Lib/decimal.py
index b6f66ab..6bd655b 100644
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -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
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index af31b38..4a352e5 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -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):
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
index ad37092..aa39de1 100644
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -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 */
}