msgspec icon indicating copy to clipboard operation
msgspec copied to clipboard

Decimal should be handled as a custom type during demarshaling.

Open NyanFisher opened this issue 6 months ago • 0 comments

Hey!

I have a problem when I use msgspec and Decimal. One popular solution to using Decimal is to not round the data as part of the algorithm execution and business logic. The rounding happens during demarshaling at the API endpoints. Decimal is the native type, so it's not possible to create an Encoder that can handle this.

Is it possible to change the behaviour for Decimal and allow interception in enc_hook?

Example:

from decimal import ROUND_HALF_UP, Decimal
from typing import Any

import msgspec


def enc_hook(obj: Any) -> Any:
    if isinstance(obj, Decimal):
        return str(obj.quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP))
    else:
        raise NotImplementedError(f"Objects of type {type(obj)} are not supported")


class Price(msgspec.Struct):
    primecost: Decimal

enc = msgspec.json.Encoder(enc_hook=enc_hook)

price = Price(primecost=Decimal("1.1234444"))

buf = enc.encode(price)
# b'{"primecost":"1.1234"}'

Creating a custom Decimal MyDecimal looks like a workaround.

NyanFisher avatar May 15 '25 16:05 NyanFisher