ramonhagenaars / jsons

🐍 A Python lib for (de)serializing Python objects to/from JSON
https://jsons.readthedocs.io
MIT License
289 stars 41 forks source link

How to define alias for dataclass attributes? #116

Closed tlzAny closed 4 years ago

tlzAny commented 4 years ago

Hi I searched for a very long time a python library that has released version and can handle deserialization from json to object by given dataclass. Now for my usecase I got a json file input with a python keyword 'type' in its body. I look for some annotation to make an alias for an attribute with different nyme i.e. _type instead of type. See similiar question here: https://stackoverflow.com/questions/60074344/reserved-word-as-an-attribute-name-in-a-dataclass-when-parsing-a-json-object

sample json entry

{
    "networkPolicyObject": [
        {
            "gid": "00000000-0000-0000-0000-180388630238",
            "name": "TEST dummy",
            "lastUpdateTime": "2013-09-10T09:55:32.743Z",
            "parentGID": "00000000-0000-0000-0000-000000000000",
            "type": "NetworkPolicyObject",
            "comment": "DNS-QIP",
            "nodeGID": "00000000-0000-0000-0000-000000000001",
            "isProperty": false,
            "isGroup": false,
            "ipData": "131.117.1.125"
        },
        {
            "gid": "00000000-0000-0000-0008-104603294934",
            "name": "TEST-LAB-NETZ-MPLS",
            "lastUpdateTime": "2015-03-13T14:57:34.556Z",
            "parentGID": "00000000-0000-0000-0000-000000000000",
            "type": "NetworkPolicyObject",
            "comment": "TEST LAB TCC B\n",
            "nodeGID": "00000000-0000-0000-0000-000000000001",
            "isProperty": false,
            "isGroup": false,
            "ipData": "10.16.144.0/255.255.255.0"
        }
}

generated dataclass with json2python-models: r""" generated by json2python-models v0.2.1 at Tue Sep 8 06:54:48 2020 command: /home/xxx/workspace/test-python-123/.venv/bin/json2models -m NetWorkObjects sample_getnetworkobjects.json -f dataclasses """ from dataclasses import dataclass, field from typing import List, Literal, Optional, Union

@dataclass
class NetWorkObjects:
    prot_version: int
    policy_object: "PolicyObject"

@dataclass
class PolicyObject:
    network_policy_object: List["NetworkPolicyObject"]

@dataclass
class NetworkPolicyObject:
    gid: str
    name: str
    parentGID: str
    lastUpdateTime: datetime.datetime
    # _type: Literal["NetworkPolicyObject"]  - How to solve this? in json source attribute is 'type' but this is a python internal keyword
    comment: str
    nodeGID: str
    isProperty: bool
    isGroup: bool
    ipData: Optional[Union[List[str], str]] = None
    updatedByUser: Optional[Literal["xxxTTT", "xxxABC"]] = None
    lastCommitTime: Optional[str] = None
    activityName: Optional[str] = None
    sub_type: Optional[Literal["NR"]] = None
    ref_gi_ds: Optional["RefGiD"] = None

@dataclass
class RefGiD:
    gid: List[str]
tlzAny commented 4 years ago

update: Like this I can skip the attribute which works for the moment but an alias would be still a good feature.


            obj: NetworkPolicyObject = jsons.loads(
                content, cls=NetworkPolicyObject, strict=False, strip_attr="type"
            )
``
ramonhagenaars commented 4 years ago

Hi @tlzAny ,

You can use key_transformer for that. It takes a callable that accepts a string (the attribute name) and expects a 'transformed' key as return value.

Example:

>>> from dataclasses import dataclass
>>> import jsons
>>> d={'type': 1}
>>> @dataclass
... class C:
...   type_: int
...
>>> jsons.load(d, cls=C, key_transformer=lambda key: 'type_' if key == 'type' else key)
C(type_=1)
tlzAny commented 4 years ago

hi ramonhagenaars Thank you for your fast reply. That's good to know.