Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b6405ef

Browse files
author
Stefan Krah
committed
Use the same exception hierarchy as decimal.py. FloatOperation now also
inherits from TypeError. Cleanup in module initialization to make repeated import failures robust.
1 parent 4b0215f commit b6405ef

4 files changed

Lines changed: 107 additions & 22 deletions

File tree

Doc/library/decimal.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1577,7 +1577,7 @@ The following table summarizes the hierarchy of signals::
15771577
InvalidOperation
15781578
Rounded
15791579
Subnormal
1580-
FloatOperation
1580+
FloatOperation(DecimalException, exceptions.TypeError)
15811581

15821582
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15831583

Lib/decimal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ class Underflow(Inexact, Rounded, Subnormal):
391391
In all cases, Inexact, Rounded, and Subnormal will also be raised.
392392
"""
393393

394-
class FloatOperation(DecimalException):
394+
class FloatOperation(DecimalException, TypeError):
395395
"""Enable stricter semantics for mixing floats and Decimals.
396396
397397
If the signal is not trapped (default), mixing floats and Decimals is

Lib/test/test_decimal.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2378,6 +2378,46 @@ def test_named_parameters(self):
23782378
self.assertRaises(TypeError, D("-1").copy_abs, context=xc)
23792379
self.assertRaises(TypeError, D("-1").copy_negate, context=xc)
23802380

2381+
def test_exception_hierarchy(self):
2382+
2383+
decimal = self.decimal
2384+
DecimalException = decimal.DecimalException
2385+
InvalidOperation = decimal.InvalidOperation
2386+
FloatOperation = decimal.FloatOperation
2387+
DivisionByZero = decimal.DivisionByZero
2388+
Overflow = decimal.Overflow
2389+
Underflow = decimal.Underflow
2390+
Subnormal = decimal.Subnormal
2391+
Inexact = decimal.Inexact
2392+
Rounded = decimal.Rounded
2393+
Clamped = decimal.Clamped
2394+
2395+
self.assertTrue(issubclass(DecimalException, ArithmeticError))
2396+
2397+
self.assertTrue(issubclass(InvalidOperation, DecimalException))
2398+
self.assertTrue(issubclass(FloatOperation, DecimalException))
2399+
self.assertTrue(issubclass(FloatOperation, TypeError))
2400+
self.assertTrue(issubclass(DivisionByZero, DecimalException))
2401+
self.assertTrue(issubclass(DivisionByZero, ZeroDivisionError))
2402+
self.assertTrue(issubclass(Overflow, Rounded))
2403+
self.assertTrue(issubclass(Overflow, Inexact))
2404+
self.assertTrue(issubclass(Overflow, DecimalException))
2405+
self.assertTrue(issubclass(Underflow, Inexact))
2406+
self.assertTrue(issubclass(Underflow, Rounded))
2407+
self.assertTrue(issubclass(Underflow, Subnormal))
2408+
self.assertTrue(issubclass(Underflow, DecimalException))
2409+
2410+
self.assertTrue(issubclass(Subnormal, DecimalException))
2411+
self.assertTrue(issubclass(Inexact, DecimalException))
2412+
self.assertTrue(issubclass(Rounded, DecimalException))
2413+
self.assertTrue(issubclass(Clamped, DecimalException))
2414+
2415+
self.assertTrue(issubclass(decimal.ConversionSyntax, InvalidOperation))
2416+
self.assertTrue(issubclass(decimal.DivisionImpossible, InvalidOperation))
2417+
self.assertTrue(issubclass(decimal.DivisionUndefined, InvalidOperation))
2418+
self.assertTrue(issubclass(decimal.DivisionUndefined, ZeroDivisionError))
2419+
self.assertTrue(issubclass(decimal.InvalidContext, InvalidOperation))
2420+
23812421
class CPythonAPItests(PythonAPItests):
23822422
decimal = C
23832423
class PyPythonAPItests(PythonAPItests):

Modules/_decimal/_decimal.c

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,10 @@ typedef struct {
143143
/* Top level Exception; inherits from ArithmeticError */
144144
static PyObject *DecimalException = NULL;
145145

146-
/* Exceptions that correspond to IEEE signals; inherit from DecimalException */
146+
/* Exceptions that correspond to IEEE signals */
147+
#define SUBNORMAL 5
148+
#define INEXACT 6
149+
#define ROUNDED 7
147150
#define SIGNAL_MAP_LEN 9
148151
static DecCondMap signal_map[] = {
149152
{"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL},
@@ -5403,9 +5406,38 @@ PyInit__decimal(void)
54035406
ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN));
54045407

54055408
/* Add exceptions that correspond to IEEE signals */
5406-
for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) {
5407-
ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname,
5408-
DecimalException, NULL));
5409+
for (i = SIGNAL_MAP_LEN-1; i >= 0; i--) {
5410+
PyObject *base;
5411+
5412+
cm = signal_map + i;
5413+
5414+
switch (cm->flag) {
5415+
case MPD_Float_operation:
5416+
base = PyTuple_Pack(2, DecimalException, PyExc_TypeError);
5417+
break;
5418+
case MPD_Division_by_zero:
5419+
base = PyTuple_Pack(2, DecimalException, PyExc_ZeroDivisionError);
5420+
break;
5421+
case MPD_Overflow:
5422+
base = PyTuple_Pack(2, signal_map[INEXACT].ex,
5423+
signal_map[ROUNDED].ex);
5424+
break;
5425+
case MPD_Underflow:
5426+
base = PyTuple_Pack(3, signal_map[INEXACT].ex,
5427+
signal_map[ROUNDED].ex,
5428+
signal_map[SUBNORMAL].ex);
5429+
break;
5430+
default:
5431+
base = PyTuple_Pack(1, DecimalException);
5432+
break;
5433+
}
5434+
5435+
if (base == NULL) {
5436+
goto error;
5437+
}
5438+
5439+
ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, base, NULL));
5440+
Py_DECREF(base);
54095441

