Poetry: Automatically generate package version from git commit
All notes in this series:
- (1) Poetry: Fixing dubious ownership error
- (2) Poetry: build.py example
- (3) Poetry: Automatically generate package version from git commit
- (4) Poetry: Fix warning about sources
- (5) Poetry: Running Black and isort with pre-commit hooks
- (6) Poetry: Fixing permission error when upgrading dulwich
- (7) NiceGUI with Click, Poetry, auto-reload and classes
- (8) Poetry: Offline installation of packages
- (9) Run Poetry command as systemd service
- (10) GitLab CI and poetry-dynamic-versioning
- (11) Poetry: install alpha builds
When building a Python package that is stored in git, it can be convenient to automatically generate the package version from the git commit and/or tag. That way there is no need to manually “bump” the version number in your Python code. Instead, each commit in git automatically generates a version such as:
1.2.3.dev45+g23b6cfd
And each tag generates a version such as:
1.2.3
Using setup.py build
, this could be done using setuptools_scm
, but using setup.py
in this manner is deprecated.
Instead, we can perform our build using Poetry, and use the poetry-dynamic-versioning
plugin to replace setuptools_scm
.
Steps §
- Run
poetry self add "poetry-dynamic-versioning[plugin]"
to install thepoetry-dynamic-versioning
plugin. - Add the following to your
pyproject.toml
:1
[tool.poetry-dynamic-versioning]
enable = true
vcs = "git"
pattern = "^(?P<base>\\d+\\.\\d+\\.\\d+)(-?((?P<stage>[a-zA-Z]+)\\.?(?P<revision>\\d+)?))?"
format-jinja = """
{%- if distance == 0 -%}
{{- base -}}
{%- else -%}
{{- base }}.dev{{ distance }}+g{{commit}}
{%- endif -%}
"""
- Then just run
poetry build
and check the output:
$ ls dist/
my_package-1.2.3.dev45+g23b6cfd-py3-none-any.whl
Bonus: Python imports §
If you want to have some fun, you can use Python imports within format-jinja
if you first specify them within format-jinja-imports
.
For example, this:
format-jinja-imports = [
{ module = "pathlib", item = "Path" },
{ module = "platform" },
]
Is equivalent to:
from pathlib import Path
import platform
Then you could, e.g. read the version string from file at /tmp/version_string.txt
if building on Linux:
format-jinja = """
{%- if platform.system() == "Linux" and Path("/tmp/version_string.txt").exists() -%}
{{ Path("/tmp/version_string.txt").read_text().strip() }}
{%- else -%}
{{- base }}.dev{{ distance }}+g{{commit}}
{%- endif -%}
"""
Using poetry-dynamic-versioning with GitLab §
If using poetry-dynamic-versioning with GitLab, you may find these notes helpful.
Thanks to mtkennerly for giving this example. ↩︎