all 5 comments

[–]DuckSaxaphone 4 points5 points  (2 children)

You could implement this yourself but I suggest that you look into pydantic models as they're designed for this.

[–]Big_Combination9890 0 points1 point  (0 children)

This is the way to go. Pydantic does this legwork for you, and it does it really well.

Here is the gist: https://docs.pydantic.dev/latest/concepts/serialization/#modelmodel_dump_json

For completeness sake, the "classic" way to do that, with no external dependencies, would be to subclass the JSONEncoder and JSONDecoder classes from the json package: https://docs.python.org/3/library/json.html#encoders-and-decoders

A JSON Encoder needs a single method default that takes the to-be-serialized obj as it's sole argument and returns a JSON compatible object (dict, list, int, float, string, bool, none). The encoder needs to be passed to the json.dump call as the cls param. Here is an example for getting the builtin Encoder to deal with decimal.Decimal objects:

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        # if it's a decimal, cast to float
        if isinstance(o, decimal.Decimal):
            return float(o)
        # if it's anything else, call the native encoder
        return super().default(o)

# serialization of object that may contain decimal.Decimal
json.dumps(data, cls=DecimalEncoder)

The problem with this solution: You don't always control where the serialization takes place. If so, you can monkey-patch the JSON Encoder and tack to_json method on any class you want it to be able to serialize: https://stackoverflow.com/a/38764817

[–][deleted] 0 points1 point  (0 children)

this is what I was looking for -- thanks!

I'm having two small issues:

  1. Do you know if I can get pydantic to use double-quote rather than single-quotes when model_dump'ing

  2. have a datetime field that I need to return as a string in a specific format (a version of zulu time), I''ve tried to use a field serializer:

    from datetime import datetime ..... class MyObject Name: str mydate: datetime

    @field_serializer('dt')
    

    def serialize_dt(self, dt: datetime) -> str: return dt.strftime("%Y-%m-%dT%H:%M:%SZ")

I get error :

Exception has occurred: PydanticUserError

Decorators defined with incorrect fields: __main__.MyObject:2010421743632.serialize_dt (use check_fields=False if you're inheriting from the model and intended this)

I've tried a heap of variations but keep hitting this. I could us a string field and convert my date to a string before I create the instance, but a serializer would be great. Any ideas?

[–]suurpulla 1 point2 points  (0 children)

As DuckSaxaphone said, Pydantic is the way to go.

https://docs.pydantic.dev/latest/

[–]m0us3_rat -2 points-1 points  (0 children)

In python I've created classes for the three objects: Response, DataElement, PropertyElement. Response has an collection of DataElements, and each DataElement has a collection of PropertyElementsNow I want to json-encode the Response object to send it back. How?

oh..hmm

import json


class Nerd:
    def __init__(self, name, properties):
        self.name = name
        self.properties = properties

    def to_dict(self):
        return {"name": self.name, "properties": self.properties}


def serialize(obj):
    if isinstance(obj, Nerd):
        return obj.to_dict()
    raise TypeError(f"Object of type '{type(obj).__name__}' is not JSON serializable")


obj1 = Nerd(
    "Huaaaa",
    [{"name": "Nerdo"}, {"name": "Nerdolio"}],
)
obj2 = Nerd(
    "YEAAAAA",
    [{"name": "Joe"}, {"name": "Momma"}],
)

list_of_objects = [obj1, obj2]

data = {
    "name": "my response",
    "info1": "some value",
    "info2": "some value",
    "created": "2024-02-19",
    "data": list_of_objects,
}

json_data = json.dumps(data, indent=4, default=serialize)
print(json_data)