Skip to content

keep_none option to skip Field._serialize() on None values #1096

Description

@PhilMarsh

I have optional attrs in some of my app-level objects.
My app-level objects are fully explicit: missing optional fields are explicitly set to None instead of being left unset.
I want my Schema to be similarly explicit on dump (ie: never skip fields), while being permissive on load (ie: allow missing fields as None).

So the behavior I want for my Fields is:
A) on load, missing or None is deserialized to None.
B) on dump, None is serialized to None.

Requirement A is easily satisfied by missing=None.
Requirement B requires more work. For custom types, I must add an is None check to the override of Field._serialize().

This asymmetry of load and dump behavior is strange to me for a couple reasons:

  1. Load-time optionality is controlled dynamically via Field parameters, which are stated in the Schema.
    But dump-time optionality is controlled statically by the Field implementation, forcing all Schemas to accept the same behavior (or use some sort of Field factory to customize behavior). I think it is common to have types which are optional in some Schemas and required in other Schemas.
  2. None may be a valid attr value on the parent object/Schema, but None is not a valid value for my custom Field's data type. For example, given:
    Foo.bar = Bar()
    
    Assuming .bar is optional, Foo.bar = None is a valid assignment. But None is not a valid Bar object. So a BarField should not be responsible for serializing a None. I would actually expect BarField to raise some TypeError-like if it was given a None to serialize.

My proposal is to add a keep_none parameter to Field to make this dump behavior configurable.
Behavior is:

  • During serialization, if an attr is found to be None and keep_none is True, then return None as the serialized value and do not call Field._serialize().

This seems similar to #229, except I don't want to skip the None Fields; I want to keep them as None in the serialized output.

EDIT 1: Requirement A is satisfied by missing=None (which implies allow_none=True), not by allow_none=True alone.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions