I'm having the same problem as this guy and possibly this guy, but I am around to share some code and respond to questions!
I have some code in a batch job that reads fields from a Microsoft Access database via pyodbc and prepares the output for display.
Here is a snippet. Note the assert.
def format_currency(amount):
if amount is None:
return ""
else:
result = "$%.2f" % amount
assert ":" not in result, (
"That's weird. The value %r of class %s is represented as %s" %
(amount, amount.__class__, result))
return result
When I run it, it successfully processes 100,000 rows and then fails:
AssertionError: That's weird. The value Decimal('54871.0000') of class <class
'decimal.Decimal'> is represented as $54870.:0
Note the aberrant colon. It occurs rarely - about one time in 300,000 records.
When I try to isolate it, of course it works.
from decimal import Decimal
print "$%.2f" % Decimal('54871.0000')
$54871.00
The type of the field in Access is:
- Data Type: Currency
- Decimal Places: 2
- Input Mask:
- Default Value:
- Validation Rule:
- Text Align: General
My vague finger-pointing suspicion based on insufficient evidence: pyodbc is poking with the internals of Decimal, perhaps confused by an Access corruption. As @ecatmur points out:
':' is '9' + 1 in ASCII
Anyone seen this and solved it?
Versions:
- Python 2.7.4
- pyodbc 3.0.6 (latest)
- Access 2010
- Windows 7
Digging further:
The decimal
module is implemented in Python. From my reading, the values are described by four attributes: _exp
, _int
, _sign
, _is_special
Suspecting corruption, I printed out the values of these fields.
Surprisingly, for both the faulty and the working version, I get:
_exp: -4
_int: 548710000
_sign: 0
_is_special: False
That's weird.
In the decimal
module, the __float__
function is defined fairly simply:
def __float__(self):
"""Float representation."""
return float(str(self))
But when I do this with the bad data:
print "Str", str(amount)
print "Float", float(amount)
I get:
Str 54871.0000
Float 54870.:
The more I learn, the less weird it doesn't get.