Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support strict setting in all decoders #434

Merged
merged 10 commits into from
Jun 11, 2023
2 changes: 1 addition & 1 deletion benchmarks/bench_encodings.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class Directory(msgspec.Struct, tag="directory"):
def bench(dumps, loads, ndata, schema=None):
data = make_filesystem_data(ndata)
if schema:
data = msgspec.from_builtins(data, schema)
data = msgspec.convert(data, schema)
timer = timeit.Timer("func(data)", globals={"func": dumps, "data": data})
n, t = timer.autorange()
dumps_time = t / n
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/bench_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def bench_msgspec(n):
dec = msgspec.json.Decoder(Directory)

def convert(data):
return msgspec.from_builtins(data, Directory)
return msgspec.convert(data, Directory)

return bench(enc.encode, dec.decode, n, convert)

Expand Down
43 changes: 43 additions & 0 deletions docs/source/supported-types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ lacks a ``null`` value, attempted to encode a message containing ``None`` to
>>> msgspec.json.decode(b'null')
None

If ``strict=False`` is specified, a string value of ``"null"`` (case
insensitive) may also be coerced to ``None``. See :ref:`strict-vs-lax` for more
information.

.. code-block:: python

>>> msgspec.json.decode(b'"null"', type=None, strict=False)
None

``bool``
--------

Expand All @@ -101,6 +110,18 @@ supported protocols.
>>> msgspec.json.decode(b'true')
True

If ``strict=False`` is specified, string values of ``"true"``/``"1"`` or
``"false"``/``"0"`` (case insensitive) may also be coerced to
``True``/``False`` respectively. See :ref:`strict-vs-lax` for more information.

.. code-block:: python

>>> msgspec.json.decode(b'"false"', type=bool, strict=False)
False

>>> msgspec.json.decode(b'"TRUE"', type=bool, strict=False)
True

``int``
-------

Expand All @@ -122,6 +143,15 @@ Support for large integers varies by protocol:
>>> msgspec.json.decode(b"123", type=int)
123

If ``strict=False`` is specified, string values may also be coerced to
integers, following the same restrictions as above. See :ref:`strict-vs-lax`
for more information.

.. code-block:: python

>>> msgspec.json.decode(b'"123"', type=int, strict=False)
123


``float``
---------
Expand Down Expand Up @@ -151,6 +181,19 @@ provided, the `int` will be automatically converted.
... msgspec.json.decode(b"123", type=float)
123.0

If ``strict=False`` is specified, string values may also be coerced to floats.
Note that in this case the strings ``"nan"``, ``"inf"``/``"infinity"``,
``"-inf"``/``"-infinity"`` (case insensitive) will coerce to
``nan``/``inf``/``-inf``. See :ref:`strict-vs-lax` for more information.

.. code-block:: python

>>> msgspec.json.decode(b'"123.45"', type=float, strict=False)
123.45

>>> msgspec.json.decode(b'"-inf"', type=float, strict=False)
-inf

``str``
-------

Expand Down
22 changes: 19 additions & 3 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,15 @@ If a message doesn't match the expected type, an error is raised.
File "<stdin>", line 1, in <module>
msgspec.ValidationError: Expected `str`, got `int` - at `$.groups[1]`

.. _strict-vs-lax:

"Strict" vs "Lax" Mode
~~~~~~~~~~~~~~~~~~~~~~

Unlike some other libraries (e.g. pydantic_), ``msgspec`` won't perform any
unsafe implicit conversion. For example, if an integer is specified and a
string is decoded instead, an error is raised rather than attempting to cast
the string to an int.
unsafe implicit conversion by default ("strict" mode). For example, if an
integer is specified and a string is provided instead, an error is raised
rather than attempting to cast the string to an int.

.. code-block:: python

Expand All @@ -143,6 +148,17 @@ the string to an int.
File "<stdin>", line 1, in <module>
msgspec.ValidationError: Expected `int`, got `str` - at `$[2]`

For cases where you'd like a more lax set of conversion rules, you can pass
``strict=False`` to any ``decode`` function or ``Decoder`` class ("lax" mode).
See :doc:`supported-types` for information on how this affects individual
types.

.. code-block:: python

>>> msgspec.json.decode(b'[1, 2, "3"]', type=list[int], strict=False)
[1, 2, 3]


.. _JSON: https://json.org
.. _MessagePack: https://msgpack.org
.. _YAML: https://yaml.org
Expand Down
Loading