mashumaro 3.20
Fast and well tested serialization library
Requires Python: >=3.9

<div align="center">

<img alt="logo" width="175" src="https://raw.githubusercontent.com/Fatal1ty/mashumaro/ac2f924591d488dbd9a776a6b1ae7dede2d8c73e/img/logo.svg">

###### Fast and well tested serialization library

[![Build Status](https://github.com/Fatal1ty/mashumaro/workflows/tests/badge.svg)](https://github.com/Fatal1ty/mashumaro/actions)
[![Coverage Status](https://coveralls.io/repos/github/Fatal1ty/mashumaro/badge.svg?branch=master)](https://coveralls.io/github/Fatal1ty/mashumaro?branch=master)
[![Latest Version](https://img.shields.io/pypi/v/mashumaro.svg)](https://pypi.python.org/pypi/mashumaro)
[![Python Version](https://img.shields.io/pypi/pyversions/mashumaro.svg)](https://pypi.python.org/pypi/mashumaro)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
</div>

In Python, you often need to dump and load objects based on the schema you
have. It can be a dataclass model, a list of third-party generic classes or
whatever. Mashumaro not only lets you save and load things in different ways,
but it also does it _super quick_.

**Key features**
* 🚀 One of the fastest libraries
* ☝️ Mature and time-tested
* 👶 Easy to use out of the box
* ⚙️ Highly customizable
* 🎉 Built-in support for JSON, YAML, TOML, MessagePack
* 📦 Built-in support for almost all Python types including typing-extensions
* 📝 JSON Schema generation

Table of contents
-------------------------------------------------------------------------------
* [Table of contents](#table-of-contents)
* [Introduction](#introduction)
* [Installation](#installation)
* [Changelog](#changelog)
* [Supported data types](#supported-data-types)
* [Usage example](#usage-example)
* [How does it work?](#how-does-it-work)
* [Benchmark](#benchmark)
* [Supported serialization formats](#supported-serialization-formats)
    * [Basic form](#basic-form)
    * [JSON](#json)
        * [json library](#json-library)
        * [orjson library](#orjson-library)
    * [YAML](#yaml)
    * [TOML](#toml)
    * [MessagePack](#messagepack)
* [Customization](#customization)
    * [SerializableType interface](#serializabletype-interface)
        * [User-defined types](#user-defined-types)
        * [User-defined generic types](#user-defined-generic-types)
    * [SerializationStrategy](#serializationstrategy)
        * [Third-party types](#third-party-types)
        * [Third-party generic types](#third-party-generic-types)
    * [Field options](#field-options)
        * [`serialize` option](#serialize-option)
        * [`deserialize` option](#deserialize-option)
        * [`serialization_strategy` option](#serialization_strategy-option)
        * [`alias` option](#alias-option)
    * [Config options](#config-options)
        * [`debug` config option](#debug-config-option)
        * [`code_generation_options` config option](#code_generation_options-config-option)
        * [`serialization_strategy` config option](#serialization_strategy-config-option)
        * [`aliases` config option](#aliases-config-option)
        * [`serialize_by_alias` config option](#serialize_by_alias-config-option)
        * [`allow_deserialization_not_by_alias` config option](#allow_deserialization_not_by_alias-config-option)
        * [`omit_none` config option](#omit_none-config-option)
        * [`omit_default` config option](#omit_default-config-option)
        * [`namedtuple_as_dict` config option](#namedtuple_as_dict-config-option)
        * [`allow_postponed_evaluation` config option](#allow_postponed_evaluation-config-option)
        * [`dialect` config option](#dialect-config-option)
        * [`orjson_options` config option](#orjson_options-config-option)
        * [`discriminator` config option](#discriminator-config-option)
        * [`lazy_compilation` config option](#lazy_compilation-config-option)
        * [`sort_keys` config option](#sort_keys-config-option)
        * [`forbid_extra_keys` config option](#forbid_extra_keys-config-option)
    * [Passing field values as is](#passing-field-values-as-is)
    * [Extending existing types](#extending-existing-types)
    * [Field aliases](#field-aliases)
    * [Dialects](#dialects)
        * [`serialization_strategy` dialect option](#serialization_strategy-dialect-option)
        * [`serialize_by_alias` dialect option](#serialize_by_alias-dialect-option)
        * [`omit_none` dialect option](#omit_none-dialect-option)
        * [`omit_default` dialect option](#omit_default-dialect-option)
        * [`namedtuple_as_dict` dialect option](#namedtuple_as_dict-dialect-option)
        * [`no_copy_collections` dialect option](#no_copy_collections-dialect-option)
        * [Changing the default dialect](#changing-the-default-dialect)
    * [Discriminator](#discriminator)
        * [Subclasses distinguishable by a field](#subclasses-distinguishable-by-a-field)
        * [Subclasses without a common field](#subclasses-without-a-common-field)
        * [Class level discriminator](#class-level-discriminator)
        * [Working with union of classes](#working-with-union-of-classes)
        * [Using a custom variant tagger function](#using-a-custom-variant-tagger-function)
    * [Code generation options](#code-generation-options)
        * [Add `omit_none` keyword argument](#add-omit_none-keyword-argument)
        * [Add `by_alias` keyword argument](#add-by_alias-keyword-argument)
        * [Add `dialect` keyword argument](#add-dialect-keyword-argument)
        * [Add `context` keyword argument](#add-context-keyword-argument)
    * [Generic dataclasses](#generic-dataclasses)
        * [Generic dataclass inheritance](#generic-dataclass-inheritance)
        * [Generic dataclass in a field type](#generic-dataclass-in-a-field-type)
    * [GenericSerializableType interface](#genericserializabletype-interface)
    * [Serialization hooks](#serialization-hooks)
        * [Before deserialization](#before-deserialization)
        * [After deserialization](#after-deserialization)
        * [Before serialization](#before-serialization)
        * [After serialization](#after-serialization)
* [JSON Schema](#json-schema)
    * [Building JSON Schema](#building-json-schema)
    * [JSON Schema constraints](#json-schema-constraints)
    * [JSON Schema plugins](#json-schema-plugins)
    * [Extending JSON Schema](#extending-json-schema)
    * [JSON Schema and custom serialization methods](#json-schema-and-custom-serialization-methods)

Introduction
-------------------------------------------------------------------------------

This library provides two fundamentally different approaches to converting
your data to and from various formats. Each of them is useful in different
situations:

* Codecs
* Mixins

Codecs are represented by a set of decoder / encoder classes and
decode / encode functions for each supported format. You can use them
to convert data of any python built-in and third-party type to JSON, YAML,
TOML, MessagePack or a basic form accepted by other serialization formats.
For example, you can convert a list of datetime objects to JSON array
containing string-represented datetimes and vice versa.

Mixins are primarily for dataclass models. They are represented by mixin
classes that add methods for converting to and from JSON, YAML, TOML,
MessagePack or a basic form accepted by other serialization formats.
If you have a root dataclass model, then it will be the easiest way to make it
serializable. All you have to do is inherit a particular mixin class.

In addition to serialization functionality, this library also provides JSON
Schema builder that can be used in places where interoperability matters.

Installation
-------------------------------------------------------------------------------

Use pip to install:
```shell
$ pip install mashumaro
```

The current version of `mashumaro` supports Python versions 3.9 — 3.14.


It's not recommended to use any version of Python that has reached its
[end of life](https://devguide.python.org/versions/) and is no longer receiving
security updates or bug fixes from the Python development team.
For convenience, there is a table below that outlines the
last version of `mashumaro` that can be installed on unmaintained versions
of Python.

| Python Version | Last Version of mashumaro                                          | Python EOL |
|----------------|--------------------------------------------------------------------|------------|
| 3.8            | [3.14](https://github.com/Fatal1ty/mashumaro/releases/tag/v3.14)   | 2024-10-07 |
| 3.7            | [3.9.1](https://github.com/Fatal1ty/mashumaro/releases/tag/v3.9.1) | 2023-06-27 |
| 3.6            | [3.1.1](https://github.com/Fatal1ty/mashumaro/releases/tag/v3.1.1) | 2021-12-23 |


Changelog
-------------------------------------------------------------------------------

This project follows the principles of [Semantic Versioning](https://semver.org).
Changelog is available on [GitHub Releases page](https://github.com/Fatal1ty/mashumaro/releases).

Supported data types
-------------------------------------------------------------------------------

There is support for generic types from the standard [`typing`](https://docs.python.org/3/library/typing.html) module:
* [`List`](https://docs.python.org/3/library/typing.html#typing.List)
* [`Tuple`](https://docs.python.org/3/library/typing.html#typing.Tuple)
* [`NamedTuple`](https://docs.python.org/3/library/typing.html#typing.NamedTuple)
* [`Set`](https://docs.python.org/3/library/typing.html#typing.Set)
* [`FrozenSet`](https://docs.python.org/3/library/typing.html#typing.FrozenSet)
* [`Deque`](https://docs.python.org/3/library/typing.html#typing.Deque)
* [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)
* [`OrderedDict`](https://docs.python.org/3/library/typing.html#typing.OrderedDict)
* [`DefaultDict`](https://docs.python.org/3/library/typing.html#typing.DefaultDict)
* [`TypedDict`](https://docs.python.org/3/library/typing.html#typing.TypedDict)
* [`Mapping`](https://docs.python.org/3/library/typing.html#typing.Mapping)
* [`MutableMapping`](https://docs.python.org/3/library/typing.html#typing.MutableMapping)
* [`Counter`](https://docs.python.org/3/library/typing.html#typing.Counter)
* [`ChainMap`](https://docs.python.org/3/library/typing.html#typing.ChainMap)
* [`Sequence`](https://docs.python.org/3/library/typing.html#typing.Sequence)

for standard generic types on [PEP 585](https://www.python.org/dev/peps/pep-0585/) compatible Python (3.9+):
* [`list`](https://docs.python.org/3/library/stdtypes.html#list)
* [`tuple`](https://docs.python.org/3/library/stdtypes.html#tuple)
* [`namedtuple`](https://docs.python.org/3/library/collections.html#collections.namedtuple)
* [`set`](https://docs.python.org/3/library/stdtypes.html#set)
* [`frozenset`](https://docs.python.org/3/library/stdtypes.html#frozenset)
* [`collections.abc.Set`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Set)
* [`collections.abc.MutableSet`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableSet)
* [`collections.deque`](https://docs.python.org/3/library/collections.html#collections.deque)
* [`dict`](https://docs.python.org/3/library/stdtypes.html#dict)
* [`collections.OrderedDict`](https://docs.python.org/3/library/collections.html#collections.OrderedDict)
* [`collections.defaultdict`](https://docs.python.org/3/library/collections.html#collections.defaultdict)
* [`collections.abc.Mapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)
* [`collections.abc.MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)
* [`collections.Counter`](https://docs.python.org/3/library/collections.html#collections.Counter)
* [`collections.ChainMap`](https://docs.python.org/3/library/collections.html#collections.ChainMap)
* [`collections.abc.Sequence`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence)
* [`collections.abc.MutableSequence`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableSequence)

for special primitives from the [`typing`](https://docs.python.org/3/library/typing.html) module:
* [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)
* [`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)
* [`Union`](https://docs.python.org/3/library/typing.html#typing.Union)
* [`TypeVar`](https://docs.python.org/3/library/typing.html#typing.TypeVar)
* [`TypeVarTuple`](https://docs.python.org/3/library/typing.html#typing.TypeVarTuple)
* [`NewType`](https://docs.python.org/3/library/typing.html#newtype)
* [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated)
* [`Literal`](https://docs.python.org/3/library/typing.html#typing.Literal)
* [`LiteralString`](https://docs.python.org/3/library/typing.html#typing.LiteralString)
* [`Final`](https://docs.python.org/3/library/typing.html#typing.Final)
* [`Self`](https://docs.python.org/3/library/typing.html#typing.Self)
* [`Unpack`](https://docs.python.org/3/library/typing.html#typing.Unpack)
* [`ReadOnly`](https://docs.python.org/3/library/typing.html#typing.ReadOnly)

for standard interpreter types from [`types`](https://docs.python.org/3/library/types.html#standard-interpreter-types) module:
* [`NoneType`](https://docs.python.org/3/library/types.html#types.NoneType)
* [`UnionType`](https://docs.python.org/3/library/types.html#types.UnionType)
* [`MappingProxyType`](https://docs.python.org/3/library/types.html#types.MappingProxyType)

for enumerations based on classes from the standard [`enum`](https://docs.python.org/3/library/enum.html) module:
* [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)
* [`IntEnum`](https://docs.python.org/3/library/enum.html#enum.IntEnum)
* [`StrEnum`](https://docs.python.org/3/library/enum.html#enum.StrEnum)
* [`Flag`](https://docs.python.org/3/library/enum.html#enum.Flag)
* [`IntFlag`](https://docs.python.org/3/library/enum.html#enum.IntFlag)

for common built-in types:
* [`int`](https://docs.python.org/3/library/functions.html#int)
* [`float`](https://docs.python.org/3/library/functions.html#float)
* [`bool`](https://docs.python.org/3/library/stdtypes.html#bltin-boolean-values)
* [`str`](https://docs.python.org/3/library/stdtypes.html#str)
* [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes)
* [`bytearray`](https://docs.python.org/3/library/stdtypes.html#bytearray)

for built-in datetime oriented types (see [more](#deserialize-option) details):
* [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime)
* [`date`](https://docs.python.org/3/library/datetime.html#datetime.date)
* [`time`](https://docs.python.org/3/library/datetime.html#datetime.time)
* [`timedelta`](https://docs.python.org/3/library/datetime.html#datetime.timedelta)
* [`timezone`](https://docs.python.org/3/library/datetime.html#datetime.timezone)
* [`ZoneInfo`](https://docs.python.org/3/library/zoneinfo.html#zoneinfo.ZoneInfo)

for pathlike types:
* [`PurePath`](https://docs.python.org/3/library/pathlib.html#pathlib.PurePath)
* [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)
* [`PurePosixPath`](https://docs.python.org/3/library/pathlib.html#pathlib.PurePosixPath)
* [`PosixPath`](https://docs.python.org/3/library/pathlib.html#pathlib.PosixPath)
* [`PureWindowsPath`](https://docs.python.org/3/library/pathlib.html#pathlib.PureWindowsPath)
* [`WindowsPath`](https://docs.python.org/3/library/pathlib.html#pathlib.WindowsPath)
* [`os.PathLike`](https://docs.python.org/3/library/os.html#os.PathLike)

for other less popular built-in types:
* [`uuid.UUID`](https://docs.python.org/3/library/uuid.html#uuid.UUID)
* [`decimal.Decimal`](https://docs.python.org/3/library/decimal.html#decimal.Decimal)
* [`fractions.Fraction`](https://docs.python.org/3/library/fractions.html#fractions.Fraction)
* [`ipaddress.IPv4Address`](https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv4Address)
* [`ipaddress.IPv6Address`](https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv6Address)
* [`ipaddress.IPv4Network`](https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv4Network)
* [`ipaddress.IPv6Network`](https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv6Network)
* [`ipaddress.IPv4Interface`](https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv4Interface)
* [`ipaddress.IPv6Interface`](https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv6Interface)
* [`typing.Pattern`](https://docs.python.org/3/library/typing.html#typing.Pattern)
* [`re.Pattern`](https://docs.python.org/3/library/re.html#re.Pattern)

for backported types from [`typing-extensions`](https://github.com/python/typing_extensions):
* [`OrderedDict`](https://docs.python.org/3/library/typing.html#typing.OrderedDict)
* [`TypedDict`](https://docs.python.org/3/library/typing.html#typing.TypedDict)
* [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated)
* [`Literal`](https://docs.python.org/3/library/typing.html#typing.Literal)
* [`LiteralString`](https://docs.python.org/3/library/typing.html#typing.LiteralString)
* [`Self`](https://docs.python.org/3/library/typing.html#typing.Self)
* [`TypeVarTuple`](https://docs.python.org/3/library/typing.html#typing.TypeVarTuple)
* [`Unpack`](https://docs.python.org/3/library/typing.html#typing.Unpack)
* [`ReadOnly`](https://docs.python.org/3/library/typing.html#typing.ReadOnly)

for arbitrary types:
* [user-defined types](#user-defined-types)
* [third-party types](#third-party-types)
* [user-defined generic types](#user-defined-generic-types)
* [third-party generic types](#third-party-generic-types)

Usage example
-------------------------------------------------------------------------------

Suppose we're developing a financial application and we operate with currencies
and stocks:

```python
from dataclasses import dataclass
from enum import Enum

class Currency(Enum):
    USD = "USD"
    EUR = "EUR"

@dataclass
class CurrencyPosition:
    currency: Currency
    balance: float

@dataclass
class StockPosition:
    ticker: str
    name: str
    balance: int
```

Now we want a dataclass for portfolio that will be serialized to and from JSON.
We inherit `DataClassJSONMixin` that adds this functionality:

```python
from mashumaro.mixins.json import DataClassJSONMixin

...

@dataclass
class Portfolio(DataClassJSONMixin):
    currencies: list[CurrencyPosition]
    stocks: list[StockPosition]
```

Let's create a portfolio instance and check methods `from_json` and `to_json`:

```python
portfolio = Portfolio(
    currencies=[
        CurrencyPosition(Currency.USD, 238.67),
        CurrencyPosition(Currency.EUR, 361.84),
    ],
    stocks=[
        StockPosition("AAPL", "Apple", 10),
        StockPosition("AMZN", "Amazon", 10),
    ]
)

portfolio_json = portfolio.to_json()
assert Portfolio.from_json(portfolio_json) == portfolio
```

If we need to serialize something different from a root dataclass,
we can use codecs. In the following example we create a JSON decoder and encoder
for a list of currencies:

```python
from mashumaro.codecs.json import JSONDecoder, JSONEncoder

...

decoder = JSONDecoder(list[CurrencyPosition])
encoder = JSONEncoder(list[CurrencyPosition])

currencies = [
    CurrencyPosition(Currency.USD, 238.67),
    CurrencyPosition(Currency.EUR, 361.84),
]
currencies_json = encoder.encode(currencies)
assert decoder.decode(currencies_json) == currencies

```

How does it work?
-------------------------------------------------------------------------------

This library works by taking the schema of the data and generating a
specific decoder and encoder for exactly that schema, taking into account the
specifics of serialization format. This is much faster than inspection of
data types on every call of decoding or encoding at runtime.

These specific decoders and encoders are generated by
[codecs and mixins](#supported-serialization-formats):
* When using codecs, these methods are compiled during the creation of the
  decoder or encoder.
* When using serialization
mixins, these methods are compiled during import time (or at runtime in some
cases) and are set as attributes to your dataclasses. To minimize the import
time, you can explicitly enable
[lazy compilation](#lazy_compilation-config-option).

Benchmark
-------------------------------------------------------------------------------

* macOS 15.1 Sequoia
* Apple M3 Max
* 36GB RAM
* Python 3.13.0

Benchmark using [pyperf](https://github.com/psf/pyperf) with GitHub Issue model. Please note that the
following charts use logarithmic scale, as it is convenient for displaying
very large ranges of values.

<picture>
  <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/Fatal1ty/mashumaro/refs/heads/master/benchmark/charts/load_light.svg">
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Fatal1ty/mashumaro/refs/heads/master/benchmark/charts/load_dark.svg">
  <img src="https://raw.githubusercontent.com/Fatal1ty/mashumaro/refs/heads/master/benchmark/charts/load_light.svg" width="604">
</picture>
<picture>
  <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/Fatal1ty/mashumaro/refs/heads/master/benchmark/charts/dump_light.svg">
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Fatal1ty/mashumaro/refs/heads/master/benchmark/charts/dump_dark.svg">
  <img src="https://raw.githubusercontent.com/Fatal1ty/mashumaro/refs/heads/master/benchmark/charts/dump_light.svg" width="604">
</picture>

> [!NOTE]\
> Benchmark results may vary depending on the specific configuration and
> parameters used for serialization and deserialization. However, we have made
> an attempt to use the available options that can speed up and smooth out the
> differences in how libraries work.

To run benchmark in your environment:
```bash
git clone git@github.com:Fatal1ty/mashumaro.git
cd mashumaro
python3 -m venv env && source env/bin/activate
pip install -e .
pip install -r requirements-dev.txt
./benchmark/run.sh
```

Supported serialization formats
-------------------------------------------------------------------------------

This library has built-in support for multiple popular formats:

* [JSON](https://www.json.org)
* [YAML](https://yaml.org)
* [TOML](https://toml.io)
* [MessagePack](https://msgpack.org)

There are preconfigured codecs and mixin classes. However, you're free
to override some settings if necessary.

> [!IMPORTANT]\
> As for codecs, you are
> offered to choose between convenience and efficiency. When you need to decode
> or encode typed data more than once, it's highly recommended to create
> and reuse a decoder or encoder specifically for that data type. For one-time
> use with default settings it may be convenient to use global functions that
> create a disposable decoder or encoder under the hood. Remember that you
> should not use these convenient global functions more that once for the same
> data type if performance is important to you.

### Basic form

Basic form denotes a python object consisting only of basic data types
supported by most serialization formats. These types are:
[`str`](https://docs.python.org/3/library/stdtypes.html#str),
[`int`](https://docs.python.org/3/library/functions.html#int),
[`float`](https://docs.python.org/3/library/functions.html#float),
[`bool`](https://docs.python.org/3/library/stdtypes.html#bltin-boolean-values),
[`list`](https://docs.python.org/3/library/stdtypes.html#list),
[`dict`](https://docs.python.org/3/library/stdtypes.html#dict).

This is also a starting point you can play with for a comprehensive
transformation of your data.

Efficient decoder and encoder can be used as follows:

```python
from mashumaro.codecs import BasicDecoder, BasicEncoder
# or from mashumaro.codecs.basic import BasicDecoder, BasicEncoder

decoder = BasicDecoder(<shape_type>, ...)
decoder.decode(...)

encoder = BasicEncoder(<shape_type>, ...)
encoder.encode(...)
```

Convenient functions are recommended to be used as follows:
```python
import mashumaro.codecs.basic as basic_codec

basic_codec.decode(..., <shape_type>)
basic_codec.encode(..., <shape_type>)
```

Mixin can be used as follows:
```python
from mashumaro import DataClassDictMixin
# or from mashumaro.mixins.dict import DataClassDictMixin

@dataclass
class MyModel(DataClassDictMixin):
    ...

MyModel.from_dict(...)
MyModel(...).to_dict()
```

> [!TIP]\
> You don't need to inherit `DataClassDictMixin` along with other serialization
> mixins because it's a base class for them.

### JSON

[JSON](https://www.json.org) is a lightweight data-interchange format. You can
choose between standard library
[json](https://docs.python.org/3/library/json.html) for compatibility and
third-party dependency [orjson](https://pypi.org/project/orjson/) for better
performance.

#### json library

Efficient decoder and encoder can be used as follows:
```python
from mashumaro.codecs.json import JSONDecoder, JSONEncoder

decoder = JSONDecoder(<shape_type>, ...)
decoder.decode(...)

encoder = JSONEncoder(<shape_type>, ...)
encoder.encode(...)
```

Convenient functions can be used as follows:
```python
from mashumaro.codecs.json import json_decode, json_encode

json_decode(..., <shape_type>)
json_encode(..., <shape_type>)
```

Convenient function aliases are recommended to be used as follows:
```python
import mashumaro.codecs.json as json_codec

json_codec.decode(...<shape_type>)
json_codec.encode(..., <shape_type>)
```

Mixin can be used as follows:
```python
from mashumaro.mixins.json import DataClassJSONMixin

@dataclass
class MyModel(DataClassJSONMixin):
    ...

MyModel.from_json(...)
MyModel(...).to_json()
```

#### orjson library

In order to use [`orjson`](https://pypi.org/project/orjson/) library, it must
be installed manually or using an extra option for `mashumaro`:

```shell
pip install mashumaro[orjson]
```

The following data types will be handled by
[`orjson`](https://pypi.org/project/orjson/) library by default:
* [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime)
* [`date`](https://docs.python.org/3/library/datetime.html#datetime.date)
* [`time`](https://docs.python.org/3/library/datetime.html#datetime.time)
* [`uuid.UUID`](https://docs.python.org/3/library/uuid.html#uuid.UUID)

Efficient decoder and encoder can be used as follows:
```python
from mashumaro.codecs.orjson import ORJSONDecoder, ORJSONEncoder

decoder = ORJSONDecoder(<shape_type>, ...)
decoder.decode(...)

encoder = ORJSONEncoder(<shape_type>, ...)
encoder.encode(...)
```

Convenient functions can be used as follows:
```python
from mashumaro.codecs.orjson import json_decode, json_encode

json_decode(..., <shape_type>)
json_encode(..., <shape_type>)
```

Convenient function aliases are recommended to be used as follows:
```python
import mashumaro.codecs.orjson as json_codec

json_codec.decode(...<shape_type>)
json_codec.encode(..., <shape_type>)
```

Mixin can be used as follows:
```python
from mashumaro.mixins.orjson import DataClassORJSONMixin

@dataclass
class MyModel(DataClassORJSONMixin):
    ...

MyModel.from_json(...)
MyModel(...).to_json()
MyModel(...).to_jsonb()
```

### YAML

[YAML](https://yaml.org) is a human-friendly data serialization language for
all programming languages. In order to use this format, the
[`pyyaml`](https://pypi.org/project/PyYAML/) package must be installed.
You can install it manually or using an extra option for `mashumaro`:

```shell
pip install mashumaro[yaml]
```

Efficient decoder and encoder can be used as follows:
```python
from mashumaro.codecs.yaml import YAMLDecoder, YAMLEncoder

decoder = YAMLDecoder(<shape_type>, ...)
decoder.decode(...)

encoder = YAMLEncoder(<shape_type>, ...)
encoder.encode(...)
```

Convenient functions can be used as follows:
```python
from mashumaro.codecs.yaml import yaml_decode, yaml_encode

yaml_decode(..., <shape_type>)
yaml_encode(..., <shape_type>)
```

Convenient function aliases are recommended to be used as follows:
```python
import mashumaro.codecs.yaml as yaml_codec

yaml_codec.decode(...<shape_type>)
yaml_codec.encode(..., <shape_type>)
```

Mixin can be used as follows:
```python
from mashumaro.mixins.yaml import DataClassYAMLMixin

@dataclass
class MyModel(DataClassYAMLMixin):
    ...

MyModel.from_yaml(...)
MyModel(...).to_yaml()
```

### TOML

[TOML](https://toml.io) is config file format for humans.
In order to use this format, the [`tomli`](https://pypi.org/project/tomli/) and
[`tomli-w`](https://pypi.org/project/tomli-w/) packages must be installed.
In Python 3.11+, `tomli` is included as
[`tomlib`](https://docs.python.org/3/library/tomllib.html) standard library
module and is used for this format. You can install the missing packages
manually or using an extra option
for `mashumaro`:

```shell
pip install mashumaro[toml]
```

The following data types will be handled by
[`tomli`](https://pypi.org/project/tomli/)/
[`tomli-w`](https://pypi.org/project/tomli-w/) library by default:
* [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime)
* [`date`](https://docs.python.org/3/library/datetime.html#datetime.date)
* [`time`](https://docs.python.org/3/library/datetime.html#datetime.time)

Fields with value `None` will be omitted on serialization because TOML
doesn't support null values.

Efficient decoder and encoder can be used as follows:
```python
from mashumaro.codecs.toml import TOMLDecoder, TOMLEncoder

decoder = TOMLDecoder(<shape_type>, ...)
decoder.decode(...)

encoder = TOMLEncoder(<shape_type>, ...)
encoder.encode(...)
```

Convenient functions can be used as follows:
```python
from mashumaro.codecs.toml import toml_decode, toml_encode

toml_decode(..., <shape_type>)
toml_encode(..., <shape_type>)
```

Convenient function aliases are recommended to be used as follows:
```python
import mashumaro.codecs.toml as toml_codec

toml_codec.decode(...<shape_type>)
toml_codec.encode(..., <shape_type>)
```

Mixin can be used as follows:
```python
from mashumaro.mixins.toml import DataClassTOMLMixin

@dataclass
class MyModel(DataClassTOMLMixin):
    ...

MyModel.from_toml(...)
MyModel(...).to_toml()
```

### MessagePack

[MessagePack](https://msgpack.org) is an efficient binary serialization format.
In order to use this mixin, the [`msgpack`](https://pypi.org/project/msgpack/)
package must be installed. You can install it manually or using an extra
option for `mashumaro`:

```shell
pip install mashumaro[msgpack]
```

The following data types will be handled by
[`msgpack`](https://pypi.org/project/msgpack/) library by default:
* [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes)
* [`bytearray`](https://docs.python.org/3/library/stdtypes.html#bytearray)

Efficient decoder and encoder can be used as follows:
```python
from mashumaro.codecs.msgpack import MessagePackDecoder, MessagePackEncoder

decoder = MessagePackDecoder(<shape_type>, ...)
decoder.decode(...)

encoder = MessagePackEncoder(<shape_type>, ...)
encoder.encode(...)
```

Convenient functions can be used as follows:
```python
from mashumaro.codecs.msgpack import msgpack_decode, msgpack_encode

msgpack_decode(..., <shape_type>)
msgpack_encode(..., <shape_type>)
```

Convenient function aliases are recommended to be used as follows:
```python
import mashumaro.codecs.msgpack as msgpack_codec

msgpack_codec.decode(...<shape_type>)
msgpack_codec.encode(..., <shape_type>)
```

Mixin can be used as follows:
```python
from mashumaro.mixins.msgpack import DataClassMessagePackMixin

@dataclass
class MyModel(DataClassMessagePackMixin):
    ...

MyModel.from_msgpack(...)
MyModel(...).to_msgpack()
```

Customization
-------------------------------------------------------------------------------

Customization options of `mashumaro` are extensive and will most likely cover your needs.
When it comes to non-standard data types and non-standard serialization support, you can do the following:
* Turn an existing regular or generic class into a serializable one
by inheriting the [`SerializableType`](#serializabletype-interface) class
* Write different serialization strategies for an existing regular or generic type that is not under your control
using [`SerializationStrategy`](#serializationstrategy) class
* Define serialization / deserialization methods:
  * for a specific dataclass field by using [field options](#field-options)
  * for a specific data type used in the dataclass by using [`Config`](#config-options) class
* Alter input and output data with serialization / deserialization [hooks](#serialization-hooks)
* Separate serialization scheme from a dataclass in a reusable manner using [dialects](#dialects)
* Choose from predefined serialization engines for the specific data types, e.g. `datetime` and `NamedTuple`

### SerializableType interface

If you have a custom class or hierarchy of classes whose instances you want
to serialize with `mashumaro`, the first option is to implement
`SerializableType` interface.

#### User-defined types

Let's look at this not very practicable example:

```python
from dataclasses import dataclass
from mashumaro import DataClassDictMixin
from mashumaro.types import SerializableType

class Airport(SerializableType):
    def __init__(self, code, city):
        self.code, self.city = code, city

    def _serialize(self):
        return [self.code, self.city]

    @classmethod
    def _deserialize(cls, value):
        return cls(*value)

    def __eq__(self, other):
        return self.code, self.city == other.code, other.city

@dataclass
class Flight(DataClassDictMixin):
    origin: Airport
    destination: Airport

JFK = Airport("JFK", "New York City")
LAX = Airport("LAX", "Los Angeles")

input_data = {
    "origin": ["JFK", "New York City"],
    "destination": ["LAX", "Los Angeles"]
}
my_flight = Flight.from_dict(input_data)
assert my_flight == Flight(JFK, LAX)
assert my_flight.to_dict() == input_data
```

You can see how `Airport` instances are seamlessly created from lists of two
strings and serialized into them.

By default `_deserialize` method will get raw input data without any
transformations before. This should be enough in many cases, especially when
you need to perform non-standard transformations yourself, but let's extend
our example:

```python
class Itinerary(SerializableType):
    def __init__(self, flights):
        self.flights = flights

    def _serialize(self):
        return self.flights

    @classmethod
    def _deserialize(cls, flights):
        return cls(flights)

@dataclass
class TravelPlan(DataClassDictMixin):
    budget: float
    itinerary: Itinerary

input_data = {
    "budget": 10_000,
    "itinerary": [
        {
            "origin": ["JFK", "New York City"],
            "destination": ["LAX", "Los Angeles"]
        },
        {
            "origin": ["LAX", "Los Angeles"],
            "destination": ["SFO", "San Fransisco"]
        }
    ]
}
```

If we pass the flight list as is into `Itinerary._deserialize`, our itinerary
will have something that we may not expect — `list[dict]` instead of
`list[Flight]`. The solution is quite simple. Instead of calling
`Flight._deserialize` yourself, just use annotations:

```python
class Itinerary(SerializableType, use_annotations=True):
    def __init__(self, flights):
        self.flights = flights

    def _serialize(self) -> list[Flight]:
        return self.flights

    @classmethod
    def _deserialize(cls, flights: list[Flight]):
        return cls(flights)

my_plan = TravelPlan.from_dict(input_data)
assert isinstance(my_plan.itinerary.flights[0], Flight)
assert isinstance(my_plan.itinerary.flights[1], Flight)
assert my_plan.to_dict() == input_data
```

Here we add annotations to the only argument of `_deserialize` method and
to the return value of `_serialize` method as well. The latter is needed for
correct serialization.

> [!IMPORTANT]\
> The importance of explicit passing `use_annotations=True` when defining a
> class is that otherwise implicit using annotations might break compatibility
> with old code that wasn't aware of this feature. It will be enabled by
> default in the future major release.

#### User-defined generic types

The great thing to note about using annotations in `SerializableType` is that
they work seamlessly with [generic](https://docs.python.org/3/library/typing.html#user-defined-generic-types)
and [variadic generic](https://peps.python.org/pep-0646/) types.
Let's see how this can be useful:

```python
from datetime import date
from typing import TypeVar
from dataclasses import dataclass
from mashumaro import DataClassDictMixin
from mashumaro.types import SerializableType

KT = TypeVar("KT")
VT = TypeVar("VT")

class DictWrapper(dict[KT, VT], SerializableType, use_annotations=True):
    def _serialize(self) -> dict[KT, VT]:
        return dict(self)

    @classmethod
    def _deserialize(cls, value: dict[KT, VT]) -> 'DictWrapper[KT, VT]':
        return cls(value)

@dataclass
class DataClass(DataClassDictMixin):
    x: DictWrapper[date, str]
    y: DictWrapper[str, date]

input_data = {
    "x": {"2022-12-07": "2022-12-07"},
    "y": {"2022-12-07": "2022-12-07"}
}
obj = DataClass.from_dict(input_data)
assert obj == DataClass(
    x=DictWrapper({date(2022, 12, 7): "2022-12-07"}),
    y=DictWrapper({"2022-12-07": date(2022, 12, 7)})
)
assert obj.to_dict() == input_data
```

You can see that formatted date is deserialized to `date` object before passing
to `DictWrapper._deserialize` in a key or value according to the generic
parameters.

If you have generic dataclass types, you can use `SerializableType` for them as well, but it's not necessary since
they're [supported](#generic-dataclasses) out of the box.

### SerializationStrategy

If you want to add support for a custom third-party type that is not under your control,
you can write serialization and deserialization logic inside `SerializationStrategy` class,
which will be reusable and so well suited in case that third-party type is widely used.
`SerializationStrategy` is also good if you want to create strategies that are slightly different from each other,
because you can add the strategy differentiator in the `__init__` method.

#### Third-party types

To demonstrate how `SerializationStrategy` works let's write a simple strategy for datetime serialization
in different formats. In this example we will use the same strategy class for two dataclass fields,
but a string representing the date and time will be different.

```python
from dataclasses import dataclass, field
from datetime import datetime
from mashumaro import DataClassDictMixin, field_options
from mashumaro.types import SerializationStrategy

class FormattedDateTime(SerializationStrategy):
    def __init__(self, fmt):
        self.fmt = fmt

    def serialize(self, value: datetime) -> str:
        return value.strftime(self.fmt)

    def deserialize(self, value: str) -> datetime:
        return datetime.strptime(value, self.fmt)

@dataclass
class DateTimeFormats(DataClassDictMixin):
    short: datetime = field(
        metadata=field_options(
            serialization_strategy=FormattedDateTime("%d%m%Y%H%M%S")
        )
    )
    verbose: datetime = field(
        metadata=field_options(
            serialization_strategy=FormattedDateTime("%A %B %d, %Y, %H:%M:%S")
        )
    )

formats = DateTimeFormats(
    short=datetime(2019, 1, 1, 12),
    verbose=datetime(2019, 1, 1, 12),
)
dictionary = formats.to_dict()
# {'short': '01012019120000', 'verbose': 'Tuesday January 01, 2019, 12:00:00'}
assert DateTimeFormats.from_dict(dictionary) == formats
```

Similarly to `SerializableType`, `SerializationStrategy` could also take advantage of annotations:

```python
from dataclasses import dataclass
from datetime import datetime
from mashumaro impo