setuptools-scm Documentation

repository·main·Indexed 21 days ago

https://github.com/pypa/setuptools-scm

An ecosystem for extracting Python package versions from Version Control System (VCS) metadata such as Git or Mercurial. The project includes the main setuptools-scm package for seamless setuptools integration and vcs-versioning, a standalone library containing core VCS versioning logic. Key features include automatic versioning via VCS tags, SCM-managed file inclusion in source distributions, and flexible configuration via pyproject.toml.

Tokens
30.8K
Snippets
95
Records
132
Agent score
70%

What's inside setuptools-scm

  1. What is setuptools-scm

    main

    setuptools-scm is a tool that extracts Python package versions from git or hg (Mercurial) metadata. Instead of manually declaring a version string in your source code or a managed file, setuptools-scm infers it from your Version Control System (VCS) state.

    Key Features:

    • Automatic Versioning: Uses VCS tags and history to determine the current version.
    • SCM-managed File Inclusion: Automatically adds all files tracked by your SCM to the source distribution (sdist).

    ⚠️ Important Security/Cleanup Note: Because it automatically includes all SCM-tracked files in your source distributions, any development files tracked in Git/Mercurial will be included in your package. To prevent unwanted files from being shipped, you must use a MANIFEST.in file to exclude them or configure Git archive settings.

  2. Overview of the setuptools-scm ecosystem

    main

    The setuptools-scm monorepo contains two primary projects:

    1. setuptools-scm: The main package used to extract Python package versions from Git or Mercurial metadata, providing seamless integration with setuptools.
    2. vcs-versioning: A standalone library containing the core VCS versioning logic, which can be used independently of setuptools.

    For specific usage instructions, refer to the individual project documentation.

  3. Remove local version components for PyPI publishing

    main

    By default, setuptools-scm generates versions with local segments (e.g., +g1a2b3c4d5 or +dirty) which are not allowed on PyPI per PEP 440. To prepare for publishing, use the SETUPTOOLS_SCM_OVERRIDES_FOR_${DIST_NAME} environment variable to override the local_scheme.

    Recommended Schemes:

    • no-local-version-strict: Use for release builds. It strips the local segment and fails the build if the working tree is dirty, preventing accidental pollution.
    • no-local-version: Use for development/nightly uploads (e.g., to test-PyPI) where a dirty tree is acceptable. It strips the local segment but allows the build to proceed.
  4. Compare GlobalOverrides and EnvReader

    main

    Choose between GlobalOverrides and EnvReader based on your integration needs:

    FeatureGlobalOverridesEnvReader
    PurposeManage standard global overridesRead any custom env vars
    Context Manager✅ Yes❌ No
    Auto-configures logging✅ Yes❌ No
    Tool fallback✅ Automatic✅ Automatic
    Dist-specific vars❌ No✅ Yes
    TOML parsing❌ No✅ Yes
    Use caseEntry point setupCustom config reading

    Typical usage together: Use GlobalOverrides as a context manager to set up the environment (logging, debug, etc.), then use EnvReader inside that context to fetch specific custom configurations.

    from vcs_versioning.overrides import GlobalOverrides, EnvReader
    import os
    
    # Apply global overrides
    with GlobalOverrides.from_env("MY_TOOL"):
        # Read custom configuration
        reader = EnvReader(
            tools_names=("MY_TOOL", "VCS_VERSIONING"),
            env=os.environ,
            dist_name="my-package"
        )
    
        custom_config = reader.read_toml("CUSTOM_CONFIG", schema=MySchema)
    
        # Both global overrides and custom config are now available
        version = detect_version_with_config(custom_config)
  5. How to use setuptools_scm.get_version() at runtime

    main

    Directly calling setuptools_scm.get_version() at runtime is strongly discouraged. You should use importlib.metadata instead.

    However, if you must use it (e.g., for legacy Sphinx configurations or specific development environments), you may need to provide root and fallback_root parameters to ensure it works correctly when the SCM metadata is not present (like in extracted tarballs) or when the script is running from a subdirectory.

    from setuptools_scm import get_version
    
    # Use root for when SCM metadata is present
    # Use fallback_root for when SCM metadata is missing (e.g. in archives)
    version = get_version(root='..', fallback_root='..', relative_to=__file__)
  6. How setuptools-scm and vcs-versioning work together

    main

    setuptools-scm is built on top of vcs-versioning.

    • vcs-versioning (core library): Handles the heavy lifting of version extraction from Git, Mercurial, and Jujutsu, including version scheme logic, tag parsing, and formatting. These features are universal and work across different build systems.
    • setuptools-scm (integration layer): Provides the setuptools-specific integration, such as build-time hooks, automatic file finder registration, and generating version files during the build process.
  7. How the experimental integrator API handles configuration priority

    main

    The experimental API uses a specific priority order when resolving configuration. This ensures users can always override settings via environment variables, while still allowing integrators to provide defaults.

    Priority Order (Highest to Lowest):

    1. Environment TOML overrides: Set via [TOOL_PREFIX]_OVERRIDES_FOR_[DIST] or [TOOL_PREFIX]_OVERRIDES.
    2. Integrator overrides: Python arguments passed directly to build_configuration_from_pyproject().
    3. Config file: Settings found in the [tool.vcs-versioning] section of pyproject.toml.
    4. Defaults: The internal default values of vcs-versioning.
  8. How the automatic file finder works

    main

    By default, setuptools-scm provides a setuptools file finder entry point. This means that when setuptools-scm is installed in your build environment, it automatically includes all SCM-tracked files in your source distributions (sdist) without requiring a MANIFEST.in file.

    Controlling file inclusion

    If you need to exclude specific files from the automatic inclusion, use one of the following methods:

    1. MANIFEST.in: Use exclude or recursive-exclude for specific files or patterns.
    2. Git Archive Configuration: Use export-ignore in .gitattributes (e.g., tests/ export-ignore).
    3. Mercurial Configuration: Use .hgignore.
  9. Understand the default versioning scheme

    main

    The version is calculated based on the latest tag, the distance from that tag, and the workdir state (uncommitted changes).

    distancestateformat
    nounchanged{tag}
    yesunchanged{next_version}.dev{distance}+{scm letter}{revision hash}
    nochanged{tag}+dYYYYMMDD
    yeschanged{next_version}.dev{distance}+{scm letter}{revision hash}.dYYYYMMDD
    • {next_version} is the last tag's numeric component + 1.
    • For Git, the hash is prefixed with g (e.g., g1a2b3c4d5).
    • Important: Always include a patch version in your tags (e.g., 1.2.3 instead of 1.2) to ensure SemVer increments correctly.
  10. Use the correct tool section in pyproject.toml

    main

    The public experimental API specifically looks for the [tool.vcs-versioning] section in pyproject.toml. While setuptools_scm may use [tool.setuptools_scm] for backward compatibility, integrators using the new API must use the vcs-versioning key.

    # ✅ Correct
    [tool.vcs-versioning]
    version_scheme = "guess-next-dev"
    local_scheme = "no-local-version"
    
    # ❌ Wrong for the public experimental API
    [tool.setuptools_scm]
    version_scheme = "guess-next-dev"
  11. Understand configuration and version resolution priority

    main

    setuptools-scm and vcs-versioning use a hierarchical system for configuration and version resolution.

    Configuration Priority

    Settings are merged in the following order (highest priority wins):

    1. Environment TOML overrides: TOOL_OVERRIDES_FOR_DIST or TOOL_OVERRIDES.
    2. Per-project overrides: A .config/python-vcs-versioning.toml file located in the SCM root.
    3. Integrator keyword arguments: Arguments passed via code (e.g., build_configuration_from_pyproject).
    4. pyproject.toml section: The [tool.setuptools_scm] or [tool.vcs-versioning] table.
    5. Defaults: Built-in defaults.

    Version Resolution Pipeline

    Once configuration is established, the version is determined in this order:

    1. Pretend version: TOOL_PRETEND_VERSION or _FOR_DIST (short-circuits all other steps).
    2. Workdir discovery: Finding the SCM root via registered entry-points or fallback files.
    3. Legacy parse entry points: Third-party setuptools_scm.parse_scm implementations.
    4. Metadata overrides: TOOL_PRETEND_METADATA or _FOR_DIST applied to the resolved version.
    5. Format: The final string is produced by combining version_scheme and local_scheme.
  12. Use Jujutsu (jj) repositories with setuptools-scm

    main

    setuptools-scm has native support for Jujutsu (jj) repositories. If a .jj/ directory is detected in the project root, the jj backend is used automatically.

    Key Behaviors

    • Automatic Detection: Uses jj commands for version inference even in colocated .jj/ and .git/ repositories.
    • Tags: Version tags are read via jj log. Use jj tag set v1.0.0 to create them.
    • Distance: Commit distance counts commits between the latest tag and the head. In jj, a dirty working copy adds 1 to the distance.
    • No Archive Support: Unlike Git/Mercurial, jj does not have a native archive mechanism for metadata. For builds from source archives, use SETUPTOOLS_SCM_PRETEND_VERSION or fallback_version.

    Disabling jj detection

    If you are in an environment (like a Docker container) where jj is not installed but a .jj/ directory exists, you must disable jj detection to fall back to Git/Mercurial. Set the following environment variable:

    export SETUPTOOLS_SCM_DISABLE_JJ=1
    # In a Dockerfile or CI config where jj is not available
    export SETUPTOOLS_SCM_DISABLE_JJ=1
    pip install -e .