-
-
Notifications
You must be signed in to change notification settings - Fork 640
Description
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:
- 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. None
may be a valid attr value on the parent object/Schema, butNone
is not a valid value for my custom Field's data type. For example, given:AssumingFoo.bar = Bar()
.bar
is optional,Foo.bar = None
is a valid assignment. ButNone
is not a validBar
object. So aBarField
should not be responsible for serializing aNone
. I would actually expectBarField
to raise someTypeError
-like if it was given aNone
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
andkeep_none is True
, then returnNone
as the serialized value and do not callField._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.