One Version to Rule Them All: Keeping Your Python Package Version Number in Sync With Git and Poetry

Poetry is my current favourite packaging and dependency management tool for Python. It combines dependency resolution, virtual environments, and packing all into one easy to use tool. However, my one big complaint at the moment is the lack of synchronization between my package version (defined in pyproject.toml) and my git tags.

Before jumping straight to poetry plugins that add dynamic versioning (and add an extra dependency), there’s a simple workaround.

Standard Release Workflow

A typical release workflow with poetry looks something like this:

  1. Use poetry to bump your package version

    poetry version patch
    
    >>> Bumping version from 0.1.0 to 0.1.1
    
  2. Create a tag to define your release in git

    git tag 0.1.1
    git push --tags
    
  3. Hope you used the same version number for both steps

Synchronized Release Workflow

To avoid human errors, we can link our poetry version to our git tags.

  1. Update pyproject.toml to have a generic version placeholder

    [tool.poetry]
    version = "0.0.0"
    
  2. Update your release script to fetch the git version before building the package artifacts

    poetry version $(git describe --tags --abbrev=0)
    poetry build
    

With this setup, poetry will fetch and use the latest git tag as its version.

As an application example and shown below, the GitHub Action that’s used to build and publish pybotics to PyPI uses the above process to keep things simple.

name: Publish

on:
  release:
    types: [created]

jobs:
  deploy:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install poetry        
    - name: Build and publish
      run: |
        poetry version $(git describe --tags --abbrev=0)
        poetry build
        poetry publish --username ${{ secrets.PYPI_USERNAME }} --password ${{ secrets.PYPI_PASSWORD }}        

Less dependencies (e.g., dynamic versioning plugins) means less things that can break. This is especially important during the release step.

Nicholas Nadeau, Ph.D., P.Eng.
Nicholas Nadeau, Ph.D., P.Eng.
Founder / Fractional CTO

Nicholas Nadeau is a fractional CTO empowering startups with next-gen technology expertise, and a passion for driving corporate innovation. Stay informed on cutting-edge hard tech trends - subscribe to my newsletter. Ready to innovate? Discover my services and accelerate your growth.

Related