Skip to content

Docs: inaccurate claim on schema field ordering #228

@mjpieters

Description

@mjpieters

The documentation states you don't need to set ordered = True on a schema when using CPython 3.6+. Unfortunately that's currently not true, as the Marshmallow Schema._init_fields() implementation relies on sets, not dictionaries, to select fields. The default set implementation used is the Python stdlib set type, which does not preserve insertion order.

This is why the following example, on Python 3.9, lists fields in a different order from that used by the schema class:

>>> import sys
>>> from marshmallow import Schema, fields
>>> class FooSchema(Schema):
...     bar = fields.String()
...     spam = fields.Int()
...     ham = fields.Boolean()
...
>>> sys.version_info
sys.version_info(major=3, minor=9, micro=0, releaselevel='final', serial=0)
>>> list(FooSchema().fields)
['spam', 'ham', 'bar']

which makes the claim in the docs that passing ordered Meta attribute is not necessary when using a Python version for which dictionaries are always ordered (>= 3.7 or CPython 3.6) incorrect.

I've taken to create a custom base class that sets set_class to OrderedSet:

>>> from marshmallow.orderedset import OrderedSet
>>> class OrderedBaseSchema(Schema):
...     set_class = OrderedSet
...
>>> class FooSchemaOrdered(OrderedBaseSchema):
...     bar = fields.String()
...     spam = fields.Int()
...     ham = fields.Boolean()
...
>>> list(FooSchemaOrdered().fields)
['bar', 'spam', 'ham']

This is sufficient to retain field ordering for Python versions with the new insertion-order-preserving dict implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions