CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-poetry-dynamic-versioning

Plugin for Poetry to enable dynamic versioning based on VCS tags

Pending
Overview
Eval results
Files

file-management.mddocs/

File Management

File modification and restoration functionality for applying dynamic versions to project files. Handles version substitution in source code, pyproject.toml updates, and automatic cleanup with comprehensive backup and restoration capabilities.

Capabilities

Main Version Application

Core function that detects project configuration, extracts version information, and applies it to project files with automatic state management and cleanup preparation.

def _get_and_apply_version(
    pyproject_path: Optional[Path] = None,
    retain: bool = False,
    force: bool = False,
    io: bool = True
) -> Optional[str]:
    """
    Main function to get version and apply it to project files.
    
    Parameters:
    - pyproject_path: Path to pyproject.toml (auto-detected if None)
    - retain: If True, don't disable plugin in pyproject.toml during application
    - force: Apply even if plugin is disabled in configuration
    - io: If True, actually modify files (False for in-memory only)
    
    Returns:
    Optional[str]: Project name if successful, None if no project detected
    
    Raises:
    - RuntimeError: Unable to find pyproject.toml or determine version
    """

Version Application to Files

Apply version information to pyproject.toml and configured source files, handling both Classic Poetry and PEP 621 project formats with comprehensive file creation and substitution.

def _apply_version(
    name: str,
    version: str,
    instance: Version,
    config: _Config,
    pyproject_path: Path,
    mode: _Mode,
    retain: bool = False
) -> None:
    """
    Apply version to pyproject.toml and configured files.
    
    Parameters:
    - name: Project name for state tracking
    - version: Formatted version string to apply
    - instance: Dunamai Version object for template rendering
    - config: Configuration containing file and substitution settings
    - pyproject_path: Path to project's pyproject.toml
    - mode: Project mode (Classic or PEP 621)
    - retain: Don't disable plugin after application if True
    """

Version Restoration

Restore all modified files to their original state, removing version changes and re-enabling plugin configuration to maintain repository cleanliness.

def _revert_version(retain: bool = False) -> None:
    """
    Revert all version changes back to original state.
    
    Parameters:
    - retain: Don't re-enable plugin configuration if True
    """

File Substitution System

Apply version substitution to multiple files using configurable patterns and folder structures with support for different substitution modes and file creation.

def _substitute_version(name: str, version: str, folders: Sequence[_FolderConfig]) -> None:
    """
    Substitute version in specified files using configured patterns.
    
    Parameters:
    - name: Project name for state tracking
    - version: Version string to substitute into files
    - folders: Folder configurations with file patterns and substitution rules
    """

Text Pattern Substitution

Core text substitution functionality supporting string and tuple modes for different version placeholder formats commonly used in Python projects.

def _substitute_version_in_text(version: str, content: str, patterns: Sequence[_SubPattern]) -> str:
    """
    Perform text substitution with version using configured patterns.
    
    Parameters:
    - version: Version string to substitute
    - content: Original text content
    - patterns: Substitution patterns with mode specifications
    
    Returns:
    str: Modified content with version substitutions applied
    """

Configuration Classes

Folder Configuration

class _FolderConfig:
    def __init__(self, path: Path, files: Sequence[str], patterns: Sequence[_SubPattern]):
        """
        Configuration for folder-specific substitution settings.
        
        Parameters:
        - path: Base path for file pattern matching
        - files: File glob patterns to process
        - patterns: Substitution patterns to apply
        """
    
    @staticmethod
    def from_config(config: _Config, root: Path) -> Sequence["_FolderConfig"]:
        """
        Create folder configurations from main configuration and project root.
        
        Parameters:
        - config: Main configuration object
        - root: Project root path for relative path resolution
        
        Returns:
        Sequence[_FolderConfig]: List of folder configurations
        """

Substitution Patterns

class _SubPattern:
    def __init__(self, value: str, mode: str):
        """
        Individual substitution pattern with mode specification.
        
        Parameters:
        - value: Regular expression pattern with two capture groups
        - mode: Substitution mode ("str" or "tuple")
        """
    
    @staticmethod
    def from_config(config: Sequence[Union[str, Mapping]]) -> Sequence["_SubPattern"]:
        """
        Create substitution patterns from configuration.
        
        Parameters:
        - config: Pattern configuration (strings or mappings with value/mode)
        
        Returns:
        Sequence[_SubPattern]: List of substitution pattern objects
        """

Project State Management

State Tracking

