jcrist / msgspec

A fast serialization and validation library, with builtin support for JSON, MessagePack, YAML, and TOML
https://jcristharif.com/msgspec/
BSD 3-Clause "New" or "Revised" License
2.44k stars 75 forks source link

msgspec.Struct as dict keys and Dict[TypeVar, TypeVar] support #718

Open u3Izx9ql7vW4 opened 3 months ago

u3Izx9ql7vW4 commented 3 months ago

Question

I made a comment on a closed issue (https://github.com/jcrist/msgspec/issues/568) and I'm not sure it got any visibility so I'm creating a new one instead.

Here's a copy-pasta of my comment:

I got a chance to look at the fix (https://github.com/jcrist/msgspec/pull/602) and the corresponding tests. I copied your test below and made Custom inherit msgspec.Struct. Encoding still works but now decoding throws the following error

msgspec.ValidationError: Expected `object`, got `str` - at `key` in `$`

This is the code I used to generate the error (taken from your tests)


import msgspec
from typing import Dict

class Custom(msgspec.Struct):
    value : int

    def __hash__(self):
        return hash(self.value)

    def __eq__(self, other):
        return self.value == other.value

def dec_hook(typ, obj):
    if typ == Custom:
        return Custom(obj)
    raise NotImplementedError

msg = msgspec.json.encode(
    {Custom("a"): 1, Custom("b"): 2}, enc_hook=lambda x: x.value
)
assert msg == b'{"a":1,"b":2}'

obj = msgspec.json.decode(msg, type=Dict[Custom, int], dec_hook=dec_hook)
assert obj == {Custom("a"): 1, Custom("b"): 2}

Is this expected behavior? Would it be difficult to support msgspec Structs as dictionary keys?

Another thing I found is using msgspec.*.decode(dec_hook=..., type=Dict[TypeVar('A') TypeVar('B')] did not work for me. Namely I wrote a stub dec_hook function that printed 'hello world' and it never triggered on decoding.

Maybe I was doing something wrong, but was wondering if this is supported at all.