bumpver
Bumpver is a Python library and command-line tool designed for automatic versioning of project files. It supports various versioning schemes, including Semantic Versioning (SemVer) and Calendar Versioning (CalVer), and works with plain text files, making it suitable for any project. It integrates optionally with Git or Mercurial to manage version tags and commits. The current version is 2025.1131. The project has an active release cadence, with updates often several times a year, addressing bug fixes and adding new features.
Warnings
- breaking The project underwent a name change from `PyCalVer` to `BumpVer` in release 2020.1100-beta. This change also introduced a new pattern syntax, although the old syntax is still supported. Users migrating from `PyCalVer` or referencing older documentation should be aware of this.
- gotcha When using Calendar Versioning (CalVer) patterns with `bumpver`, auto-incrementing parts like `PATCH` will reset (roll over to zero) if a higher-order date part (e.g., year or month) changes. For example, if you increment `--patch` on `2024.1.5` at the end of January, the next increment in February might become `2024.2.0`, resetting the patch.
- gotcha For Semantic Versioning (SemVer) patterns, `bumpver` requires explicit flags (`--major`, `--minor`, or `--patch`) to specify which part of the version to increment. Unlike CalVer, simply running `bumpver update` without such flags will result in an error if the date has not changed or if no auto-incrementing parts are defined.
- gotcha Incorrectly configuring `file_patterns` in `pyproject.toml` (e.g., wrong regular expression, escaping issues, or inconsistent quoting) can lead to `bumpver` failing to find and update version strings in files. This results in 'Pattern not found' errors.
- gotcha Using the `--allow-dirty` flag with `bumpver update` bypasses the check for uncommitted changes. However, `bumpver` will still abort the commit if there are uncommitted changes *to the files containing version strings*. This can lead to unexpected failures even when `--allow-dirty` is used.
Install
-
pip install bumpver
Quickstart
import os
import subprocess
def setup_project():
# Simulate project structure
os.makedirs('my_project', exist_ok=True)
os.chdir('my_project')
with open('pyproject.toml', 'w') as f:
f.write("""
[tool.bumpver]
current_version = "2024.1.0"
version_pattern = "YYYY.MINOR.PATCH"
[tool.bumpver.file_patterns]
"src/__init__.py" = [
'^__version__ = "{version}"$',
]
"README.md" = [
'Current Version: {version}',
]
"""
)
os.makedirs('src', exist_ok=True)
with open('src/__init__.py', 'w') as f:
f.write('__version__ = "2024.1.0"\n')
with open('README.md', 'w') as f:
f.write('My Project\n\nCurrent Version: 2024.1.0\n')
# Initialize bumpver config if it doesn't exist (optional, but good practice)
try:
subprocess.run(["bumpver", "init"], check=True, capture_output=True)
print("bumpver init successful.")
except subprocess.CalledProcessError as e:
print(f"bumpver init failed: {e.stderr.decode()}")
def run_bumpver_update():
print("\n--- Running bumpver update --patch --dry ---")
try:
result = subprocess.run(["bumpver", "update", "--patch", "--dry"], check=True, capture_output=True)
print(result.stdout.decode())
except subprocess.CalledProcessError as e:
print(f"bumpver update failed: {e.stderr.decode()}")
print("\n--- Verifying file contents (dry run means no actual changes) ---")
with open('src/__init__.py', 'r') as f:
print(f"src/__init__.py: {f.read().strip()}")
with open('README.md', 'r') as f:
print(f"README.md: {f.read().strip()}")
print("\n--- Running actual bumpver update --patch ---")
try:
result = subprocess.run(["bumpver", "update", "--patch"], check=True, capture_output=True)
print(result.stdout.decode())
except subprocess.CalledProcessError as e:
print(f"bumpver update failed: {e.stderr.decode()}")
print("\n--- Verifying actual file contents ---")
with open('src/__init__.py', 'r') as f:
print(f"src/__init__.py: {f.read().strip()}")
with open('README.md', 'r') as f:
print(f"README.md: {f.read().strip()}")
if __name__ == '__main__':
original_dir = os.getcwd()
try:
setup_project()
run_bumpver_update()
finally:
os.chdir(original_dir)
# Clean up created directory if necessary (omitted for simplicity in quickstart)