class _ProjectState:
    def __init__(
        self,
        path: Path,
        original_version: Optional[str],
        version: str,
        mode: _Mode,
        dynamic_array: Optional[tomlkit.items.Array],
        substitutions: Optional[MutableMapping[Path, str]] = None,
    ) -> None:
        """
        Track state for a single project during version application.
        
        Parameters:
        - path: Path to project's pyproject.toml
        - original_version: Original version before modification
        - version: Applied dynamic version
        - mode: Project configuration mode (Classic or PEP 621)
        - dynamic_array: PEP 621 dynamic array for restoration
        - substitutions: Map of modified files to original content
        """

Global State

class _State:
    def __init__(self) -> None:
        """Global plugin state management."""
    
    patched_core_poetry_create: bool    # Whether Poetry core has been patched
    cli_mode: bool                      # Whether running in CLI mode
    projects: MutableMapping[str, _ProjectState]  # Active project states

Substitution Modes

The substitution system supports different modes for version placeholder replacement:

String Mode (default)

# Pattern captures quotes around version string
pattern = r"(^__version__\s*(?::.*?)?=\s*['\"])[^'\"]*(['\"])"
# Substitutes: __version__ = "1.2.3"

Tuple Mode

# Pattern captures parentheses around version tuple
pattern = r"(^__version_tuple__\s*(?::.*?)?=\s*\()[^)]*(\))"
# Substitutes: __version_tuple__ = (1, 2, 3)
# With pre-release: __version_tuple__ = (1, 2, 3, "dev0", "abc123")

Usage Examples

Basic Version Application

from poetry_dynamic_versioning import _get_and_apply_version
from pathlib import Path

# Apply version to current project
project_name = _get_and_apply_version()
if project_name:
    print(f"Applied version to project: {project_name}")

# Apply with specific path and options
project_name = _get_and_apply_version(
    pyproject_path=Path("./my-project/pyproject.toml"),
    retain=True,  # Don't disable plugin
    force=True,   # Apply even if disabled
    io=True       # Actually modify files
)

Manual Version Application

from poetry_dynamic_versioning import (
    _apply_version, _get_version, _get_config, _Mode
)
from pathlib import Path

# Get configuration and version
config = _get_config_from_path()
version_str, version_obj = _get_version(config)

# Apply to specific project
pyproject_path = Path("./pyproject.toml")
_apply_version(
    name="my-project",
    version=version_str,
    instance=version_obj,
    config=config,
    pyproject_path=pyproject_path,
    mode=_Mode.Classic,
    retain=False
)

Custom Substitution Patterns

from poetry_dynamic_versioning import _substitute_version_in_text, _SubPattern

# Define custom patterns
patterns = [
    _SubPattern(r'(VERSION = ")[^"]*(")', "str"),
    _SubPattern(r'(version_info = \()[^)]*(\))', "tuple")
]

# Apply substitution to content
original_content = '''
VERSION = "0.0.0"
version_info = (0, 0, 0)
'''

new_content = _substitute_version_in_text("1.2.3", original_content, patterns)
print(new_content)
# VERSION = "1.2.3"
# version_info = (1, 2, 3)

File Restoration

from poetry_dynamic_versioning import _revert_version, _state

# Check current project states
for name, state in _state.projects.items():
    print(f"Project: {name}, Modified files: {len(state.substitutions)}")

# Revert all changes
_revert_version(retain=False)  # Re-enable plugin after revert
print("All version changes reverted")

Folder Configuration

from poetry_dynamic_versioning import _FolderConfig, _SubPattern
from pathlib import Path

# Create custom folder configuration
patterns = [_SubPattern(r'(__version__ = ")[^"]*(")', "str")]
folder_config = _FolderConfig(
    path=Path("./src"),
    files=["**/*.py"],
    patterns=patterns
)

# Apply substitution to folder
from poetry_dynamic_versioning import _substitute_version
_substitute_version("my-project", "1.2.3", [folder_config])

File Creation with Initial Content

Configuration in pyproject.toml can create files with initial content:

[tool.poetry-dynamic-versioning.files."src/mypackage/_version.py"]
initial-content = """
# This file is automatically generated by poetry-dynamic-versioning
__version__ = "0.0.0"
__version_tuple__ = (0, 0, 0)
"""
persistent-substitution = true

The system will create the file with initial content, then apply version substitution patterns to update the placeholders.

Install with Tessl CLI

npx tessl i tessl/pypi-poetry-dynamic-versioning

docs

cli-interface.md

configuration.md

file-management.md

index.md

plugin-system.md

version-detection.md

tile.json