dataclasses-json icon indicating copy to clipboard operation
dataclasses-json copied to clipboard

Dataclass fields are not serialized in definition order when explicitly building schema

Open JoseUusitalo opened this issue 4 years ago • 3 comments

This library does not seem to support dataclass member ordering when serializing objects using a pregenerated schema created with the schema method unless I missed something. However since marshmallow Meta objects explicitly support keeping dataclass fields in the definition order with the ordered parameter this is probably just an oversight?

Currently dataclass fields are in a random order in the serialized output every time the script is run. (The to_json method does work as expected.) Below is sample code that demonstrates the issue.

from dataclasses import dataclass
from dataclasses_json import dataclass_json

@dataclass_json
@dataclass
class Person:
    first_name: str
    last_name: str
    age: int

person = Person(first_name="Jane", last_name="Doe", age=30)
person_schema = Person.schema()
print("Person:", person_schema.dumps(person))
print("Expected:", '{"first_name": "Jane", "last_name": "Doe", "age": 30}')

The code will have a chance of returning the following output:

Person: {"last_name": "Doe", "age": 30, "first_name": "Jane"} Expected: {"first_name": "Jane", "last_name": "Doe", "age": 30}

After debugging for a while I figured out that to fix this I simply needed to add the following line:

'ordered': True,

To mm.py in the build_schema function on line 328. After applying the fix the serialized output always matches the expected output.

I think the library should provide an option to keep dataclass fields in definition order (preferably on by default) in the serialized output. Or just always keep them in order like the to_json method does.

JoseUusitalo avatar Apr 26 '20 15:04 JoseUusitalo

Hi, thanks for reporting this issue. Agreed, that the behavior should be configurable.

As for why this is happening, here's a blurb from the json documentation (which backs to_json):

Prior to Python 3.7, dict was not guaranteed to be ordered, so inputs and outputs were typically scrambled unless collections.OrderedDict was specifically requested.

So I guess this issue might also happen for to_json in 3.6

lidatong avatar Jun 06 '20 15:06 lidatong

I would also like to see this feature made available.

ZachPerkitny avatar Aug 02 '20 18:08 ZachPerkitny

+1 What I've did for now is set:

schema.dump_fields = schema.declared_fields

This works for me because all declared fields must be dumped.

dynamicmindset avatar Mar 01 '21 14:03 dynamicmindset