# Test-driven Python learning

Bugs are nice because I can learn from them. Recently I found a bug that taught me about floats in Python and how not to use them. I found it thanks to an automated test.

### The test

In a legal contract I had to print a monetary amount in a format similar to

`MXN $11,600.00 (eleven thousand, six hundred pesos 00/100 cents)`

My tests check the LaTeX source of the resulting PDF, looking for the correctly formatted string `11,600.00`

, which represents an amount of `11,000`

something plus a VAT of 16%, and also for the string `eleven thousand, six hundred`

.

It essentially goes like this:

```
from app.models import LeaseAgreement
def test_contract_states_rent_plus_vat():
"""Test correct statement of rent amount with and without IVA (VAT (USt (MWSt)))."""
contract = LeaseAgreement.build(
rent_amount=Decimal(10000.00)
)
tex = contract.render_tex()
assert '10,000.00' in tex
assert '11,600.00' in tex
assert 'eleven thousand, six hundred' in tex
```

The first two asserts did not fail, the third one did. My code actually printed

`MXN $11,600.00 (eleven thousand, five hundred and ninety-nine pesos 00/100 cents)`

### The bug

Turns out I had misused Python's `Decimal`

class to calculate the amount plus VAT. Like this:

```
>>> x = Decimal(10000) * Decimal(1.16)
```

Printing the number in the desired format works fine.

```
>>> print('{:,.2f}'.format(x))
11,600.00
```

But rounding down for only printing the amount without decimal places does not.

```
>>> num2words(int(x))
'eleven thousand, five hundred and ninety-nine'
```

That is because floats are not exact.

```
>>> Decimal(1.16)
Decimal('1.1599999999999999200639422269887290894985198974609375')
>>> int(Decimal(1.16)*10000)
11599
```

### The fix

Working with monetary amounts that round to 2 digits requires care. Thanks to Rami and others, I now know that I should have used e.g.

```
Decimal('1.16')
```

and

```
Decimal('1.16').quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
```

when apropriate.