Versioning strategy¶
Each canVODpy package has its own version
(ADR 0010). A package used on its own
(for example canvod-readers) changes its version only when its code changes. The
umbrella package canvodpy pins every package to an exact version, so a
canvodpy version names exactly the mix of packages it installs.
Why a version per package, and one umbrella?¶
-
Reusable packages
A tool that needs only canvod-readers depends on canvod-readers, and its version says what changed in the readers, not elsewhere.
-
Scientific reproducibility
uv add canvodpy==1.1.0installs exactly the mix of packages that was tested together, so one version is enough to cite in a paper.
Semantic versioning¶
Following Semantic Versioning 2.0.0, for each package on its own:
| Increment | Trigger | Example |
|---|---|---|
MAJOR |
Breaking API changes | 1.4.2 \(\rightarrow\) 2.0.0 |
MINOR |
New features, backwards compatible | 1.1.0 \(\rightarrow\) 1.2.0 |
PATCH |
Bug fixes, backwards compatible | 1.1.0 \(\rightarrow\) 1.1.1 |
Versions are written as Python writes them (PEP 440).
canvodpy's increment is at least the largest increment of the packages released with it: a minor release of canvod-store comes with at least a minor release of canvodpy.
Pre-releases¶
Before a final version, a package can be released as a test version. PEP 440 defines three kinds, marked by a suffix, and sorts them before the final version:
1.0.0a1 \(<\) 1.0.0b1 \(<\) 1.0.0rc1 \(<\) 1.0.0
| Stage | Suffix | What it says | Choose it when |
|---|---|---|---|
| Alpha | a |
Incomplete | Planned features are still missing |
| Beta | b |
Nearly complete, may still change | The planned features are in, but behavior or interfaces can still change before the final version |
| Release candidate | rc |
The final version, unless a bug turns up | Only fixes remain |
| Final | none | Released | A release candidate needed no further fix |
- Each stage counts from 1 (
1.0.0b1,1.0.0b2, …), and the next stage starts again at 1 (1.0.0b2, then1.0.0rc1). A stage may be skipped. - A pre-release of canvodpy pins pre-releases of the packages it releases,
with the same suffix: canvodpy
1.0.0b1pins canvod-store1.0.0b1. - uv and pip skip pre-releases unless asked for one: by its exact version
(
uv add canvodpy==1.0.0b1), or with--prerelease allow(uv) or--pre(pip). canvodpy's exact pins then bring every package at its pre-release. A notebook or script that installs canVODpy packages next to canvodpy pins each of them too: a package that nothing pins to its pre-release is installed at its last final version. - Tags carry the suffix (
v1.0.0b1,canvod-store-v1.0.0b1), and the draft GitHub release is marked as a pre-release. Publishing to PyPI stays a separate step, as for a final version (Releasing).
Choosing a version¶
For each package in a release:
- Choose the increment from the changes since the package's last final version (Semantic Versioning): major, minor or patch.
- Choose the stage (Pre-releases): a pre-release while the release is still being tested, the final version once it holds.
- canvodpy takes at least the largest increment of the packages, and the same stage.
Requirements between packages¶
canvodpyrequires each package at exactly one version (canvod-store==1.1.0): its pins are the log of which mix a canvodpy version is.- A package requires another canVODpy package with a range up to the next
major version (
canvod-config>=1.0.0,<2). The lower bound is the version that has what the package uses; raise it by hand when the package starts to use something newer. - A major release of a package (for example canvod-config 2.0.0) is outside the ranges of the packages that require it: the release is refused until each of them is checked against the new version and its range widened by hand.
__version__of each package is read from the installed package (importlib.metadata), never written into the code.
Tags¶
| Package | Tag | GitHub release |
|---|---|---|
| canvodpy | vX.Y.Z (for example v1.1.0) |
yes, drafted from CHANGELOG.md |
| any other package | <package>-vX.Y.Z (for example canvod-store-v1.1.0) |
no |
Every package has its own CHANGELOG.md in its folder; canvodpy's is the
one at the repository root, and each of its sections lists the package
versions it pins.
Before per-package versions (up to 0.4.0), all packages shared one version
and the tag vX.Y.Z.
Creating releases¶
The maintainer chooses the packages and versions; Releasing has the steps.
just release-status # commits per package since its last tag
just release canvod-store=1.1.0 canvodpy=1.1.0 # prepare the release commit
just tag-release # on the merged commit on main
Deprecation policy¶
Superseded public code is deprecated with the deprecated decorator of
canvod-utils and removed only with the next major version
(ADR 0005). The documentation
describes only the code to use: guides and examples leave deprecated code
out, and the API reference hides everything that carries the decorator,
and every argument named by its companion deprecated_argument
(scripts/griffe_hide_deprecated.py).
Citation¶
@software{canvodpy2026,
author = {Bader, Nicolas and Contributors},
title = {canvodpy: GNSS Vegetation Optical Depth Analysis},
version = {1.0.0},
year = {2026},
url = {https://github.com/TUW-GEO/canvodpy},
doi = {10.5281/zenodo.XXXXXXX}
}
"Analysis was performed using canvodpy v1.0.0 (Bader et al., 2026)."
Cite the canvodpy version: it fixes the version of every package.