Skip to main content

Language-agnostic version management across project files

Project description

vrzn

Author: Scott Arne Johnson (scott.arne.johnson@gmail.com)

Language-agnostic version management across project files.

Overview

Projects often store version numbers in multiple files: pyproject.toml, __init__.py, CMakeLists.txt, package.json, and others. When these fall out of sync, builds break and releases ship incorrect metadata.

vrzn solves this by letting you declare every file that contains a version number in a single configuration file. It can then read, set, and bump versions across all of them at once, with full PEP 440 support.

Installation

Requires Python 3.10 or later.

pip install vrzn

For YAML config file support:

pip install 'vrzn[yaml]'

Quick Start

Create a vrzn.toml in your project root:

[[locations]]
file = "pyproject.toml"
type = "pyproject-version"

[[locations]]
file = "src/mypackage/__init__.py"
type = "python-dunder"

Check that all version locations are in sync:

$ vrzn get

                       vrzn — version report
╭───────────────────────────┬───────────────────┬─────────┬────────╮
│ File                      │ Location          │ Version │ Status │
├───────────────────────────┼───────────────────┼─────────┼────────┤
│ pyproject.toml            │ pyproject-version │  1.0.0  │   ok   │
├───────────────────────────┼───────────────────┼─────────┼────────┤
│ src/mypackage/__init__.py │ python-dunder     │  1.0.0  │   ok   │
╰───────────────────────────┴───────────────────┴─────────┴────────╯

  Consensus version: 1.0.0
  All version numbers are consistent.

Set a specific version everywhere:

$ vrzn -y set 1.2.0

  Setting version to 1.2.0

                                updated files
╭───────────────────────────┬───────────────────┬─────────┬───────┬─────────╮
│ File                      │ Location          │ Current │  New  │ Result  │
├───────────────────────────┼───────────────────┼─────────┼───────┼─────────┤
│ pyproject.toml            │ pyproject-version │  1.0.0  │ 1.2.0 │ updated │
│ src/mypackage/__init__.py │ python-dunder     │  1.0.0  │ 1.2.0 │ updated │
╰───────────────────────────┴───────────────────┴─────────┴───────┴─────────╯

  All versions set to 1.2.0.

Bump the version:

$ vrzn -y bump patch

  Version bump: 1.2.0 → 1.2.1

                                updated files
╭───────────────────────────┬───────────────────┬─────────┬───────┬─────────╮
│ File                      │ Location          │ Current │  New  │ Result  │
├───────────────────────────┼───────────────────┼─────────┼───────┼─────────┤
│ pyproject.toml            │ pyproject-version │  1.2.0  │ 1.2.1 │ updated │
│ src/mypackage/__init__.py │ python-dunder     │  1.2.0  │ 1.2.1 │ updated │
╰───────────────────────────┴───────────────────┴─────────┴───────┴─────────╯

  Version bumped to 1.2.1.

Preview changes without writing files:

$ vrzn --dry-run bump minor

  Version bump: 1.2.1 → 1.3.0

                                    dry run
╭───────────────────────────┬───────────────────┬─────────┬───────┬──────────────╮
│ File                      │ Location          │ Current │  New  │    Result     │
├───────────────────────────┼───────────────────┼─────────┼───────┼──────────────┤
│ pyproject.toml            │ pyproject-version │  1.2.1  │ 1.3.0 │ would update │
│ src/mypackage/__init__.py │ python-dunder     │  1.2.1  │ 1.3.0 │ would update │
╰───────────────────────────┴───────────────────┴─────────┴───────┴──────────────╯

  Dry run — no files were modified.

Pre-release workflows:

vrzn -y bump patch --pre rc  # 1.0.0 -> 1.0.1rc1
vrzn -y bump pre             # 1.0.1rc1 -> 1.0.1rc2
vrzn -y bump release         # 1.0.1rc2 -> 1.0.1

CLI Reference

Global Options

Global options must be placed before the subcommand (e.g., vrzn --dry-run bump patch).

Option Description
--dry-run Show what would change without writing files.
--yes, -y Skip confirmation prompts.
--quiet, -q Machine-readable output, no tables.
--config, -c PATH Path to config file (overrides discovery).

Commands

vrzn get

Display the current version in all configured files. Prints a table showing each location, its version, and whether it matches the consensus.

With --quiet, prints only the consensus version string.

Exit codes: 0 if all versions agree, 1 if mismatches exist, 2 if no config found.

vrzn set VERSION

