Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ Inspect
.. autoclass:: TimeType
.. autoclass:: DateType
.. autoclass:: UUIDType
.. autoclass:: DecimalType
.. autoclass:: ExtType
.. autoclass:: RawType
.. autoclass:: EnumType
Expand Down
28 changes: 12 additions & 16 deletions docs/source/extending.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,39 +65,38 @@ by defining two callback functions:
- ``dec_hook`` in ``Decoder``, for converting natively supported types back
into a custom type when using :ref:`typed decoding <typed-decoding>`.

Here we define ``enc_hook`` and ``dec_hook`` callbacks to convert
`decimal.Decimal` objects to/from strings, which are then natively handled by
``msgspec``.
Here we define ``enc_hook`` and ``dec_hook`` callbacks to convert `complex`
objects to/from objects, which are then natively handled by ``msgspec``.

.. code-block:: python

import msgspec
from typing import Any, Type
from decimal import Decimal

def enc_hook(obj: Any) -> Any:
if isinstance(obj, Decimal):
# convert the Decimal to a str
return str(obj)
if isinstance(obj, complex):
# convert the complex to a tuple of real, imag
return (obj.real, obj.imag)
else:
# Raise a TypeError for other types
raise TypeError(f"Objects of type {type(obj)} are not supported")


def dec_hook(type: Type, obj: Any) -> Any:
# `type` here is the value of the custom type annotation being decoded.
if type is Decimal:
# Convert ``obj`` (which should be a ``str``) to a Decimal
return Decimal(obj)
if type is complex:
# Convert ``obj`` (which should be a ``tuple``) to a complex
real, imag = obj
return complex(real, imag)
else:
# Raise a TypeError for other types
raise TypeError(f"Objects of type {type} are not supported")


# Define a message that contains a Decimal
# Define a message that contains a complex type
class MyMessage(msgspec.Struct):
field_1: str
field_2: Decimal
field_2: complex

# Create an encoder and a decoder using the custom callbacks.
# Note that typed deserialization is required for successful
Expand All @@ -106,10 +105,7 @@ Here we define ``enc_hook`` and ``dec_hook`` callbacks to convert
dec = msgspec.json.Decoder(MyMessage, dec_hook=dec_hook)

# An example message
msg = MyMessage(
"some string",
Decimal("3.1415926535897932384626433832795"),
)
msg = MyMessage("some string", complex(1, 2))

# Encode and decode the message to show that things work
buf = enc.encode(msg)
Expand Down
32 changes: 29 additions & 3 deletions docs/source/supported-types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Most combinations of the following types are supported (with a few restrictions)
- `datetime.date`
- `datetime.time`
- `uuid.UUID`
- `decimal.Decimal`
- `typing.Any`
- `typing.Optional`
- `typing.Union`
Expand Down Expand Up @@ -317,6 +318,31 @@ timezone-naive by specifying a ``tz`` constraint (see
File "<stdin>", line 1, in <module>
msgspec.ValidationError: Invalid UUID

``decimal``
-----------

`decimal.Decimal` values are serialized as their string representation in all
protocols. This ensures no precision loss during serialization, as would happen
with a float representation.

.. code-block:: python

>>> import decimal

>>> x = decimal.Decimal("1.2345")

>>> msg = msgspec.json.encode(x)

>>> msg
b'"1.2345"'

>>> msgspec.json.decode(msg, type=decimal.Decimal)
Decimal('1.2345')

>>> msgspec.json.decode(b'"oops"', type=decimal.Decimal)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
msgspec.ValidationError: Invalid decimal string

``list`` / ``tuple`` / ``set`` / ``frozenset``
----------------------------------------------
Expand Down Expand Up @@ -714,9 +740,9 @@ Union restrictions are as follows:

- Unions may contain at most one type that encodes to a string (`str`,
`enum.Enum`, `bytes`, `bytearray`, `datetime.datetime`, `datetime.date`,
`datetime.time`, `uuid.UUID`). Note that this restriction is fixable with
some work, if this is a feature you need please `open an issue
<https://github.com/jcrist/msgspec/issues>`__.
`datetime.time`, `uuid.UUID`, `decimal.Decimal`). Note that this restriction
is fixable with some work, if this is a feature you need please `open an
issue <https://github.com/jcrist/msgspec/issues>`__.

- Unions may contain at most one type that encodes to an object (`dict`,
`typing.TypedDict`, `dataclasses.dataclass`, `Struct` with
Expand Down
Loading