Skip to main content

Versioned persistence for Python dataclasses with hash validation, declarative migrations, and pluggable backends

Project description

versionable

versionable logo

Save and load Python dataclasses to files — with schema versioning, type converters, and pluggable storage backends.

Full documentation →

Why versionable ?

Your data lives in files. Your code keeps changing. Without protection, old files silently load with missing fields, wrong types, or stale values — your data schemes against you.

versionable stops the scheming. Define your data as a Python dataclass, and get save() and load() functions that produce human-readable files (YAML, JSON, TOML) or binary-efficient ones (HDF5). Every file is stamped with a schema fingerprint and version number, so a file written by v1 of your code loads cleanly into v5 — automatically migrated, never silently broken.

What to use? .pickle is unsafe. Pure .json and .yaml carry no schema and manual wrappers break the moment your schema changes. .csv and .parquet are great for tables but poor at handling structured metadata. .npz files aren't even guaranteed to be compatible across numpy versions. .proto (Protocol Buffers) are schema-aware but require a build step and offer no migrations. And if you've resorted to folders with sidecar files (data.npy + params.json + metadata.txt), you already know how easily those drift out of sync.

What you get with versionable:

  • Zero boilerplate — no schema files, no code generation, no build step. Just inherit from Versionable
  • Simple versioning with declarative migrations — rename, add, remove, or transform fields across versions
  • Rich type support — datetime, Path, UUID, Enum, numpy arrays, and more — easy to extend with your own
  • Nested objects with independent versioning — compose complex dataclasses from smaller Versionable pieces
  • Native numpy array support — with lazy HDF5 loading for large datasets
  • JSON, YAML, TOML, HDF5 — or bring your own backend
  • Import-time safety — schema hash mismatches are caught when your module loads, not in production
  • Modern, type-safe Python — fully typed and compatible with mypy, pyright, and other static analyzers

How does it compare?

Versionable Features pickle dc libs¹ protobuf raw JSON sidecars
✅ Zero boilerplate
✅ Versioning with declarative migrations
✅ Rich type support 🔧
✅ Nested objects, versioned independently 🟠 🟠 🟠 🟠
✅ Native numpy / lazy HDF5 🟠 🟠
✅ Custom Backends 🟠 🟠 🟠
✅ Import-time validation 🔧
✅ Modern, type-safe Python 🟠

¹ pydantic, dataclasses-json, etc.

  • 🔧 = requires manual effort / build step
  • 🟠 = partial

Installation

pip install versionable

# With HDF5 backend support (h5py + hdf5plugin)
pip install "versionable[hdf5]"

Or install from source:

pip install git+https://github.com/hendrickmelo/versionable.git

Quick Start

You save a config file today:

from dataclasses import dataclass
import versionable
from versionable import Versionable

@dataclass
class SensorConfig(Versionable, version=1, hash="82bc30"):
    name: str
    value: float

config = SensorConfig(name="experiment-A", value=9.81)
versionable.save(config, "config.yaml")

A few weeks later you rename value to magnitude. Without versionable, old files silently load with missing data. With it, you bump the version and declare a migration — old files upgrade automatically:

from versionable import Versionable, Migration

@dataclass
class SensorConfig(Versionable, version=2, hash="064498"):
    name: str
    magnitude: float  # renamed from "value"

    class Migrate:
        v1 = Migration().rename("value", "magnitude")

# Old file loads cleanly into the new schema
loaded = versionable.load(SensorConfig, "config.yaml")
assert loaded.magnitude == 9.81

The schema hash is validated at import time — if your fields change but the hash doesn't, you get an error immediately, not a silent bug in production.

Learn More

Want to see how old files get upgraded automatically when your schema changes?

For AI Agents

If you're an AI agent working with versionable, see AGENT.md for a condensed API reference.

Complete Documentation

For custom type converters, HDF5 support, and more, see the full documentation.

Acknowledgements

The idea behind versionable started over 15 years ago in C++, where I first learned the approach from Steve Araiza. Over the years the idea of a Serializable / Versionable class evolved from using CArchive to make use of C++11, variadic macros, and other fun modern C++ features. Some version of this pattern has been a part of every project I've worked on since those days.

This is the Python version of the idea. It is built using modern, type-safe Python with great fresh ideas from Emma Powers.

A big thank you to both of them! 🥓🥞🍳

License

MIT - Copyright ©️ 2026 Hendrick Melo

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

versionable-0.0.1rc1.tar.gz (281.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

versionable-0.0.1rc1-py3-none-any.whl (34.6 kB view details)

Uploaded Python 3

File details

Details for the file versionable-0.0.1rc1.tar.gz.

File metadata

  • Download URL: versionable-0.0.1rc1.tar.gz
  • Upload date:
  • Size: 281.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for versionable-0.0.1rc1.tar.gz
Algorithm Hash digest
SHA256 712792ec10edd64d2463ac6dfcc42d3ba16813d797d8774dbaff093c88290be5
MD5 672601df01b53624a932470ae3db5879
BLAKE2b-256 5cb5f374e9f4c6237821adc3cced7d99fac78c694c86bf277a64475d2de8e46c

See more details on using hashes here.

Provenance

The following attestation bundles were made for versionable-0.0.1rc1.tar.gz:

Publisher: publish.yml on hendrickmelo/versionable

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file versionable-0.0.1rc1-py3-none-any.whl.

File metadata

  • Download URL: versionable-0.0.1rc1-py3-none-any.whl
  • Upload date:
  • Size: 34.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for versionable-0.0.1rc1-py3-none-any.whl
Algorithm Hash digest
SHA256 94647045e8682d56c6a492d4ed41858c885a93848e0ecfa9711dc8e7f849707d
MD5 2e5f079cb4d66a9dd79bafbeef2daf23
BLAKE2b-256 0072f719056b9b606073905000f80e05afa6e1aa9bd9429de65cc03c7206841a

See more details on using hashes here.

Provenance

The following attestation bundles were made for versionable-0.0.1rc1-py3-none-any.whl:

Publisher: publish.yml on hendrickmelo/versionable

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page