Versioning It with your Version In Git - automatic package versioning based on VCS tags
—
Object-oriented interface providing fine-grained control over the version calculation pipeline. This class allows step-by-step execution, detailed reporting, and advanced customization of the versioning process.
Create Versioningit instances from project directories or configuration objects.
class Versioningit:
project_dir: Path
default_version: Optional[str]
vcs: VersioningitMethod
tag2version: VersioningitMethod
next_version: VersioningitMethod
format: VersioningitMethod
template_fields: VersioningitMethod
write: Optional[VersioningitMethod]
onbuild: Optional[VersioningitMethod]
@classmethod
def from_project_dir(
cls, project_dir: str | Path = os.curdir, config: Optional[dict] = None
) -> Versioningit:
"""
Construct a Versioningit object for the project rooted at project_dir.
Parameters:
- project_dir: Project root directory (default: current directory)
- config: Configuration dict or None to read from configuration file
Returns:
Versioningit: Configured instance ready for version calculation
Raises:
- NoConfigFileError: if config is None and no configuration file exists
- NoConfigSectionError: if configuration file has no versioningit section
- ConfigError: if configuration values are invalid
"""
@classmethod
def from_config(cls, project_dir: str | Path, config: Config) -> Versioningit:
"""
Construct a Versioningit object from a parsed configuration object.
"""Execute the version calculation pipeline with optional file writing.
def get_version(self, write: bool = False, fallback: bool = True) -> str:
"""
Determine the version for the project.
Parameters:
- write: Whether to update file specified in write configuration
- fallback: Whether to read from PKG-INFO if not under version control
Returns:
str: The calculated version string
Raises:
- NotVCSError: if fallback is False and not under version control
- NotSdistError: if fallback is True, not under VCS, and no PKG-INFO
- ConfigError: if configuration values are invalid
- MethodError: if a method returns wrong type
"""
def run(
self, write: bool = False, fallback: bool = True
) -> Report | FallbackReport:
"""
Run all pipeline steps and return detailed report with intermediate values.
Parameters:
- write: Whether to update file specified in write configuration
- fallback: Whether to read from PKG-INFO if not under version control
Returns:
Report | FallbackReport: Detailed execution report with all calculated values
Raises:
- NotVCSError: if fallback is False and not under version control
- NotSdistError: if fallback is True, not under VCS, and no PKG-INFO
- ConfigError: if configuration values are invalid
- MethodError: if a method returns wrong type
"""Execute individual pipeline steps for debugging or custom workflows.
def do_vcs(self) -> VCSDescription:
"""
Run the vcs step to query version control system.
Returns:
VCSDescription: Repository state information
Raises:
- MethodError: if method does not return VCSDescription
"""
def do_tag2version(self, tag: str) -> str:
"""
Run the tag2version step to extract version from tag.
Parameters:
- tag: VCS tag string
Returns:
str: Version string extracted from tag
Raises:
- MethodError: if method does not return str
"""
def do_next_version(self, version: str, branch: Optional[str]) -> str:
"""
Run the next-version step to calculate next version.
Parameters:
- version: Base version string
- branch: Current branch name or None
Returns:
str: Calculated next version
Raises:
- MethodError: if method does not return str
"""
def do_format(
self, description: VCSDescription, base_version: str, next_version: str
) -> str:
"""
Run the format step to apply version formatting.
Parameters:
- description: VCS repository state
- base_version: Version extracted from tag
- next_version: Calculated next version
Returns:
str: Formatted version string
Raises:
- MethodError: if method does not return str
"""
def do_template_fields(
self,
version: str,
description: Optional[VCSDescription],
base_version: Optional[str],
next_version: Optional[str],
) -> dict:
"""
Run the template-fields step to generate template variables.
Parameters:
- version: Final version string
- description: VCS repository state or None
- base_version: Version from tag or None
- next_version: Calculated next version or None
Returns:
dict: Template fields for write and onbuild steps
Raises:
- MethodError: if method does not return dict
"""
def do_write(self, template_fields: dict[str, Any]) -> None:
"""
Run the write step to update version file.
Parameters:
- template_fields: Variables for template substitution
"""
def do_onbuild(
self,
file_provider: OnbuildFileProvider,
is_source: bool,
template_fields: dict[str, Any],
) -> None:
"""
Run the onbuild step to modify build artifacts.
Parameters:
- file_provider: Interface for accessing build files
- is_source: True for sdist, False for wheel
- template_fields: Variables for template substitution
"""from versioningit import Versioningit
# Create instance and get version
vgit = Versioningit.from_project_dir()
version = vgit.get_version()
print(f"Version: {version}")
# Get detailed report
report = vgit.run()
print(f"Version: {report.version}")
print(f"Base version: {report.base_version}")
print(f"Next version: {report.next_version}")
print(f"Using default: {report.using_default_version}")from versioningit import Versioningit
vgit = Versioningit.from_project_dir()
# Execute individual steps
try:
description = vgit.do_vcs()
print(f"Tag: {description.tag}")
print(f"State: {description.state}")
print(f"Branch: {description.branch}")
base_version = vgit.do_tag2version(description.tag)
print(f"Base version: {base_version}")
next_version = vgit.do_next_version(base_version, description.branch)
print(f"Next version: {next_version}")
if description.state == "exact":
final_version = base_version
else:
final_version = vgit.do_format(description, base_version, next_version)
print(f"Final version: {final_version}")
template_fields = vgit.do_template_fields(
final_version, description, base_version, next_version
)
print(f"Template fields: {template_fields}")
except Exception as e:
print(f"Error in pipeline: {e}")config = {
"default-version": "0.0.0",
"vcs": {"method": "git"},
"tag2version": {"method": "basic", "rmprefix": "v"},
"next-version": {"method": "smallest"},
"format": {
"distance": "{version}.dev{distance}+{vcs}{rev}",
"dirty": "{version}+dirty"
},
"template-fields": {"method": "basic"},
"write": {
"file": "version.txt",
"template": "{version}"
}
}
vgit = Versioningit.from_project_dir(config=config)
version = vgit.get_version(write=True)from versioningit import Versioningit, NotVCSError
vgit = Versioningit.from_project_dir()
try:
# Try without fallback first
version = vgit.get_version(fallback=False)
print(f"VCS version: {version}")
except NotVCSError:
# Fallback to PKG-INFO
try:
report = vgit.run(fallback=True)
if isinstance(report, FallbackReport):
print(f"PKG-INFO version: {report.version}")
else:
print(f"VCS version: {report.version}")
except Exception as e:
print(f"Could not determine version: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-versioningit