
1059 stars · MIT (named in the About sidebar) · v26.2.1 (2026-09-26), shown on /releases/latest as '26 Sep' with no year and settled from the Python package index · Track this in Scout
Turns loose data such as a parsed JSON document into declared Python objects, and back again.
Radar check
What we found when we opened it. Every bar is one fact, with its date.
Last code pushed 25 Oct 2026, the same day before this check.
Latest release v26.2.1 on 26 Sep 2026.
Public since August 2016, a little over 10 years.
1,059 stars and 185 forks.
28 commits and 7 new issues in the last 90 days.
93 contributors. 18 pull requests merged in 90 days.
A security policy says how to report a problem. No published security advisories.
How the bars are scored
- Alive. Days since the last code push: a week or less 100, a month 90, three months 70, six months 50, a year 30, eighteen months 15, older 0.
- Releases. Age of the latest GitHub release, on a similar scale; no bar when the project publishes no releases.
- Maturity. Age of the project: eight years 100, five 90, three 70, two 55, one 40, six months 25, younger 10.
- Adoption. Stars on a log scale: 100,000 stars is 100, 10,000 is 80, 1,000 is 60, 100 is 40.
- Activity. Commits in the last 90 days: 300 or more 100, 100 85, 30 65, 10 45, any 25.
- Community. People who have contributed: 100 or more 100, 30 80, 10 60, 5 40, 2 25, one 10.
- Security. A published security policy 80, none 40; published advisories are listed, not scored.
Checked by Repo Radar on 25 Oct 2026 from the repository on GitHub. Covered in Edition 61.
▶Repo detailsthe review · specs · pros & cons · install
What it does
You give it a pile of plain Python values — the kind a parsed JSON document produces — and the class you expect them to be. It builds that class, following the type annotations you already wrote, and complains where the data does not fit. It handles the awkward cases: optional values, lists, tuples, sets, dictionaries, typed dictionaries and unions. Going the other way, it flattens an object back into plain values ready to be written out. It ships nine ready-made converters tuned for particular output libraries, including the standard JSON module, orjson, msgpack, CBOR, BSON, YAML and TOML, so the quirks of each are already handled. It needs Python 3.10 or newer. It does not define your classes — those come from attrs or from the standard dataclasses — and it does no reading or writing itself: the actual serialising is handed to whichever library you chose.
Why it matters
Who it suits. Anyone whose Python code receives JSON and then checks fields by hand, and anyone who has written the same "turn this dictionary into an object" function three times. It fits a project that already uses dataclasses and does not want to rewrite every model class to adopt a framework. Skip it if validation itself is the main need, because this converts rather than enforces rules.
Verdict. Half an hour, and the thing to understand is where it sits. It is deliberately not a model framework: you keep your own classes and it converts them, which is precisely why it suits a codebase that already has classes it likes. Code was pushed on the morning of this edition and version 26.2.1 was published on 26 September 2026, so a 1,059-star project is being actively maintained. Two warnings, both real. Unions of unrelated types are not resolved automatically — anything beyond a set of classes with distinct fields needs a small function you write and register, and that is the usual first wall. More importantly, a type it does not know how to convert is passed through unchanged rather than rejected, so a wrong setup can produce quietly wrong data instead of an error. Test the round trip rather than trusting it. The better-known alternative is pydantic/pydantic, which does validation and conversion together but owns the class definitions, and that difference is the whole choice.
- Keeps your own classes, so adopting it does not mean rewriting every model.
- Nine ready-made converters, so the quirks of each output library are already handled.
- Very small and dependency-light, which makes it easy to remove again.
- Unknown types pass through unchanged, so a mistake yields wrong data rather than an error.
- Unions of unrelated types need a disambiguation function written by hand.
- Python 3.10 or newer only, so it is unavailable on older pinned interpreters.
- pydantic/pydantic
MIT, 29.1k stars; does validation and conversion together, but your classes have to be its classes, which is more capable and a much larger commitment.
Track this in Scout - jcrist/msgspec
BSD-3-Clause, 4.2k stars; the same structuring job with the encoders written in C for speed, where this project hands the encoding to other libraries.
Track this in Scout - marshmallow-code/marshmallow
MIT, 7.2k stars; the same converting job driven by hand-written schema classes instead of by the type annotations already in the code.
Track this in Scout
python3 -m venv venv source venv/bin/activate pip install cattrs