The blessed package to manage your versions by SCM tags
—
The core API provides the fundamental functions and classes for extracting version information from SCM repositories. These components form the foundation of setuptools-scm's functionality.
from re import Pattern
from datetime import date, datetime
from typing import Any, Callable, Sequence
from os import PathLike
# Type Aliases (from setuptools_scm)
PathT = PathLike[str] | str
CMD_TYPE = Sequence[PathT] | str
VERSION_SCHEME = str | Callable[["ScmVersion"], str]Primary entry points for getting version information from SCM repositories with extensive configuration options.
def get_version(
root: PathT = ".",
version_scheme: VERSION_SCHEME = "guess-next-dev",
local_scheme: VERSION_SCHEME = "node-and-date",
write_to: PathT | None = None,
write_to_template: str | None = None,
version_file: PathT | None = None,
version_file_template: str | None = None,
relative_to: PathT | None = None,
tag_regex: str | Pattern[str] = DEFAULT_TAG_REGEX,
parentdir_prefix_version: str | None = None,
fallback_version: str | None = None,
fallback_root: PathT = ".",
parse: Any | None = None,
git_describe_command: CMD_TYPE | None = None,
dist_name: str | None = None,
version_cls: Any | None = None,
normalize: bool = True,
search_parent_directories: bool = False
) -> str:
"""
Get version from SCM metadata.
Parameters:
- root: Directory to search for SCM repository
- version_scheme: Strategy for version calculation (default: "guess-next-dev")
- local_scheme: Strategy for local version part (default: "node-and-date")
- write_to: Path to write version file
- write_to_template: Template for version file content
- version_file: Path for version file relative to project
- version_file_template: Template for version file
- relative_to: File path to resolve root relatively from (typically __file__)
- tag_regex: Regex for parsing version tags
- parentdir_prefix_version: Prefix to strip from parent directory name
- fallback_version: Version to use if SCM detection fails
- fallback_root: Root directory for fallback parsing
- parse: Custom parse function
- git_describe_command: Custom git describe command
- dist_name: Distribution name for version file generation
- version_cls: Custom version class
- normalize: Whether to normalize version strings
- search_parent_directories: Whether to search parent directories for SCM
Returns:
Version string extracted from SCM
"""def _get_version(
config: Configuration,
force_write_version_files: bool | None = None
) -> str | None:
"""
Internal version retrieval using Configuration object.
Parameters:
- config: Configuration object with all settings
- force_write_version_files: Whether to force writing version files
Returns:
Version string or None if no version could be determined
"""Configuration class that encapsulates all setuptools-scm settings and provides methods for loading from files.
@dataclasses.dataclass
class Configuration:
"""Global configuration model for setuptools-scm"""
relative_to: PathT | None = None
root: PathT = "."
version_scheme: VERSION_SCHEME = "guess-next-dev"
local_scheme: VERSION_SCHEME = "node-and-date"
tag_regex: Pattern[str] = DEFAULT_TAG_REGEX
parentdir_prefix_version: str | None = None
fallback_version: str | None = None
fallback_root: PathT = "."
write_to: PathT | None = None
write_to_template: str | None = None
version_file: PathT | None = None
version_file_template: str | None = None
git_describe_command: CMD_TYPE | None = None
dist_name: str | None = None
version_cls: type = Version
parse: Any | None = None
search_parent_directories: bool = False
@property
def absolute_root(self) -> str:
"""Returns the absolute path to the repository root"""
@classmethod
def from_file(
cls,
name: PathT = "pyproject.toml",
dist_name: str | None = None,
**kwargs
) -> "Configuration":
"""
Read configuration from pyproject.toml file.
Parameters:
- name: Path to pyproject.toml file
- dist_name: Distribution name for file generation
- **kwargs: Additional configuration overrides
Returns:
Configuration object loaded from file
"""
@classmethod
def from_data(cls, relative_to: PathT, data: dict[str, Any]) -> "Configuration":
"""
Create configuration from data dictionary.
Parameters:
- relative_to: File path to resolve root from
- data: Configuration data as dictionary
Returns:
Configuration object created from data
"""Data class representing a parsed version from SCM with formatting capabilities.
@dataclasses.dataclass
class ScmVersion:
"""Represents a parsed version from SCM metadata"""
tag: Version | NonNormalizedVersion | str
"""The related tag or preformatted version string"""
config: Configuration
"""The configuration used to parse the version"""
distance: int = 0
"""The number of commits since the tag"""
node: str | None = None
"""The shortened node/commit ID"""
dirty: bool = False
"""Whether the working copy had uncommitted changes"""
preformatted: bool = False
"""Whether the version string was preformatted"""
branch: str | None = None
"""The branch name if any"""
node_date: date | None = None
"""The date of the commit if available"""
time: datetime = dataclasses.field(default_factory=_source_epoch_or_utc_now)
"""The current time or source epoch time"""
@property
def exact(self) -> bool:
"""Returns True if checked out exactly on a tag with no local changes"""
return self.distance == 0 and not self.dirty
def format_with(self, fmt: str, **kw: object) -> str:
"""
Format a given format string with attributes of this object.
Parameters:
- fmt: Format string with placeholders like {tag}, {distance}, {node}
- **kw: Additional keyword arguments for formatting
Returns:
Formatted version string
"""
def format_choice(self, clean_format: str, dirty_format: str, **kw: object) -> str:
"""
Choose format based on dirty state and format using format_with.
Parameters:
- clean_format: Format string for clean repository state
- dirty_format: Format string for dirty repository state
- **kw: Additional keyword arguments for formatting
Returns:
Formatted version string based on repository state
"""
def format_next_version(
self,
guess_next: Callable,
fmt: str = "{guessed}.dev{distance}",
*args,
**kwargs
) -> str:
"""
Format next version using a guess function.
Parameters:
- guess_next: Function that guesses the next version
- fmt: Format string for the result
- *args, **kwargs: Arguments passed to guess function
Returns:
Formatted next version string
"""Version handling classes that control normalization and string representation.
class Version:
"""Standard packaging Version class (from packaging.version)"""
class NonNormalizedVersion(Version):
"""
A non-normalizing version handler that preserves original version strings.
Use this class to preserve version verification but skip normalization.
For example, to avoid git release candidate version tags ("1.0.0-rc1")
being normalized to "1.0.0rc1". Only use if you fully trust version tags.
"""
def __init__(self, version: str) -> None:
"""
Initialize with version string.
Parameters:
- version: Version string to preserve
"""
def __str__(self) -> str:
"""Return the non-normalized version string"""
def __repr__(self) -> str:
"""Return representation showing non-normalized version"""from setuptools_scm import get_version
# Simple case - get version from current directory
version = get_version()
print(f"Current version: {version}")
# Specify repository location
version = get_version(root="/path/to/my/repo")
print(f"Repo version: {version}")from setuptools_scm import get_version, Configuration
import re
# Custom tag regex for non-standard tag formats
custom_regex = re.compile(r"^release-(?P<version>.+)$")
version = get_version(
tag_regex=custom_regex,
version_scheme="only-version",
local_scheme="no-local-version"
)
# Configuration object approach
config = Configuration(
root=".",
version_scheme="simplified-semver",
local_scheme="node-and-date",
fallback_version="0.0.0.dev0",
write_to="src/mypackage/_version.py"
)
from setuptools_scm import _get_version
version = _get_version(config)from setuptools_scm import Configuration, _get_version
config = Configuration()
# This would typically be called internally, but shown for illustration
version_obj = setuptools_scm._get_version_impl.parse_version(config)
if version_obj:
print(f"Tag: {version_obj.tag}")
print(f"Distance: {version_obj.distance}")
print(f"Node: {version_obj.node}")
print(f"Dirty: {version_obj.dirty}")
print(f"Exact: {version_obj.exact}")
# Custom formatting
custom_format = version_obj.format_with("{tag}.post{distance}")
print(f"Custom format: {custom_format}")Install with Tessl CLI
npx tessl i tessl/pypi-setuptools-scm