NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #4109 most downloaded on PyPI
Yet another serialization library on top of dataclasses
Last release 15 days ago
19 Sep 2026
Ships fairly regularly
a new release about every 3 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
8 years old
118 releases · first in 2018
Fix internal tagging with deny_unknown_fields by @AllanChain in #798
Full Changelog: v0.33.0...v0.33.1
Support PEP 747 TypeForm in deserialization APIs by @yukinarit in #796
Full Changelog: v0.32.2...v0.33.0
One column per quarter.
Update typing-extensions requirement from <4.16.0,>=4.1.0 to >=4.1.0,<4.17.0 by @dependabot [bot] in #788
Full Changelog: v0.32.1...v0.32.2
Recognize ClassVar when detecting dataclasses by @AllanChain in #786
Full Changelog: v0.32.0...v0.32.1
Add custom coercer API by @AllanChain in #781
Full Changelog: v0.31.8...v0.32.0
Fix flatten on an optional dataclass field with a default by @sarathfrancis90 in #776
Full Changelog: v0.31.7...v0.31.8
Fix alias for non-primitive fields by @sarathfrancis90 in #773
Full Changelog: v0.31.6...v0.31.7
Fix Union[None, X] being serialized as null after Optional[X] by @gaoflow in #764
Full Changelog: v0.31.5...v0.31.6
Apply global class (de)serializers to top-level values (fixes #514 ) by @gaoflow in #762
Full Changelog: v0.31.4...v0.31.5
Fix deserialization with skip by @PingPongun in #751
skip by @PingPongun in #751Full Changelog: v0.31.3...v0.31.4
Bump the uv group across 2 directories with 2 updates by @dependabot [bot] in #744
Full Changelog: v0.31.2...v0.31.3
skip ignored fields in compat walkers by @AllanChain in #739
Full Changelog: v0.31.1...v0.31.2
Fix from_dict for Optional values in collections by @AllanChain in #733
Full Changelog: v0.31.0...v0.31.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.30.1...v0.31.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.30.0...v0.30.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.29.1...v0.30.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.29.0...v0.29.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.28.0...v0.29.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.27.0...v0.28.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.26.2...v0.27.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.26.1...v0.26.2
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.26.0...v0.26.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
multilingual form book.toml by @yukinarit in https://github.com/yukinarit/pyserde/pull/677Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.25.1...v0.26.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.25.0...v0.25.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.24.0...v0.25.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
numpy>2.0.0 by @krylowicz in https://github.com/yukinarit/pyserde/pull/649jaxtyping<0.3.0 and typing_extensions>=4.1.0,<4.13.0 by @krylowicz in https://github.com/yukinarit/pyserde/pull/644Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.23.0...v0.24.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.22.3...v0.23.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.22.2...v0.22.3
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.22.1...v0.22.2
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.22.0...v0.22.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.21.0...v0.22.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.20.1...v0.21.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.20.0...v0.20.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.19.4...v0.20.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.19.3...v0.19.4
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.19.2...v0.19.3
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.19.1...v0.19.2
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Special Thanks to @K-dash for translating pyserde guide to Japanese! :pray::tada:
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.19.0...v0.19.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.18.0...v0.19.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.17.1...v0.18.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.17.0...v0.17.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
pyserde now experimentally support SQLAlchemy integration. Thanks @barsa-net for nice work!
@serde
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(Text, nullable=False)
fullname: Mapped[str] = mapped_column(Text, nullable=False)
nickname: Mapped[Optional[str]] = mapped_column(Text)
attributes: Mapped[Optional[dict[str, str]]] = mapped_column(JSON)
projects: Mapped[list[Project]] = relationship(backref="owner")
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.16.1...v0.17.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.16.0...v0.16.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.15.0...v0.16.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
is_bearable to isinstance by @rtbs-dev in https://github.com/yukinarit/pyserde/pull/485Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.14.2...v0.15.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.14.1...v0.14.2
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.14.0...v0.14.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
pyserde's strict type check system is overhauled by using beartype - O(1) runtime type checker. all pyserde classes now implicitly implement beartype decorator by default. Passing wrong type of values in constructor raises beartype's validation error.
@serde
class Foo:
s: str
If you call Foo with wrong type of object, beartype validation error is raised.
>>> foo = Foo(10)
beartype.roar.BeartypeCallHintParamViolation: Method __main__.Foo.__init__()
parameter s=10 violates type hint <class 'str'>, as int 10 not instance of str.
If you deserialize with wrong value, serde error is raised.
>>> print(from_json(Foo, '{"s": 10}'))
serde.compat.SerdeError: Method __main__.Foo.__init__()
parameter s=10 violates type hint <class 'str'>, as int 10 not instance of str.
If you want to disable type check, set either serde.disabled or serde.coerce in type_check class attribute.
from serde import serde, disabled
@serde(type_check=disabled)
class Foo:
s: str
See https://yukinarit.github.io/pyserde/guide/en/type-check.html for more information.
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.13.2...v0.14.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.13.1...v0.13.2
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.13.0...v0.13.1
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
New custom class (de)serializer allows to extend pyserde to support third party types in a neat and robust way. Also custom global (de)serializer is a game changer to allow sharing and reusing custom serializers across different python projects. See custom class serializer and custom global serializer for more information.
e.g. Implementing serializer for datetime and int
class Serializer:
# Custom serializer for "datetime"
@overload
def serialize(self, value: datetime) -> str:
return value.strftime("%d/%m/%y")
# Custom serializer for "int"
@overload
def serialize(self, value: int) -> Any:
return str(value)
....
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.12.7...v0.13.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
skip_if causing serialization of a recursive type to be O(2**n) instead of O(n) by @gschaffner in https://github.com/yukinarit/pyserde/pull/452Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.12.6...v0.12.7
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.12.5...v0.12.6
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.12.4...v0.12.5
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.12.3...v0.12.4
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.12.2...v0.12.3
<!-- Release notes generated using configuration in .github/release.yml at v0.12.2 -->
<!-- Release notes generated using configuration in .github/release.yml at v0.12.2 -->
kw_only by @m472 in https://github.com/yukinarit/pyserde/pull/413frozen and kw_only support by @yukinarit in https://github.com/yukinarit/pyserde/pull/415Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.12.1...v0.12.2
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.12.0...v0.12.1
However, This will introduce a breaking change!! The default behaviour when you pass Union directly was "Untagged" until v0.11.1, but since v0.12.0 it…
<!-- Release notes generated using configuration in .github/release.yml at main -->
This example works correctly now
@serde
@dataclass
class Foo:
a: int
@serde
@dataclass
class Bar:
a: int
bar = Bar(10)
s = to_json(bar)
print(s)
print(from_json(Union[Foo, Bar], s))
However, This will introduce a breaking change!! The default behaviour when you pass Union directly was "Untagged" until v0.11.1, but since v0.12.0 it is "ExternalTagging".
The following code prints {"a": 10} until v0.11.1, but prints {"Bar": {"a": 10}} since v0.12.0
print(to_json(bar))
For more information about Union, please see the docs
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.11.1...v0.12.0
<!-- Release notes generated using configuration in .github/release.yml at main -->
<!-- Release notes generated using configuration in .github/release.yml at main -->
Full Changelog: https://github.com/yukinarit/pyserde/compare/v0.11.0...v0.11.1
Your coding agent can read these notes before it upgrades. Set up the MCP server →