54105442
/* add to module */
54115443
Py_INCREF(cm->ex);
@@ -5425,8 +5457,20 @@ PyInit__decimal(void)
54255457

54265458
/* Add remaining exceptions, inherit from InvalidOperation */
54275459
for (cm = cond_map+1; cm->name != NULL; cm++) {
5428-
ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname,
5429-
signal_map[0].ex, NULL));
5460+
PyObject *base;
5461+
if (cm->flag == MPD_Division_undefined) {
5462+
base = PyTuple_Pack(2, signal_map[0].ex, PyExc_ZeroDivisionError);
5463+
}
5464+
else {
5465+
base = PyTuple_Pack(1, signal_map[0].ex);
5466+
}
5467+
if (base == NULL) {
5468+
goto error;
5469+
}
5470+
5471+
ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, base, NULL));
5472+
Py_DECREF(base);
5473+
54305474
Py_INCREF(cm->ex);
54315475
CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex));
54325476
}
@@ -5472,6 +5516,7 @@ PyInit__decimal(void)
54725516
for (ssize_cm = ssize_constants; ssize_cm->name != NULL; ssize_cm++) {
54735517
ASSIGN_PTR(obj, PyLong_FromSsize_t(ssize_cm->val));
54745518
CHECK_INT(PyModule_AddObject(m, ssize_cm->name, obj));
5519+
obj = NULL;
54755520
}
54765521

54775522
/* Init int constants */
@@ -5488,23 +5533,23 @@ PyInit__decimal(void)
54885533

54895534

54905535
error:
5491-
Py_XDECREF(obj); /* GCOV_NOT_REACHED */
5492-
Py_XDECREF(numbers); /* GCOV_NOT_REACHED */
5493-
Py_XDECREF(Number); /* GCOV_NOT_REACHED */
5494-
Py_XDECREF(Rational); /* GCOV_NOT_REACHED */
5495-
Py_XDECREF(collections); /* GCOV_NOT_REACHED */
5496-
Py_XDECREF(MutableMapping); /* GCOV_NOT_REACHED */
5497-
Py_XDECREF(SignalTuple); /* GCOV_NOT_REACHED */
5498-
Py_XDECREF(DecimalTuple); /* GCOV_NOT_REACHED */
5536+
Py_CLEAR(obj); /* GCOV_NOT_REACHED */
5537+
Py_CLEAR(numbers); /* GCOV_NOT_REACHED */
5538+
Py_CLEAR(Number); /* GCOV_NOT_REACHED */
5539+
Py_CLEAR(Rational); /* GCOV_NOT_REACHED */
5540+
Py_CLEAR(collections); /* GCOV_NOT_REACHED */
5541+
Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */
5542+
Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */
5543+
Py_CLEAR(DecimalTuple); /* GCOV_NOT_REACHED */
54995544
#ifdef WITHOUT_THREADS
5500-
Py_XDECREF(module_context); /* GCOV_NOT_REACHED */
5545+
Py_CLEAR(module_context); /* GCOV_NOT_REACHED */
55015546
#else
5502-
Py_XDECREF(default_context_template); /* GCOV_NOT_REACHED */
5503-
Py_XDECREF(tls_context_key); /* GCOV_NOT_REACHED */
5547+
Py_CLEAR(default_context_template); /* GCOV_NOT_REACHED */
5548+
Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */
55045549
#endif
5505-
Py_XDECREF(basic_context_template); /* GCOV_NOT_REACHED */
5506-
Py_XDECREF(extended_context_template); /* GCOV_NOT_REACHED */
5507-
Py_XDECREF(m); /* GCOV_NOT_REACHED */
5550+
Py_CLEAR(basic_context_template); /* GCOV_NOT_REACHED */
5551+
Py_CLEAR(extended_context_template); /* GCOV_NOT_REACHED */
5552+
Py_CLEAR(m); /* GCOV_NOT_REACHED */
55085553

55095554
return NULL; /* GCOV_NOT_REACHED */
55105555
}

0 commit comments

Comments
 (0)