Parsing Decimal from JSON number loses precision
When parsing a decimal from a JSON number, pydantic-core (2.33.1) is losing precision. It seems like the JSON number is converted to a float internally before being passed to Decimal. This problem has been brought up already in the pydantic repo (https://github.com/pydantic/pydantic/issues/9180), but I think it belongs here.
Code to reproduce with pydantic-core:
from decimal import Decimal
from pydantic_core import SchemaValidator
def test_parse_decimal():
v = SchemaValidator(
{
'type': 'typed-dict',
'fields': {
'value': {
'type': 'typed-dict-field',
'schema': {
'type': 'decimal',
},
},
},
}
)
r1 = v.validate_json(b'{"value": 0.29999999999999998}')
assert r1["value"] == Decimal("0.29999999999999998")
AssertionError: assert Decimal('0.3') == Decimal('0.29999999999999998')
Since the JSON standard doesn't specify limits on range and precision for numbers, parsing them into Decimals without loss of precision is a valid use case. So I assume this is a bug.
I'm seeing a similar issue with UUIDs loaded from JSON strings. I've found that calling model_validate on the return from model_validate_json will properly coerce the UUID strings to UUID types. Not sure if that will help you in the Decimal case. But it seems the issue is across types.
@kolditz-senec I understand the frustration with losing decimal precision, but this isn't actually a bug in pydantic-core. The precision loss happens at the JSON parsing layer before pydantic-core even gets the value.
pydantic-core uses jiter for JSON parsing, and jiter converts JSON numbers to floats during parsing. When you write {"value": 0.29999999999999998} as a JSON number, the precision is already lost due to floating-point representation before pydantic-core receives it.
To fix this, we'd need jiter to parse numbers as strings or have special precision-preserving mode, which would be a significant architectural change.
The workaround is using JSON strings: {"value": "0.29999999999999998"}. This bypasses float conversion and preserves exact precision. That's also why pydantic serializes Decimals as strings by default.