Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatic custom constructor for python dataclass

I'm trying to create a custom constructor for my python dataclass that will ideally take in a dict (from request json data) and fill in the attributes of the dataclass.

Eg

@dataclass
class SoldItem:
    title: str
    purchase_price: float
    shipping_price: float
    order_data: datetime

def main():
    json = requests.get(URL).json()
    sold_item = SoldItem(json)

So I want SoldItem to have a method that saves the json data in the appropriate attributes of the dataclass instead of having to do SoldItem(title=json['title']...

I would also preferably have the class be able to recognise that the data being passed in is a dict and execute the from dict constructor.

I have done my best to look up possible solutions but have come up mostly empty.

Any help would be greatly appreciated.

like image 633
rick_grimes Avatar asked Oct 17 '25 02:10

rick_grimes


1 Answers

For the simplest approach - with no additional libraries - I would personally go with a de-structuring approach via **kwargs.

For example:

>>> json = {'title': 'test', 'purchase_price': 1.2, 'shipping_price': 42, 'order_data': datetime.min}
>>> SoldItem(**json)
SoldItem(title='test', purchase_price=1.2, shipping_price=42, order_data=datetime.datetime(1, 1, 1, 0, 0))

In case of a more involved use case, such as:

  • a nested dataclass structure
  • the input dict is the result of an API call
  • keys in the dict are not in snake_case
  • value for a key does not match annotated type for a dataclass field

In such cases, I would suggest third-party tools that will automagically handle this data transform for you.

For instance, the dataclass-wizard is a (de)serialization library I have come up with, for exactly this use case, i.e. when the input data might be coming from another source, such as the result of an API call or response.

It can be installed with pip:

pip install dataclass-wizard

Usage:

from dataclasses import dataclass
from datetime import datetime

from dataclass_wizard import JSONWizard


@dataclass
class SoldItem(JSONWizard):
    title: str
    purchase_price: float
    shipping_price: float
    order_data: datetime


def main():
    from pprint import pprint

    # json = requests.get(URL).json()
    json = {'title': 'test',
            'purchasePrice': '1.23',
            'shipping-price': 42,
            'Order_Data': '2021-01-02T12:34:56Z'}

    # create a `SoldItem` instance from an input `dict`,
    # such as from an API response.
    sold_item = SoldItem.from_dict(json)

    pprint(sold_item)


if __name__ == '__main__':
    main()

Prints:

SoldItem(title='test',
         purchase_price=1.23,
         shipping_price=42.0,
         order_data=datetime.datetime(2021, 1, 2, 12, 34, 56, tzinfo=datetime.timezone.utc))
like image 196
rv.kvetch Avatar answered Oct 19 '25 20:10

rv.kvetch



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!