[Python-Dev] decimal.py signals & traps

David Goodger goodger at python.org
Thu Jul 8 03:55:11 CEST 2004


There's a problem in the decimal.py API regarding signals & traps.  I
noticed Raymond's checkin enabling certain traps (thanks Raymond!), so
I updated my copy and played around a bit:

 >>> from decimal import Decimal
 >>> Decimal('1')/0
Traceback (most recent call last):
...
decimal.DivisionByZero: x / 0

As expected.  But:

 >>> Decimal('0')/0
Decimal("NaN")

I expected this to raise decimal.DivisionUndefined.  Even worse:

 >>> Decimal('bogus')
Decimal("NaN")

That should have raised decimal.ConversionSyntax.  This behavior
obviously doesn't agree with:

[Tim Peters]
 > You can't get a NaN or infinity from finite operands without
 > signaling one of the 3 I recommend trap-enabling, so enabling those
 > traps stops their program the instant the first NaN or infinity
 > appears.

The problem is that the implementation associates traps with what it
calls "signals" but the spec & PEP 327 call "conditions".  I believe
that led to a misunderstanding:

[Tim Peters]
 > I'm still of the opinion that the invalid-operation, overflow, and
 > division-by-zero traps should be enabled by default, and the others
 > disabled

Tim is referring to traps associated with spec/PEP-defined "signals".
Raymond implemented the default-enabled traps like this:

     _default_traps.update(
         {DivisionByZero:1, Overflow:1, InvalidOperation:1})

Take a look at the "Signal" column of the table in
<http://www.python.org/peps/pep-0327.html#exceptional-conditions>.
The "invalid-operation" *signal* is associated with 5 different
*conditions*: conversion syntax, division impossible, division
undefined, invalid context, and invalid operation.  The spec/PEP lists
12 conditions and 8 signals, but

 >>> len(decimal.Signals)
13

decimal.Signals is actually a list of spec/PEP *conditions*, with
decimal.DecimalException (the base exception class) also included.

The easy solution is to change

     _default_traps.update(
         {DivisionByZero:1, Overflow:1, InvalidOperation:1})

to

     _default_traps.update(
         {DivisionByZero:1, Overflow:1, InvalidOperation:1,
          ConversionSyntax:1, DivisionImpossible:1, DivisionUndefined:1,
          InvalidContext})

But I don't think that's the best solution.  It still leaves the
mismatch between spec/PEP "signals" and implementation "signals".

Should traps be set on spec/PEP conditions, or spec/PEP signals?  If
the former, decimal.Signals should at least be renamed to
decimal.Conditions.  If the latter, decimal.py's implementation of
exceptions needs to be reworked.

-- 
David Goodger <http://python.net/~goodger>


More information about the Python-Dev mailing list