Description
Description
Per the documentation of UNSET:
During encoding, any field containing UNSET is omitted from the message.
Unfortunately, this fails for Structs with array_like=True
, resulting in the following error:
TypeError: Encoding objects of type msgspec.UnsetType is unsupported
This appears to be an oversight in the function json_encode_struct_array, which does not check for (and ignore) UNSET values, whereas json_encode_struct_object does ignore UNSET values, as expected.
I suspect this might be intentional since there can be cases where decoding in the face of UNSET values can present ambiguity, as least in the face of roundtripping, when attributes that can be UNSET are interspersed with those that cannot be UNSET.
However, I would argue that the developer should make judicious use of array_like=True
to avoid such ambiguity. In other words, it seems reasonable to me that msgspec should indeed skip UNSET values in this case anyway, documenting that this is sort of a "use at your own risk of ambiguity" for the developer, particularly since decoding works without issue.
For example, consider this struct:
class Position(msgspec.Struct, array_like=True, frozen=True, forbid_unknown_fields=True):
longitude: float
latitude: float
altitude: Union[float, msgspec.UnsetType] = msgspec.UNSET
Decoding works perfectly well:
>>> pos = msgspec.json.decode("[-3.703790, 40.416775]", type=Position)
>>> pos
Position(longitude=-3.70379, latitude=40.416775, altitude=UNSET)
Unfortunately, encoding does not:
>>> msgspec.json.encode(pos)
Traceback (most recent call last):
...
TypeError: Encoding objects of type msgspec.UnsetType is unsupported
Instead of that TypeError
, I expect encoding to result in b'[-3.70379, 40.416775]'
since altitude
is UNSET
.
When I remove array_like=True
(or set it explicitly to False
), decoding (a JSON object in place of a JSON array, without a value for altitude
) and encoding work as expected.