jcrist / msgspec

A fast serialization and validation library, with builtin support for JSON, MessagePack, YAML, and TOML

Home Page:https://jcristharif.com/msgspec/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Callbacks to `Encoder`/`Decoder` are not respected in `datetime` objects

kaixuan-datature opened this issue · comments

Description

Both dec_hook and enc_hook arguments are not respected in all encoders and decoders (tested on JSON and YAML) when datetime objects are used. Note that the print functions in both hooks are not run, and the variable buf contains an ISO 8601 duration string instead of a number (as seen from enc_hook).

Attached is a sample script to show that custom decoding of datetime.timedelta objects is not supported. It also doesn't work for datetime.datetime objects.

import msgspec
from typing import Any, Type
from datetime import timedelta


def enc_hook(obj: Any) -> Any:
    print("Encoding")
    if isinstance(obj, timedelta):
        # convert the timedelta to a number
        return obj.total_seconds()
    else:
        # Raise a NotImplementedError for other types
        raise NotImplementedError(f"Objects of type {type(obj)} are not supported")


def dec_hook(type: Type, obj: Any) -> Any:
    print("Decoding", type)
    # `type` here is the value of the custom type annotation being decoded.
    if type is timedelta:
        # Convert ``obj`` (which should be a ``number``) to a timedelta
        return timedelta(seconds=obj)
    else:
        # Raise a NotImplementedError for other types
        raise NotImplementedError(f"Objects of type {type} are not supported")


class MyMessage(msgspec.Struct):
    field_1: str
    field_2: timedelta


enc = msgspec.json.Encoder(enc_hook=enc_hook)
dec = msgspec.json.Decoder(MyMessage, dec_hook=dec_hook)

msg = MyMessage("some string", timedelta(seconds=5))


# Encode and decode the message to show that things work
buf = msgspec.yaml.encode(msg, enc_hook=enc_hook)
print(buf)
a = msgspec.yaml.decode(buf, type=MyMessage, dec_hook=dec_hook)
print(a)

Apologies, refer to the other issue instead