1

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?

dbanas
  • 1,707
  • 14
  • 24
  • What build system are you using for Python? This is very build system specific, as they pretty much all expose different mechanisms for specifying/discovery the distribution version – Brian61354270 Feb 19 '23 at 18:10
  • Build tools may differ in how they *produce* the package, but the end result should conform to a standard format that can be queried using the [`importlib.metadata`](https://docs.python.org/3/library/importlib.metadata.html) module in the standard library. – chepner Feb 19 '23 at 18:18
  • @Brian61354270, I'm using `conda-build`. – dbanas Apr 05 '23 at 18:39
  • @chepner, and is that library intended to support self-referencing queries? (Please, see my response to zaufi, below.) – dbanas Apr 05 '23 at 18:41

1 Answers1

1

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.

zaufi
  • 6,811
  • 26
  • 34
  • Is this approach intended to work for self-referencing cases? That is, if I put the line `__version__ = _get_version('myproj')` in the `myproj/__init__.py` file, should that work, or will it fail due to the circular reference? (I'm trying it and it's failing.) – dbanas Apr 05 '23 at 18:46
  • Why it should fail? `hatch-vcs` will set the metadata for the package at build-time and the given statement just gets it at run-time. – zaufi Apr 06 '23 at 20:07
  • If you don't use `hatch-vcs` (or similar) it's just a run-time getting part that remains. Not a failure reason anyway. – zaufi Apr 06 '23 at 20:09