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.1.tar.gz (26.1 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.1-py3-none-any.whl (17.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: vrzn-0.2.1.tar.gz
  • Upload date:
  • Size: 26.1 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.1.tar.gz
Algorithm Hash digest
SHA256 d26a9dcbc5336805403fdba996a7dffcc9184c04359572dbdd401207a693faa8
MD5 ff570e47d50959bdc93d10e0f5123d74
BLAKE2b-256 9738aa16596c56fefb8701aba6eabaace88362214eb3f3134783713c45afe9dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for vrzn-0.2.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: vrzn-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 17.5 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a499dc2e613a658de91d3bc92936afcf1bdb1903e8f2f17772fdfcadb0c27897
MD5 9c7b593b89a90cce16fa68dbfc8f6cb8
BLAKE2b-256 43769814c64d5625c4633511d50074bd6be8cc1c9d2e3f69e124b4b40c961d1e

See more details on using hashes here.

Provenance

The following attestation bundles were made for vrzn-0.2.1-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