Plugin for Poetry to enable dynamic versioning based on VCS tags
—
Poetry plugin integration classes and functionality that hook into Poetry's command lifecycle. Provides event-driven activation, command registration, and automatic cleanup for seamless integration with Poetry's build and development workflows.
Core Poetry plugin that integrates dynamic versioning into Poetry's application lifecycle with automatic event handling and command registration.
class DynamicVersioningPlugin(ApplicationPlugin):
def __init__(self):
"""Initialize plugin with empty application reference."""
def activate(self, application: Application) -> None:
"""
Activate the plugin within Poetry application.
Parameters:
- application: Poetry Application instance
Registers commands, validates configuration, and sets up event listeners
for COMMAND, SIGNAL, TERMINATE, and ERROR events.
"""Poetry command implementations for dynamic versioning operations accessible through Poetry's CLI interface.
class DynamicVersioningCommand(Command):
name: str = "dynamic-versioning"
description: str = "Apply the dynamic version to all relevant files..."
def __init__(self, application: Application):
"""
Initialize main dynamic versioning command.
Parameters:
- application: Poetry Application instance
"""
def handle(self) -> int:
"""
Execute dynamic versioning application.
Returns:
int: Exit code (0 for success)
"""
class DynamicVersioningEnableCommand(Command):
name: str = "dynamic-versioning enable"
description: str = "Update pyproject.toml to enable the plugin..."
def handle(self) -> int:
"""
Enable dynamic versioning in project configuration.
Returns:
int: Exit code (0 for success)
"""
class DynamicVersioningShowCommand(Command):
name: str = "dynamic-versioning show"
description: str = "Print the version without changing any files."
def handle(self) -> int:
"""
Show current dynamic version without modifications.
Returns:
int: Exit code (0 for success)
"""Internal functions that handle plugin lifecycle, dependency version patching, and conditional activation based on Poetry commands and environment settings.
def _apply_version_via_plugin(
poetry: Poetry,
retain: bool = False,
force: bool = False,
standalone: bool = False,
io: bool = True
) -> None:
"""
Apply version through the plugin system to a Poetry instance.
Parameters:
- poetry: Poetry instance to modify
- retain: Don't disable plugin in pyproject.toml if True
- force: Apply even if plugin disabled in configuration
- standalone: Report application results if True
- io: Actually modify files if True
"""
def _patch_dependency_versions(io: bool) -> None:
"""
Patch Poetry's Factory.create_poetry() for dependency version handling.
Parameters:
- io: Whether to perform actual file I/O operations
Ensures that dependencies using dynamic versioning also get processed.
"""Functions that handle PEP 517 build backend integration with automatic patching activation and cleanup.
def activate() -> None:
"""
Activate patching for build backend usage.
Checks configuration, applies necessary patches to Poetry core,
and registers cleanup handlers. Called automatically by backend module.
"""
def deactivate() -> None:
"""
Clean up and revert changes when not in CLI mode.
Restores original state and removes version modifications
to maintain repository cleanliness after build operations.
"""Functions that determine when the plugin should activate based on Poetry commands and environment configuration.
def _should_apply(command: str) -> bool:
"""
Determine if dynamic versioning should apply for a Poetry command.
Parameters:
- command: Poetry command name
Returns:
bool: True if versioning should be applied
Checks POETRY_DYNAMIC_VERSIONING_COMMANDS environment variable
and excludes commands like 'run', 'shell', and dynamic-versioning commands.
"""
def _should_apply_with_io(command: str) -> bool:
"""
Determine if dynamic versioning should modify files for a command.
Parameters:
- command: Poetry command name
Returns:
bool: True if files should be modified
Checks POETRY_DYNAMIC_VERSIONING_COMMANDS_NO_IO environment variable
and excludes 'version' command by default.
"""The plugin registers event listeners for comprehensive lifecycle management:
The plugin system respects several environment variables for behavior control:
# Command filtering
POETRY_DYNAMIC_VERSIONING_COMMANDS: str
# Comma-separated list of commands to activate on
# Default: All commands except 'run', 'shell', and dynamic-versioning commands
POETRY_DYNAMIC_VERSIONING_COMMANDS_NO_IO: str
# Comma-separated list of commands that shouldn't modify files
# Default: "version"The plugin is automatically registered through Poetry's plugin system via entry points in pyproject.toml:
[tool.poetry.plugins."poetry.application.plugin"]
poetry-dynamic-versioning = "poetry_dynamic_versioning.plugin:DynamicVersioningPlugin"from poetry.console.application import Application
from poetry_dynamic_versioning.plugin import DynamicVersioningPlugin
# Create Poetry application
app = Application()
# Manually activate plugin
plugin = DynamicVersioningPlugin()
plugin.activate(app)
# Plugin is now registered and will handle eventsOnce the plugin is installed and activated, commands are available through Poetry CLI:
# Apply dynamic versioning manually
poetry dynamic-versioning
# Enable dynamic versioning in project
poetry dynamic-versioning enable
# Show current version without changes
poetry dynamic-versioning showfrom poetry.console.application import Application
from poetry_dynamic_versioning.plugin import DynamicVersioningCommand
# Create application and command
app = Application()
command = DynamicVersioningCommand(app)
# Execute command programmatically
exit_code = command.handle()
print(f"Command completed with exit code: {exit_code}")from cleo.events.console_command_event import ConsoleCommandEvent
from poetry_dynamic_versioning.plugin import DynamicVersioningPlugin
class CustomPlugin(DynamicVersioningPlugin):
def _apply_version(self, event: ConsoleCommandEvent, kind: str, dispatcher) -> None:
print(f"Applying version for command: {event.command.name}")
super()._apply_version(event, kind, dispatcher)
def _revert_version(self, event: ConsoleCommandEvent, kind: str, dispatcher) -> None:
print(f"Reverting version after command: {event.command.name}")
super()._revert_version(event, kind, dispatcher)import os
from poetry_dynamic_versioning.plugin import _should_apply, _should_apply_with_io
# Set environment to limit activation to specific commands
os.environ["POETRY_DYNAMIC_VERSIONING_COMMANDS"] = "build,publish"
# Check if versioning should apply
should_version = _should_apply("build") # True
should_io = _should_apply_with_io("build") # True
should_version = _should_apply("run") # False (excluded command)
should_io = _should_apply_with_io("version") # False (no-IO command)The plugin also integrates with PEP 517 build backends through the patch system:
# pyproject.toml configuration
[build-system]
requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"]
build-backend = "poetry_dynamic_versioning.backend"The backend automatically activates patching to ensure dynamic versioning works with tools like pip and build that use the PEP 517 interface.
from poetry_dynamic_versioning.plugin import _patch_dependency_versions
from poetry.core.factory import Factory
# Check if patching is active
from poetry_dynamic_versioning import _state
if _state.patched_core_poetry_create:
print("Poetry Factory has been patched for dynamic versioning")
# Manually trigger patching (usually automatic)
_patch_dependency_versions(io=True)Install with Tessl CLI
npx tessl i tessl/pypi-poetry-dynamic-versioning