Set all version numbers to VERSION. Accepts any PEP 440 version string (e.g., 1.0.0, 1.0.0rc1, 1.0.0.post1). Non-normalized forms are accepted and automatically normalized.

Prompts for confirmation unless --yes or --dry-run is set.

Exit codes: 1 for invalid version format, 2 if no config found.

vrzn bump PART [--pre LABEL]

Bump the version number. PART must be one of: major, minor, patch, pre, release.

Use --pre with a label (alpha, a, beta, b, rc) to enter a pre-release state. Use bump pre to increment an existing pre-release. Use bump release to finalize a pre-release to its stable version.

If versions are out of sync, vrzn warns and uses a consensus version (most common across locations). Prompts for confirmation unless --yes or --dry-run is set.

Exit codes: 1 for errors (no readable version, invalid bump operation), 2 if no config found.

Configuration

vrzn searches up the directory tree for config in this order:

  1. vrzn.toml
  2. vrzn.yaml
  3. vrzn.json
  4. pyproject.toml (under [tool.vrzn])

Built-in Presets

Each preset is a template string with a version placeholder that tells vrzn how to find and replace the version in a file.

Preset Matches Format
pyproject-version version = "X.Y.Z" in TOML full
python-dunder __version__ = "X.Y.Z" full
python-version-info __version_info__ = (X, Y, Z) base
cmake-project project(NAME VERSION X.Y.Z) base
c-define #define PREFIX_VERSION_MAJOR N component
cargo-toml version = "X.Y.Z" in Cargo.toml full
package-json "version": "X.Y.Z" in JSON full
maven-pom <version>X.Y.Z</version> full
gradle-version version = 'X.Y.Z' in Gradle full

Format types:

  • full — reads/writes a complete PEP 440 version string (e.g., 1.2.3rc1)
  • base — reads/writes only MAJOR.MINOR.PATCH (e.g., 1.2.3), ignoring pre-release suffixes
  • component — reads/writes a single integer (MAJOR, MINOR, or PATCH); excluded from agreement checking

The c-define preset requires a prefix parameter and expands to three component locations:

[[locations]]
file = "include/mylib.h"
type = "c-define"
prefix = "MYLIB"

Custom Locations

For files that don't match a built-in preset, use custom with a template string containing a version placeholder:

[[locations]]
file = "docs/conf.py"
type = "custom"
label = "Sphinx config"
template = 'release\s*=\s*"{version}"'

The template is a regex string with exactly one placeholder embedded in it. The text around the placeholder is standard regex that matches the surrounding context in the file.

Available placeholders:

Placeholder Writes Format
{version} Full PEP 440 version (e.g., 1.2.3rc1) full
{base} MAJOR.MINOR.PATCH only (e.g., 1.2.3) base
{info_tuple} Comma-separated tuple (e.g., 1, 2, 3) base
{major} Major version integer component
{minor} Minor version integer component
{patch} Patch version integer component

Development

pip install --config-settings editable_mode=compat -e ".[dev,yaml]"
pytest

License

MIT License. Copyright (c) 2026 Scott Arne Johnson. See LICENSE for details.

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

vrzn-0.2.0.tar.gz (25.6 kB view details)

Uploaded Source

Built Distribution

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

vrzn-0.2.0-py3-none-any.whl (17.1 kB view details)

Uploaded Python 3

File details

Details for the file vrzn-0.2.0.tar.gz.

File metadata

  • Download URL: vrzn-0.2.0.tar.gz
  • Upload date:
  • Size: 25.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for vrzn-0.2.0.tar.gz
Algorithm Hash digest
SHA256 39cd50d40c0c5a182cdf939718f1aae72cc2325e8f519e8ff81c5ffaa28e6dcf
MD5 41b8c1c8308fe9bfd05bc4a4c57f8941
BLAKE2b-256 f6cea40c0a5c132d5b60e8565bb9d19a679dda31ea3fd3238497bc73f30395ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for vrzn-0.2.0.tar.gz:

Publisher: build-wheels.yml on scott-arne/vrzn

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

File details

Details for the file vrzn-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: vrzn-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 17.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for vrzn-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 992fb2425161a6dcf286f161cd7f532bee33406ab67da0cd2994c153f2f3560a
MD5 7c43b38395e393aee7b1877b637a4d7a
BLAKE2b-256 c5267621b5b9fde16aad258531978ce1f09b6e411384814a5c39845750d477f4

See more details on using hashes here.

Provenance

The following attestation bundles were made for vrzn-0.2.0-py3-none-any.whl:

Publisher: build-wheels.yml on scott-arne/vrzn

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