Feature Request: Optional Serde By Alias
See original GitHub issueHello I have a feature request that would be very beneficial to us. We are moving models in and out of a document store where attributes contribute to the size of the document. Because of this we want to shorten attributes when saving the document and rehydrate them coming out.
But there are places in our application where we don’t have access to the deserialized dataclass and instead just have a dict. We want to abstract this so we don’t have to know what the aliased fields are when working directly against a dict, and instead would like to have the ability to deserialize the dict based on either the alias or the unaliased keys.
FEATURE REQUEST: MIXED ALIAS DESERIALIZATION
Here is an example of a case where I’d like to build a new user entity from a dict. Then I’d like to deserialize it into my UserEntity. But while building my new user dict I don’t want to have to know what the aliased fields are:
@dataclass
class UserEntity(DataClassDictMixin):
name: str = field(metadata=field_options(alias="n"))
age: str = field(metadata=field_options(alias="a"))
new_user = { "name": "Bill", "age": 30 }
new_user_ent = UserEntity.from_dict(new_user)
This doesn’t work with DataClasDictMixin as far as I’m aware, so we created a helper mixin that translates unaliased fields to aliased fields before deserializing in the __pre_deserialization__
method:
ALLOW_UNALIASED_DESERIALIZATION = True
@classmethod
def __pre_deserialize__(cls, d: Dict[Any, Any]) -> Dict[Any, Any]:
if cls.ALLOW_UNALIASED_DESERIALIZATION:
alias_revmap = cls.get_alias_revmap()
for field, alias in alias_revmap.items():
if field in d:
d[alias] = d[field]
d.pop(field)
return d
@classmethod
def get_alias_map(cls) -> Dict[str, str]:
"""
If aliases are defined. Returns a map of the aliased fields to the non-aliased field names
"""
if not hasattr(cls, "__alias_map__"):
cls.__alias_map__ = {}
for key, field in cls.__dataclass_fields__.items():
alias = field.metadata.get("alias")
if alias:
cls.__alias_map__[alias] = key
return cls.__alias_map__
@classmethod
def get_alias_revmap(cls) -> Dict[str, str]:
"""
If aliases are defined. Returns a map of the non-aliased fields to the alias field names
"""
if not hasattr(cls, "__alias_revmap__"):
alias_map = cls.get_alias_map()
cls.__alias_revamp__ = {
v: k for k, v in alias_map.items()
}
return cls.__alias_revamp__
FEATURE REQUEST: OPTIONALLY DISABLE ALIAS SERIALIZATION
When serializing entities, aliases are not used by default. Once again we have a situation where we’d like to optionally opt out of alias serialization. This can be done with the TO_DICT_ADD_BY_ALIAS_FLAG
, but perhaps an oversight is that you cannot make alias serialization the default and the opt out of it. If it is optional, it’s only opt in.
@dataclass
class MyEntity(DataClassDictMixin):
a: str = field(metadata=field_options(alias="FieldA"))
b: str = field(metadata=field_options(alias="FieldB"))
class Config(BaseConfig):
serialize_by_alias = True
code_generation_options = [TO_DICT_ADD_BY_ALIAS_FLAG]
def scratch():
me = MyEntity(
a="Hello",
b="World"
)
print(me.to_dict())
print(me.to_dict(by_alias=False))
if __name__ == "__main__":
scratch()
In this sample I would expect print(me.to_dict())
to use aliases during serialization, and for print(me.to_dict(by_alias=False))
to opt out of the default. But even though I set the serialize_by_alias
flag it will still use the unaliased fields during serialization because I’ve also added the TO_DICT_ADD_BY_ALIAS_FLAG
.
I tried removing the TO_DICT_ADD_BY_ALIAS_FLAG
entirely, but when you do that you no longer have access to by_alias
in the to_dict()
and it will throw this exception:
to_dict() got an unexpected keyword argument 'by_alias'
I tried to get around this by overwriting the to_dict
method in both my helper mixin and entity class, but that code never gets hit.
def to_dict(self, **kwargs) -> dict:
print("HERE")
return super().to_dict(**kwargs)
Whether as an instance method or a class method.
Thank you for taking the time to read through my feature request.
Issue Analytics
- State:
- Created 2 years ago
- Comments:15 (9 by maintainers)
Ah, I see what you mean. It could be written as follows then:
Thanks @Fatal1ty - I’ll try this out soon (probably next week).