Contributing¶
Thanks for your interest in contributing! This document covers how to set up the project, run checks, and submit changes.
Getting Started¶
External contributions should come from a fork. Fork the repo on GitHub, then clone your fork:
git clone https://github.com/<your-username>/versionable.git
cd versionable
versionable uses Pixi for environment management:
pixi install
This installs all dependencies, including optional backends (TOML, YAML, HDF5) and dev tools (pytest, mypy, ruff). When
you’re ready, open a PR from your fork against main.
Running Checks¶
Before submitting a PR, run the full cleanup and test suite:
pixi run cleanup # formatters, linters, type checkers
pixi run test # pytest
cleanup runs ruff (format + lint), mypy, pyright, prettier (markdown), and markdownlint. Fix all errors before pushing
— CI runs the same checks.
To run checks individually:
pixi run format # ruff format
pixi run ruff # ruff check --fix
pixi run mypy # mypy src/
pixi run pyright # pyright src/
pixi run test # pytest
CI Environments¶
CI runs in two environments:
default — all backends installed (JSON, TOML, YAML, HDF5)
minimal — JSON backend only (no h5py, pyyaml, or toml)
You can run both locally:
pixi run ci-all
Building Documentation¶
Documentation uses Sphinx with MyST markdown and lives in the docs/ directory. It builds in its own pixi environment:
pixi run -e docs docs # one-time build → docs/_build/html/
pixi run -e docs docs-live # live-reload server for local editing
CI also builds the docs on every PR, so you’ll see a failure if your changes break the build.
Code Style¶
Naming Conventions¶
This project uses camelCase for functions, methods, and variables — see the
FAQ for why. Test files use
snake_case (pytest convention).
What |
Style |
Example |
|---|---|---|
Functions / methods / variables |
|
|
Classes / types |
|
|
Constants |
|
|
Private members |
Leading underscore |
|
Test functions |
|
|
Type Annotations¶
All functions and instance variables must have type hints. Use modern syntax (X | Y, list[T], dict[K, V]). Avoid
Any unless strictly necessary — add a short comment explaining why if you do.
Never use # type: ignore, # noqa:, or pyright exclude to suppress type errors. Fix the underlying issue instead.
Imports¶
from __future__ import annotations
# 1. Standard library
import hashlib
from typing import Any
# 2. Third-party
import numpy as np
# 3. Local
from versionable._hash import computeHash
Tests¶
Tests live in
tests/and use pytestTest file names match
test_*.pyUse
snake_casefor all identifiers in test filesHardcode schema hashes as string literals (e.g.,
hash="74a182") — don’t callcomputeHash()in tests
Pull Requests¶
Open PRs from your fork
Target the
mainbranchPreserve individual commit history — we don’t squash merge
Keep PR descriptions concise: what changed, why, and what you tested
PR Description Format¶
**Description:** Brief explanation of what and why
**Changes:**
- Bullet point of change 1
- Bullet point of change 2
**Tests performed:**
- Test scenario 1
- Test scenario 2
Project Structure¶
src/versionable/ Source code (src layout)
__init__.py Public API exports
_api.py save() / load() entry points
_base.py Versionable mixin, registry, metadata
_hash.py Schema hash computation
_types.py Type converter registry + built-in converters
_migration.py Declarative and imperative migrations
_backend.py Backend abstract base class
_json_backend.py JSON backend
_toml_backend.py TOML backend (optional)
_yaml_backend.py YAML backend (optional)
_hdf5_backend.py HDF5 backend (optional)
_hdf5_session.py Incremental HDF5 sessions
errors.py Exception hierarchy
tests/ pytest test suite
docs/ Sphinx documentation (MyST markdown)
Private modules (prefixed with _) are internal — public API is exposed only through __init__.py.
Reporting Issues¶
File issues on GitHub. Include:
What you expected vs. what happened
A minimal reproducible example
Python version and versionable version (
python -c "import versionable; print(versionable.__version__)")