Fatal1ty / mashumaro

Fast and well tested serialization library
Apache License 2.0
751 stars 44 forks source link

Using Union with int/float casts to whichever appears first #190

Closed ggydush closed 6 months ago

ggydush commented 6 months ago

Description

Using a dataclass with Union comprised of int/float causes the value to be cast to whichever appears first in the Union definition. Looking at the pack_union method, the output makes sense, but wondering if special cases should be added to preserve int/float types.

What I Did

from dataclasses import dataclass

from mashumaro.mixins.json import DataClassJSONMixin

@dataclass
class Example(DataClassJSONMixin):
    val1: float | int
    val2: int | float

print(Example(val1=3, val2=3.5).to_dict())

Output:

{'val1': 3.0, 'val2': 3}
Fatal1ty commented 6 months ago

Default converters for int and float types on serialization are int and float functions respectively. It has its roots in how Union types are currently processed. Imagine that you have Union[int, <another_dataclass>]. If int values were passing as is, then we would be passing <another_dataclass> values as is because "passing through" strategy appears first. I have plans to rework Union types and get rid of explicit converters for int, float types but before that you can use pass_through helper:

from dataclasses import dataclass

from mashumaro import pass_through
from mashumaro.config import BaseConfig
from mashumaro.mixins.json import DataClassJSONMixin

@dataclass
class Example(DataClassJSONMixin):
    val1: float | int
    val2: int | float

    class Config(BaseConfig):
        serialization_strategy = {
            int: {"serialize": pass_through},
            float: {"serialize": pass_through},
        }

print(Example(val1=3, val2=3.5).to_dict())
ggydush commented 6 months ago

That makes total sense, and the Config overrides should work fine for my use case! Thanks for the prompt response and providing a solution!

Fatal1ty commented 5 months ago

@ggydush you might be interested in this pull request: