The blessed package to manage your versions by SCM tags
—
setuptools-scm uses configurable schemes to transform SCM metadata into version strings. Version schemes determine the main version format, while local schemes control the local version identifier (the part after +).
Functions that determine how the main version string is calculated from SCM metadata.
def guess_next_dev_version(version: ScmVersion) -> str:
"""
Default version scheme. Returns exact tag for clean repos,
or guessed next version with .dev suffix for repos with commits after tag.
Examples:
- Exact tag "1.0.0" → "1.0.0"
- Tag "1.0.0" + 3 commits → "1.0.1.dev3"
"""
def no_guess_dev_version(version: ScmVersion) -> str:
"""
Returns exact tag for clean repos, tag with .dev suffix for dirty repos.
Does not attempt to guess next version.
Examples:
- Exact tag "1.0.0" → "1.0.0"
- Tag "1.0.0" + 3 commits → "1.0.0.dev3"
"""
def only_version(version: ScmVersion) -> str:
"""
Always returns the exact tag version, ignoring distance and dirty state.
Examples:
- Tag "1.0.0" (any state) → "1.0.0"
"""
def postrelease_version(version: ScmVersion) -> str:
"""
Uses post-release versioning scheme with .post suffix.
Examples:
- Exact tag "1.0.0" → "1.0.0"
- Tag "1.0.0" + 3 commits → "1.0.0.post3"
"""
def simplified_semver_version(version: ScmVersion) -> str:
"""
Simplified semantic versioning that bumps appropriate version component.
Examples:
- Exact tag "1.0.0" → "1.0.0"
- Tag "1.0.0" + commits → "1.0.1.dev{distance}"
- Feature branch → "1.1.0.dev{distance}"
"""
def release_branch_semver_version(version: ScmVersion) -> str:
"""
Semantic versioning with release branch support.
Different bumping strategy based on branch patterns.
"""
def calver_by_date(version: ScmVersion) -> str:
"""
Calendar versioning scheme using current date.
Examples:
- Tag "2023.1.0" + commits → "2023.1.1.dev{distance}"
"""Functions that determine the local version identifier (part after + in version string).
def get_local_node_and_date(version: ScmVersion) -> str:
"""
Default local scheme. Includes commit hash and date.
Examples:
- Clean repo → "" (no local part)
- Dirty repo → "+g{node}.d20231201"
- Commits after tag → "+g{node}.d20231201"
"""
def get_local_node_and_timestamp(version: ScmVersion) -> str:
"""
Local scheme with commit hash and timestamp.
Examples:
- Dirty repo → "+g{node}.{timestamp}"
"""
def get_local_dirty_tag(version: ScmVersion) -> str:
"""
Simple local scheme that only adds suffix for dirty repos.
Examples:
- Clean repo → "" (no local part)
- Dirty repo → "+dirty"
"""
def get_no_local_node(version: ScmVersion) -> str:
"""
No local version identifier scheme.
Examples:
- Any state → "" (no local part)
"""Utility functions for version processing and manipulation.
def tag_to_version(tag: str, config: Configuration) -> Version | None:
"""
Convert a tag string to a Version object using tag regex.
Parameters:
- tag: Tag string from SCM
- config: Configuration with tag_regex pattern
Returns:
Version object or None if tag doesn't match regex
"""
def meta(
tag: str,
*,
distance: int = 0,
dirty: bool = False,
node: str | None = None,
preformatted: bool = False,
branch: str | None = None,
config: Configuration,
node_date: date | None = None
) -> ScmVersion:
"""
Create ScmVersion object from tag metadata.
Parameters:
- tag: Version tag string
- distance: Number of commits since tag
- dirty: Whether working directory has uncommitted changes
- node: Commit hash/node identifier
- preformatted: Whether tag is already formatted
- branch: Branch name
- config: Configuration object
- node_date: Date of the commit
Returns:
ScmVersion object with parsed metadata
"""
def format_version(version: ScmVersion, **kwargs) -> str:
"""
Format ScmVersion to final version string using configured schemes.
Parameters:
- version: ScmVersion object to format
- **kwargs: Additional formatting arguments
Returns:
Final formatted version string
"""
def guess_next_version(tag_version: ScmVersion) -> str:
"""
Guess the next version based on current tag.
Used internally by guess_next_dev_version scheme.
Parameters:
- tag_version: ScmVersion with current tag information
Returns:
Guessed next version string
"""
def guess_next_simple_semver(
version: ScmVersion,
retain: int,
increment: bool = True
) -> str:
"""
Guess next semantic version with configurable component retention.
Parameters:
- version: ScmVersion object
- retain: Number of version components to retain (1=major, 2=minor, 3=patch)
- increment: Whether to increment the last retained component
Returns:
Next semantic version string
"""from setuptools_scm import get_version
# Use different version schemes
dev_version = get_version(version_scheme="guess-next-dev")
post_version = get_version(version_scheme="post-release")
exact_version = get_version(version_scheme="only-version")
semver_version = get_version(version_scheme="python-simplified-semver")
print(f"Dev: {dev_version}") # e.g., "1.0.1.dev3+g1234567.d20231201"
print(f"Post: {post_version}") # e.g., "1.0.0.post3+g1234567.d20231201"
print(f"Exact: {exact_version}") # e.g., "1.0.0+g1234567.d20231201"
print(f"Semver: {semver_version}") # e.g., "1.0.1.dev3+g1234567.d20231201"from setuptools_scm import get_version
# Use different local schemes
node_date = get_version(local_scheme="node-and-date")
node_timestamp = get_version(local_scheme="node-and-timestamp")
dirty_only = get_version(local_scheme="dirty-tag")
no_local = get_version(local_scheme="no-local-version")
print(f"Node+Date: {node_date}") # e.g., "1.0.0+g1234567.d20231201"
print(f"Node+Time: {node_timestamp}") # e.g., "1.0.0+g1234567.1701432000"
print(f"Dirty: {dirty_only}") # e.g., "1.0.0+dirty" or "1.0.0"
print(f"No local: {no_local}") # e.g., "1.0.0"[tool.setuptools_scm]
version_scheme = "python-simplified-semver"
local_scheme = "no-local-version"
tag_regex = "^(?P<version>[vV]?\\d+(?:\\.\\d+){0,2}[^\\+]*)(?:\\+.*)?$"
fallback_version = "0.0.0"You can define custom schemes by creating entry points in your package:
[project.entry-points."setuptools_scm.version_scheme"]
"my-custom-scheme" = "mypackage.version:my_version_scheme"
[project.entry-points."setuptools_scm.local_scheme"]
"my-local-scheme" = "mypackage.version:my_local_scheme"# mypackage/version.py
def my_version_scheme(version):
"""Custom version scheme implementation"""
if version.exact:
return str(version.tag)
return f"{version.tag}.custom{version.distance}"
def my_local_scheme(version):
"""Custom local scheme implementation"""
if version.dirty:
return "+modified"
return ""from setuptools_scm.version import meta
from setuptools_scm import Configuration
config = Configuration()
# Create ScmVersion manually (normally done internally)
scm_ver = meta(
tag="1.0.0",
distance=3,
dirty=True,
node="abc1234",
branch="main",
config=config
)
# Use built-in formatting methods
clean_fmt = scm_ver.format_choice("{tag}", "{tag}.dirty{distance}")
custom_fmt = scm_ver.format_with("v{tag}-{distance}-{node}")
print(f"Clean/Dirty: {clean_fmt}") # "1.0.0.dirty3"
print(f"Custom: {custom_fmt}") # "v1.0.0-3-abc1234"DEFAULT_VERSION_SCHEME: str = "guess-next-dev"
DEFAULT_LOCAL_SCHEME: str = "node-and-date"
DEFAULT_TAG_REGEX: Pattern[str] # Regex pattern: ^(?:[\w-]+-)?(?P<version>[vV]?\d+(?:\.\d+){0,2}[^\+]*)(?:\+.*)?$Install with Tessl CLI
npx tessl i tessl/pypi-setuptools-scm