CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-versioningit

Versioning It with your Version In Git - automatic package versioning based on VCS tags

Pending
Overview
Eval results
Files

exceptions.mddocs/

Exception Handling

Comprehensive error hierarchy for handling configuration errors, VCS issues, method validation problems, and other exceptional conditions in versioningit operations.

Capabilities

Base Exception

Root exception class for all versioningit-specific errors.

class Error(Exception):
    """Base class of all versioningit-specific errors."""

Configuration 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}"

Method Errors

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.
    """

Version Control Errors

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.
    """

Version Processing Errors

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.
    """

Source Distribution Errors

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.
    """

Usage Examples

Basic Error Handling

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}")

Handling Configuration Errors

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}")

VCS Error Handling

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")

Method Error Handling

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}")

Version Processing Errors

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}")

Fallback and Recovery

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}")

Error Context and Debugging

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}")
    raise

Custom Error Handling in Methods

from 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}")

Exception Hierarchy

# 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

docs

build-integration.md

builtin-methods.md

core-operations.md

data-models.md

exceptions.md

index.md

method-system.md

versioningit-class.md

tile.json