Versioning It with your Version In Git - automatic package versioning based on VCS tags
—
Comprehensive error hierarchy for handling configuration errors, VCS issues, method validation problems, and other exceptional conditions in versioningit operations.
Root exception class for all versioningit-specific errors.
class Error(Exception):
"""Base class of all versioningit-specific errors."""Errors related to invalid configuration settings and values.
class ConfigError(Error, ValueError):
"""
Raised when the versioningit configuration contains invalid settings.
This includes invalid parameter types, missing required fields,
invalid format strings, and other configuration validation failures.
"""
class NotVersioningitError(Error):
"""
Raised when versioningit is used on a project that does not have
versioningit enabled.
"""
class NoConfigFileError(NotVersioningitError):
"""
Raised when versioningit is used on a project that does not contain a
versioningit.toml or pyproject.toml file.
"""
def __init__(self, project_dir: Path) -> None:
self.project_dir: Path = project_dir
"""The path to the project directory."""
def __str__(self) -> str:
return f"No pyproject.toml or versioningit.toml file in {self.project_dir}"
class NoConfigSectionError(NotVersioningitError):
"""
Raised when versioningit is used on a project whose versioningit.toml or
pyproject.toml file does not contain a versioningit configuration table.
"""
def __init__(self, config_path: Path) -> None:
self.config_path: Path = config_path
"""The path to the configuration file."""
def __str__(self) -> str:
return f"versioningit not configured in {self.config_path}"Errors related to method loading, validation, and execution.
class MethodError(Error):
"""
Raised when a method is invalid or returns an invalid value.
This includes entry points that don't resolve to callables,
methods that return wrong types, and method loading failures.
"""Errors related to VCS operations and repository state.
class NotVCSError(Error):
"""
Raised when versioningit is run in a directory that is not under
version control or when the relevant VCS program is not installed.
"""
class NoTagError(Error):
"""
Raised when a tag cannot be found in version control.
This occurs when the repository has no tags or no tags match
the configured patterns.
"""Errors related to tag and version string processing.
class InvalidTagError(Error, ValueError):
"""
Raised by tag2version methods when passed a tag that they cannot work with.
This includes tags that don't match required patterns or contain
invalid version information.
"""
class InvalidVersionError(Error, ValueError):
"""
Raised by next-version and template-fields methods when passed a
version that they cannot work with.
This includes malformed version strings or versions that don't
conform to expected formats.
"""Errors related to PKG-INFO file handling and source distributions.
class NotSdistError(Error):
"""
Raised when attempting to read a PKG-INFO file from a directory
that doesn't have one.
This typically occurs when fallback mode tries to read version
information from a source distribution but no PKG-INFO file exists.
"""from versioningit import get_version
from versioningit.errors import (
NotVCSError, NoConfigFileError, ConfigError,
MethodError, InvalidTagError
)
try:
version = get_version()
print(f"Version: {version}")
except NotVCSError:
print("Not in a version control repository")
except NoConfigFileError:
print("No configuration file found")
except ConfigError as e:
print(f"Configuration error: {e}")
except MethodError as e:
print(f"Method error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")from versioningit import Versioningit
from versioningit.errors import ConfigError, NoConfigSectionError
config = {
"vcs": {"method": "git"},
"tag2version": {"method": "basic", "rmprefix": 123}, # Wrong type
"format": {"invalid-state": "template"} # Invalid state key
}
try:
vgit = Versioningit.from_project_dir(config=config)
except ConfigError as e:
print(f"Invalid configuration: {e}")
try:
vgit = Versioningit.from_project_dir("/path/without/config")
except NoConfigSectionError as e:
print(f"No versioningit configuration: {e}")
print(f"Config file: {e.config_path}")from versioningit import get_version, get_next_version
from versioningit.errors import NotVCSError, NoTagError
try:
version = get_version(fallback=False)
except NotVCSError:
print("Project must be under version control")
try:
next_version = get_next_version()
except NoTagError:
print("No tags found in repository")
except NotVCSError:
print("Not a version control repository")from versioningit.methods import EntryPointSpec, CustomMethodSpec
from versioningit.errors import MethodError, ConfigError
# Entry point not found
try:
spec = EntryPointSpec(group="versioningit.tag2version", name="nonexistent")
method = spec.load(".")
except ConfigError as e:
print(f"Entry point error: {e}")
# Custom method not callable
try:
spec = CustomMethodSpec(
module="sys", # sys.path is not callable
value="path",
module_dir=None
)
method = spec.load(".")
except MethodError as e:
print(f"Method not callable: {e}")from versioningit.basics import basic_tag2version
from versioningit.next_version import next_minor_version
from versioningit.errors import InvalidTagError, InvalidVersionError
# Invalid tag
try:
version = basic_tag2version(
tag="not-a-version-tag",
params={"regex": r"v(?P<version>\d+\.\d+\.\d+)", "require-match": True}
)
except InvalidTagError as e:
print(f"Tag doesn't match pattern: {e}")
# Invalid version
try:
next_ver = next_minor_version(
version="not.a.valid.version.string",
branch=None,
params={}
)
except InvalidVersionError as e:
print(f"Cannot parse version: {e}")from versioningit import get_version
from versioningit.errors import NotVCSError, NotSdistError
def get_version_with_fallback(project_dir="."):
"""Get version with multiple fallback strategies."""
# Try VCS first
try:
return get_version(project_dir, fallback=False)
except NotVCSError:
pass
# Try PKG-INFO fallback
try:
return get_version(project_dir, fallback=True)
except NotSdistError:
pass
# Try with default version
try:
config = {"default-version": "0.0.0.dev0"}
return get_version(project_dir, config=config)
except Exception:
pass
# Final fallback
return "unknown"
version = get_version_with_fallback()
print(f"Version: {version}")from versioningit import Versioningit
from versioningit.errors import Error
import logging
# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
try:
vgit = Versioningit.from_project_dir()
report = vgit.run()
if report.using_default_version:
print("Warning: Used default version due to errors")
print(f"Version: {report.version}")
except Error as e:
print(f"Versioningit error: {type(e).__name__}: {e}")
# Debug info available in logs
except Exception as e:
print(f"Unexpected error: {type(e).__name__}: {e}")
raisefrom versioningit.errors import ConfigError, InvalidTagError, MethodError
def custom_tag2version_method(*, tag: str, params: dict) -> str:
"""Custom method with proper error handling."""
# Validate parameters
required_prefix = params.get("required-prefix")
if required_prefix and not isinstance(required_prefix, str):
raise ConfigError("required-prefix must be a string")
# Validate tag format
if required_prefix and not tag.startswith(required_prefix):
raise InvalidTagError(f"Tag {tag!r} must start with {required_prefix!r}")
# Process tag
try:
if required_prefix:
tag = tag[len(required_prefix):]
return tag.lstrip("v")
except Exception as e:
raise MethodError(f"Failed to process tag {tag!r}: {e}")
def custom_vcs_method(*, project_dir: Path, params: dict) -> VCSDescription:
"""Custom VCS method with error handling."""
try:
# Custom VCS operations
result = run_custom_vcs_command(project_dir)
return VCSDescription(
tag=result["tag"],
state=result["state"],
branch=result["branch"],
fields=result["fields"]
)
except subprocess.CalledProcessError as e:
raise NotVCSError(f"VCS command failed: {e}")
except KeyError as e:
raise MethodError(f"Missing required VCS result field: {e}")# All versioningit exceptions inherit from Error
from versioningit.errors import *
def handle_versioningit_error(e: Exception):
"""Handle different types of versioningit errors."""
if isinstance(e, NotVersioningitError):
if isinstance(e, NoConfigFileError):
print(f"Missing config file in {e.project_dir}")
elif isinstance(e, NoConfigSectionError):
print(f"No versioningit config in {e.config_path}")
else:
print("Project doesn't use versioningit")
elif isinstance(e, ConfigError):
print(f"Configuration problem: {e}")
elif isinstance(e, MethodError):
print(f"Method problem: {e}")
elif isinstance(e, NotVCSError):
print("Not under version control")
elif isinstance(e, NoTagError):
print("No version tags found")
elif isinstance(e, InvalidTagError):
print(f"Invalid tag format: {e}")
elif isinstance(e, InvalidVersionError):
print(f"Invalid version format: {e}")
elif isinstance(e, NotSdistError):
print("No PKG-INFO file found for fallback")
elif isinstance(e, Error):
print(f"Other versioningit error: {e}")
else:
print(f"Non-versioningit error: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-versioningit