Version-bump your software with a single command
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pattern-based file modification system for updating version strings across multiple files with configurable search and replace patterns. Supports both simple text replacement and complex structured data file updates with comprehensive logging and validation.
Core class for handling version updates in individual files according to configuration specifications.
class ConfiguredFile:
"""
Handles version changes in individual files per configuration.
Manages file reading, pattern matching, version replacement, and writing
with support for regex patterns, structured data files, and validation.
"""
def __init__(
self,
file_change: FileChange,
version_config: VersionConfig
) -> None:
"""
Initialize configured file with change specification.
Args:
file_change: File modification configuration
version_config: Version parsing and formatting configuration
"""
def update_file(
self,
current_version: Version,
new_version: Version,
context: Dict[str, Any],
dry_run: bool = False
) -> None:
"""
Update file with new version strings.
Searches for current version patterns and replaces with new version
according to configured search/replace patterns and options.
Args:
current_version: Current Version object
new_version: New Version object
context: Template context for formatting
dry_run: Preview changes without modifying file
Raises:
VersionNotFoundError: Version pattern not found in file
FileNotFoundError: File doesn't exist and not configured to ignore
"""
@property
def filename(self) -> str:
"""File path being managed."""
@property
def search_for(self) -> str:
"""Search pattern used for finding version strings."""
@property
def replace_with(self) -> str:
"""Replacement pattern for new version strings."""
class FileUpdater:
"""
Base class for updating file content with version changes.
Handles text-based file modifications with pattern matching,
validation, and change logging capabilities.
"""
def __init__(self, file_change: FileChange) -> None:
"""Initialize file updater with change configuration."""
def update_file(
self,
search_for: str,
replace_with: str,
dry_run: bool = False
) -> None:
"""
Update file content with search and replace operation.
Args:
search_for: Pattern to search for
replace_with: Replacement string
dry_run: Preview without modifying file
"""
class DataFileUpdater(FileUpdater):
"""
Specialized updater for structured data files.
Handles JSON, TOML, and YAML files by parsing structure,
updating specific keys, and preserving formatting.
"""
def update_file(
self,
search_for: str,
replace_with: str,
dry_run: bool = False
) -> None:
"""
Update structured data file at specified key path.
Parses file format, navigates to key path, updates value,
and writes back with preserved formatting.
"""High-level functions for managing multiple files and resolving configurations.
def modify_files(
files: List[ConfiguredFile],
current_version: Version,
new_version: Version,
context: Dict[str, Any],
dry_run: bool = False
) -> None:
"""
Apply version changes to list of configured files.
Processes multiple files in sequence, updating version strings
according to each file's configuration with comprehensive logging.
Args:
files: List of ConfiguredFile objects to update
current_version: Current Version object
new_version: New Version object
context: Template context for pattern formatting
dry_run: Preview changes without modifying files
Raises:
VersionNotFoundError: Version not found in one or more files
"""
def resolve_file_config(
files_config: List[FileChange],
version_config: VersionConfig
) -> List[ConfiguredFile]:
"""
Convert file change configurations into configured file objects.
Creates ConfiguredFile instances from FileChange specifications,
applying version configuration and validating file paths.
Args:
files_config: List of FileChange configurations
version_config: Version parsing/formatting configuration
Returns:
List of ConfiguredFile objects ready for updates
"""
def contains_pattern(search: re.Pattern, contents: str) -> bool:
"""
Check if file contents contain regex pattern.
Args:
search: Compiled regex pattern
contents: File contents to search
Returns:
True if pattern found, False otherwise
"""
def log_changes(
file_path: str,
file_content_before: str,
file_content_after: str,
dry_run: bool = False
) -> None:
"""
Log file changes with diff output.
Displays unified diff showing changes made to file content
with color formatting and dry-run indicators.
Args:
file_path: Path to file being modified
file_content_before: Original file content
file_content_after: Modified file content
dry_run: Whether this is a dry-run preview
"""Simple search and replace in text files:
from bumpversion.config.models import FileChange
# Basic version replacement
file_config = FileChange(
filename="setup.py",
search="version='{current_version}'",
replace="version='{new_version}'"
)
# Using default patterns (searches for current_version, replaces with new_version)
file_config = FileChange(filename="src/mypackage/__init__.py")Advanced pattern matching with regular expressions:
# Regex-based replacement
file_config = FileChange(
filename="version.txt",
search=r"Version:\s*{current_version}",
replace="Version: {new_version}",
regex=True
)
# Complex regex with capture groups
file_config = FileChange(
filename="Dockerfile",
search=r"(LABEL version=){current_version}",
replace=r"\1{new_version}",
regex=True
)Updates to JSON, TOML, and YAML files using key paths:
# Update JSON file at specific key
file_config = FileChange(
filename="package.json",
key_path="version"
)
# Update nested TOML key
file_config = FileChange(
filename="pyproject.toml",
key_path="project.version"
)
# Update YAML with custom patterns
file_config = FileChange(
filename="chart.yaml",
key_path="version",
search="{current_version}",
replace="{new_version}"
)Apply configurations to multiple files matching patterns:
# Update all Python files in src/
file_config = FileChange(
glob="src/**/*.py",
search="__version__ = '{current_version}'",
replace="__version__ = '{new_version}'"
)
# Update version in all markdown files
file_config = FileChange(
glob="docs/*.md",
search="Version {current_version}",
replace="Version {new_version}"
)Configure behavior for missing files and versions:
# Ignore if file doesn't exist
file_config = FileChange(
filename="optional_file.txt",
ignore_missing_file=True
)
# Ignore if version pattern not found
file_config = FileChange(
filename="changelog.md",
search="## Version {current_version}",
replace="## Version {new_version}",
ignore_missing_version=True
)from bumpversion.files import ConfiguredFile, modify_files
from bumpversion.config.models import FileChange
from bumpversion.versioning.version_config import VersionConfig
# Create file configurations
file_changes = [
FileChange(filename="setup.py"),
FileChange(
filename="src/mypackage/__init__.py",
search="__version__ = '{current_version}'",
replace="__version__ = '{new_version}'"
)
]
# Create version config
version_config = VersionConfig(
parse=r"(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)",
serialize=["{major}.{minor}.{patch}"],
search="{current_version}",
replace="{new_version}",
part_configs={}
)
# Create configured files
from bumpversion.files import resolve_file_config
configured_files = resolve_file_config(file_changes, version_config)
# Update files
from bumpversion.versioning.models import Version
current_version = Version({"major": "1", "minor": "0", "patch": "0"}, None)
new_version = Version({"major": "1", "minor": "0", "patch": "1"}, None)
modify_files(
files=configured_files,
current_version=current_version,
new_version=new_version,
context={"current_version": "1.0.0", "new_version": "1.0.1"},
dry_run=True # Preview changes
)from bumpversion.files import ConfiguredFile
# Create configured file
file_change = FileChange(
filename="VERSION",
search="{current_version}",
replace="{new_version}"
)
configured_file = ConfiguredFile(file_change, version_config)
# Update individual file
configured_file.update_file(
current_version=current_version,
new_version=new_version,
context={"current_version": "1.0.0", "new_version": "1.0.1"},
dry_run=False
)# Update package.json version
json_file = FileChange(
filename="package.json",
key_path="version"
)
# Update pyproject.toml version
toml_file = FileChange(
filename="pyproject.toml",
key_path="project.version"
)
# Update Kubernetes manifest
yaml_file = FileChange(
filename="k8s/deployment.yaml",
key_path="spec.template.spec.containers[0].image",
search="myapp:{current_version}",
replace="myapp:{new_version}"
)
configured_files = resolve_file_config([json_file, toml_file, yaml_file], version_config)
modify_files(configured_files, current_version, new_version, context)# Complex regex replacement
complex_file = FileChange(
filename="docs/installation.md",
search=r"(pip install mypackage==){current_version}",
replace=r"\1{new_version}",
regex=True
)
# Multiple pattern file
multi_pattern_file = FileChange(
filename="README.md",
search="Version {current_version}",
replace="Version {new_version}"
)
# Date-based replacement with context
date_file = FileChange(
filename="CHANGELOG.md",
search="## Unreleased",
replace="## {new_version} ({now:%Y-%m-%d})"
)# Graceful error handling
robust_config = FileChange(
filename="optional-config.ini",
search="version = {current_version}",
replace="version = {new_version}",
ignore_missing_file=True,
ignore_missing_version=True
)
# Strict validation (default)
strict_config = FileChange(
filename="critical-file.py",
search="VERSION = '{current_version}'",
replace="VERSION = '{new_version}'"
# Will raise exceptions if file missing or version not found
)Install with Tessl CLI
npx tessl i tessl/pypi-bump-my-version