CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-lastversion

A CLI tool to find the latest stable version of an arbitrary project

Pending
Overview
Eval results
Files

version-handling.mddocs/

Version Handling

Enhanced version class and utilities for parsing, normalizing, and comparing software versions. Extends PEP 440 with intelligent handling of real-world version inconsistencies found across different software projects and platforms.

Capabilities

Version Class

Enhanced version class that extends packaging.version.Version with additional normalization and transformation capabilities for handling inconsistent real-world version formats.

class Version(PackagingVersion):
    """
    Enhanced version class implementing PEP 440 with additional normalization.
    
    This class extends packaging.version.Version with specialized transformations
    to handle common version format inconsistencies found in real-world software
    projects across different platforms and release practices.
    """
    
    def __init__(self, version: str):
        """
        Initialize Version with intelligent normalization.
        
        Parameters:
        - version: Version string to parse and normalize
        
        Raises:
        - InvalidVersion: If version cannot be normalized to PEP 440 format
        """
    
    @staticmethod
    def special_cases_transformation(version: str) -> str:
        """
        Apply specialized transformations for common version format issues.
        
        Handles cases like:
        - Release candidate formats (rc1.2 → rc1)
        - Post-release patterns (p1 → post1)
        - Preview/early access versions
        - Beta-RC combinations
        - Dashed pre-release formats
        
        Parameters:
        - version: Raw version string
        
        Returns:
        - Transformed version string compatible with PEP 440
        """

Version Transformation Patterns

The Version class applies various regex-based transformations to normalize version strings:

# Dashed substitution patterns applied during normalization
regex_dashed_substitutions = [
    (re.compile(r"-p(\d+)$"), "-post\\1"),           # -p1 → -post1
    (re.compile(r"-preview-(\d+)"), "-pre\\1"),      # -preview-1 → -pre1
    (re.compile(r"-early-access-(\d+)"), "-alpha\\1"), # -early-access-1 → -alpha1
    (re.compile(r"-pre-(\d+)"), "-pre\\1"),          # -pre-1 → -pre1
    (re.compile(r"-beta[-.]rc(\d+)"), "-beta\\1"),   # -beta-rc1 → -beta1
    (re.compile(r"^pre-(.*)"), "\\1-pre0"),          # pre-1.0 → 1.0-pre0
]

# Part normalization mapping for common pre-release identifiers
part_to_pypi_dict = {
    "devel": "dev0",
    "test": "dev0", 
    "dev": "dev0",
    "alpha": "a0",
    "beta": "b0",
    "rc": "rc0",
    "preview": "rc0",
    "pre": "rc0",
}

Version Parsing Utilities

Utility functions for extracting and parsing version information from various sources.

def parse_version(tag: str) -> Version:
    """
    Parse version from git tag or other version source.
    
    Extracts version information from tag strings that may contain
    prefixes, suffixes, or other metadata beyond the core version.
    
    Parameters:
    - tag: Tag string or version identifier
    
    Returns:
    - Version object with parsed and normalized version
    
    Raises:
    - InvalidVersion: If no valid version can be extracted
    """

Usage Examples

Basic Version Operations

from lastversion.version import Version

# Create version objects
v1 = Version("1.2.3")
v2 = Version("1.2.4")

# Version comparison
print(v1 < v2)        # True
print(v1 == v2)       # False
print(max(v1, v2))    # Version('1.2.4')

# String representation
print(str(v1))        # "1.2.3"
print(repr(v1))       # "<Version('1.2.3')>"

Handling Inconsistent Formats

from lastversion.version import Version

# Normalize various real-world version formats
versions = [
    "v1.2.3-rc1",           # Git tag with prefix
    "release-1.2.3",        # Release prefix
    "1.2.3-p1",            # Post-release
    "1.2.3-preview-1",      # Preview release
    "1.2.3-beta-rc2",       # Beta release candidate
    "pre-1.2.3",           # Pre-release prefix
]

normalized = [Version(v) for v in versions]
for orig, norm in zip(versions, normalized):
    print(f"{orig} → {norm}")

Version Filtering and Selection

from lastversion.version import Version
from packaging.version import InvalidVersion

def filter_stable_versions(version_strings):
    """Filter out pre-release and invalid versions."""
    stable_versions = []
    
    for version_str in version_strings:
        try:
            version = Version(version_str)
            # Check if it's a stable release (no pre-release components)
            if not version.is_prerelease:
                stable_versions.append(version)
        except InvalidVersion:
            continue  # Skip invalid versions
    
    return sorted(stable_versions)

# Example usage
raw_versions = ["1.0.0", "1.1.0-beta", "1.1.0", "2.0.0-rc1", "2.0.0"]
stable = filter_stable_versions(raw_versions)
print(f"Latest stable: {max(stable)}")  # Version('2.0.0')

Integration with Core Functions

from lastversion import latest
from lastversion.version import Version

# Get version object directly
version_obj = latest("mautic/mautic", output_format="version")

# Version objects support all comparison operations
if version_obj >= Version("4.0.0"):
    print("Major version 4 or higher")

# Check version properties
print(f"Is prerelease: {version_obj.is_prerelease}")
print(f"Is devrelease: {version_obj.is_devrelease}")
print(f"Major version: {version_obj.major}")
print(f"Minor version: {version_obj.minor}")
print(f"Micro version: {version_obj.micro}")

Custom Version Transformations

from lastversion.version import Version

# Example of how special_cases_transformation works
test_versions = [
    "1.0.0-p1",          # Post release
    "2.0.0-preview-1",   # Preview
    "3.0.0-beta-rc2",    # Beta release candidate
    "pre-4.0.0",         # Pre-prefixed version
]

for version_str in test_versions:
    transformed = Version.special_cases_transformation(version_str)
    version_obj = Version(transformed)
    print(f"{version_str} → {transformed} → {version_obj}")

Error Handling

from lastversion.version import Version
from packaging.version import InvalidVersion

def safe_version_parse(version_str):
    """Safely parse version with error handling."""
    try:
        return Version(version_str)
    except InvalidVersion as e:
        print(f"Invalid version '{version_str}': {e}")
        return None

# Example usage
versions = ["1.2.3", "invalid", "1.2.3-rc1", "not.a.version"]
parsed = [safe_version_parse(v) for v in versions]
valid_versions = [v for v in parsed if v is not None]

Install with Tessl CLI

npx tessl i tessl/pypi-lastversion

docs

core-functions.md

exceptions.md

index.md

repository-holders.md

utilities.md

version-handling.md

tile.json