dataclasses-json
dataclasses-json copied to clipboard
Efficient way to skip encoding null optionals?
Is there a way to configure a dataclass_json class to skip encoding some or any fields when they have None values?
I'm also looking for something similar. Apparently this might help https://github.com/marshmallow-code/marshmallow/issues/229
In my case I don't use marshmallow
and I'm just interested in dropping None
values when encoding with to_json
function
Same Here Actually, I would prefer any optional value which is also it's "default" value be skipped.
If i have an int whose default is 55, it would be good to be able to NOT serialise it if the int is 55, and only serialize it in all other cases.
Yes it is easy to skip Null optionals, as i just discovered:
my_field: Optional[str] = field(
default=None, metadata=config(exclude=ExcludeIfNone)
)
exclude takes a function which is passed a single variable, the value of the field. To exclude it needs to return True. SO, to exclude if None, it needs to say:
def ExcludeIfNone(value):
return value is None
you could also do it inline with a lambda, but i prefer the self documenting nature of exclude=ExcludeIfNone
it would be really nice, if a second parameter could be passed to this function, the field definition. Then you would be able to do a check if the field is its default, as it stands you need to explicitly have a ExcludeIfZero
etc, for all the cases of your defaults that you want to not encode.
~~Thanks @stevenj - thanks for a working solution... but it's a ton of boilerplate?~~
I spoke too soon - I can't seem to get this working --?
@lidatong would you consider a PR to make this an option on the decorator?
Thanks, Chad
@chadbr I just tested and it worked for me. In my case I used a lambda:
my_field: Optional[dict] = field(default=None, metadata=config(exclude=lambda x: x is None))
I would love it if the exclude function was also passed the fields metadata in addition to its value. Then one could write a "Exclude if Default" which can't be done now except explicitly as in Default is None, so exclude if None.
I'm also having this issue with an inconsistent behavior between Marshmallow and dataclass_json. A lot of my data code looks like this (working example):
from dataclasses import dataclass, field
from dataclasses_json import config, dataclass_json
from typing import Optional
from enum import Enum
class ArgType(Enum):
Type1 = 'type1'
Type2 = 'type2'
@dataclass_json
@dataclass
class Args:
id: str
arg_type: ArgType
optional: Optional[bool] = field(default=None, metadata=config(exclude=lambda f: f is None))
And the serialization behaves differently between the method used, without common ground, which is disturbing:
>>> a = Args('1', ArgType.Type1)
>>> a.to_dict()
{'id': '1', 'arg_type': <ArgType.Type1: 'type1'>}
>>> a.schema().dump(a)
{'optional': None, 'id': '1', 'arg_type': 'type1'}
The optional field is well excuded in the to_dict
version, but here the Enum is not serialized, so it fails in other libraries using the default json
Encoder:
self = <json.encoder.JSONEncoder object at 0x111259af0>
o = <ArgType.Type1: 'type1'>
[...redacted]
> raise TypeError(f'Object of type {o.__class__.__name__} '
f'is not JSON serializable')
E TypeError: Object of type ArgType is not JSON serializable
So, it's either the field metadata specifications are followed but using a data structure that requires extra config everywhere it's used, or the field metadata are ignored and the data structure is correctly serialized.
It can be seen in the marshmallow schema:
>>> schema = a.schema()
>>> schema.fields['optional'].metadata
{}
This works for the mixin as well:
class Mixin(DataClassJsonMixin):
dataclass_json_config = dataclasses_json.config( # type: ignore
letter_case=dataclasses_json.LetterCase.CAMEL, # type: ignore
undefined=dataclasses_json.Undefined.EXCLUDE,
exclude=lambda f: f is None # type: ignore
)["dataclasses_json"]