Search code examples
pythoncmakeversioning

How to properly implement single source project versioning in Python?


I love the way CMake allows me to single source version my C/C++ projects, by letting me say:

project(Tutorial VERSION 1.0)

in my CMakeLists.txt file and, then, use placeholders of the form:

#define ver_maj @Tutorial_VERSION_MAJOR@
#define ver_min @Tutorial_VERSION_MINOR@

in my *.h.in file, which, when run through configure_file(), becomes:

#define ver_maj 1
#define ver_min 0

in my equivalent *.h file.
I'm then able to include that file anywhere I need access to my project version numbers.

This is decidedly different than the experience I have with Python projects. In that case, I'm often rebuilding, because I forgot to sync. up the version numbers in my pyproject.toml and <module>/__init__.py files.

What is the preferred way to achieve something similar to CMake style single source project versioning in a Python project?


Solution

  • In the __init__.py you can set the __version__ like this:

    from importlib.metadata import version as _get_version
    
    # Set PEP396 version attribute
    __version__ = _get_version('<put-your-package-name-here>')
    

    Or, if your package targeted older Python:

    import sys
    if sys.version_info >= (3, 8):
        from importlib.metadata import version as _get_version
    else:
        from importlib_metadata import version as _get_version
    
    # …
    

    and a package requirement:

    importlib-metadata = {version = ">= 3.6", markers="python_version < '3.8'"}
    

    (use the proper syntax for your build tool)

    Also, there are some extensions for build tools (e.g., setuptools-scm or hatch-vcs) that allows avoiding setting explicit version in the pyproject.toml for the sake of e.g., git. So, the only source of version becomes VCS used.