# [Python-ideas] Should decimal.InvalidOperation subclass ValueError?

Steven D'Aprano steve at pearwood.info
Sun May 22 04:45:58 EDT 2016

```On the tutor mailing list, somebody asked a question about
decimal.InvalidOperation. They were converting strings to Decimal using
something like this:

try:
d = Decimal(the_string)
except ValueError:
handle_error()

and were perplexed by the error that they got:

decimal.InvalidOperation: [<class 'decimal.ConversionSyntax'>]

This got me thinking. Normally, such a conversion error should raise
ValueError, as ints, floats and Fractions do. Presumably decimal does
something different as it must match the General Decimal Arithmetic
Specification. But, is there any reason why InvalidOperation couldn't be
a subclass of ValueError? Exception class hierarchies are not part of
the GDAS, so this should be allowed.

Looking at the docs, there are nine examples given of things which can
raise InvalidOperation (if not trapped, in which case they return a
NAN):

Infinity - Infinity
0 * Infinity
Infinity / Infinity
x % 0
Infinity % x
sqrt(-x) and x > 0
0 ** 0
x ** (non-integer)
x ** Infinity

plus invalid string conversion. To my mind, ValueError would be an
acceptable error for all of these things. E.g. the root of a negative
value raises ValueError in Python 2:

>>> (-2.0)**0.5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: negative number cannot be raised to a fractional power

(In Python 3, it returns a complex number.)

So I propose that InvalidOperation be changed to inherit from
ValueError, to match the expected behaviour from other numeric types.

The only tricky bit is that division by zero doesn't raise ValueError,
but DivideByZeroError instead. But that's no worse than the current
situation:

# current
- people expect Decimal(1)/0 to raise DivideByZeroError, but it
raises InvalidOperation;

# proposal
- people expect Decimal(1)/0 to raise DivideByZero, but it
raises InvalidOperation (subclass of ValueError).

Oh, a further data point: if you pass an invalid list or tuple to
Decimal, you get a ValueError:

py> decimal.Decimal([])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: argument must be a sequence of length 3

Thoughts?

--
Steve
```