#Responses don't seem to work with Decimal types?

1 messages · Page 1 of 1 (latest)

pseudo tundra
#
import decimal

import msgspec
import litestar


class Foo1(msgspec.Struct):
    bar: decimal.Decimal

class Foo2(msgspec.Struct):
    bar: float

@litestar.get("/1")
async def test1() -> Foo1:
    d = decimal.Decimal(123.00)
    return Foo1(bar=d)

@litestar.get("/2")
async def test2() -> Foo2:
    d = decimal.Decimal(123.00)
    return Foo2(bar=d)


app = litestar.Litestar(route_handlers=[test1, test2])

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, port=7777)

My response becomes a string.. shouldn't it be a float?
{"bar": "123"}

The reason I ask, is when I use asyncpg plugin, my numeric types are decimal. So in my msgspec, I'll type it as float so that it converts properly.

Why is this happening?

#

I guess I just need to cast to float in the post init this isn't possible it seems

#

I didn't realize decimal would stay string and that structs don't convert it automatically

#

Looks like there's some options in the msgspec lib for this 🙂

pseudo tundra
#

Is there a way to set a custom encoder like this for responses in litestar?

encoder = msgspec.json.Encoder(ResponseStruct, decimal_format="number")

encoder.encode(x)

frigid heath
#

doesn't really seem possible to me without the use of patch, but maybe you could encode it into bytes with the custom encoder and setting it as the response content?

opaque karma
#

It's a string because decimals can't be represented as floats without loss of precision

#

In your case, it could be, but encoding a decimal to different types based on its value isn't ideal

#

And no, there's not really a way to customise this unfortunately, as Litestar doesn't use the msgspec encoder classes

#

Can I ask though, if your input type are floats, why use decimals at all?