[Python-checkins] cpython: Use the same exception hierarchy as decimal.py. FloatOperation now also

stefan.krah python-checkins at python.org
Fri Mar 23 14:49:04 CET 2012


http://hg.python.org/cpython/rev/94009b75a09d
changeset:   75899:94009b75a09d
user:        Stefan Krah <skrah at bytereef.org>
date:        Fri Mar 23 14:46:48 2012 +0100
summary:
  Use the same exception hierarchy as decimal.py. FloatOperation now also
inherits from TypeError. Cleanup in module initialization to make repeated
import failures robust.

files:
  Doc/library/decimal.rst     |   2 +-
  Lib/decimal.py              |   2 +-
  Lib/test/test_decimal.py    |  40 +++++++++++
  Modules/_decimal/_decimal.c |  85 +++++++++++++++++++-----
  4 files changed, 107 insertions(+), 22 deletions(-)


diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst
--- a/Doc/library/decimal.rst
+++ b/Doc/library/decimal.rst
@@ -1577,7 +1577,7 @@
            InvalidOperation
            Rounded
            Subnormal
-           FloatOperation
+           FloatOperation(DecimalException, exceptions.TypeError)
 
 .. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
diff --git a/Lib/decimal.py b/Lib/decimal.py
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -391,7 +391,7 @@
     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
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -2378,6 +2378,46 @@
                 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
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -143,7 +143,10 @@
 /* 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 @@
     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 @@
 
     /* 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 @@
     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 @@
 
 
 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 */
 }

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list