How to Keep Your Python Package Metadata in Sync with GitHub Release Tags

Keeping versions aligned across setup.py, pyproject.toml, and GitHub tags is critical for maintaining a healthy Python project. It prevents mismatches, enables CI/CD automation, and ensures seamless releases.

In this guide, you’ll learn best practices for versioning Python packages and syncing metadata with GitHub release tags using bump-my-version, GitHub Actions, and automation scripts.


Table of Contents

  1. Why Versioning is Crucial
  2. The Right Way to Define Your Version
  3. Aligning Versions with GitHub Tags
  4. Keeping Dependencies in Sync
  5. Using bump-my-version for Automated Versioning
  6. Validating Versions in CI/CD
  7. Mistakes to Avoid
  8. Final Checklist
  9. FAQs

Why Versioning is Crucial

Imagine deploying a package and realizing later that the version in setup.py differs from pyproject.toml. 🤦‍️ This breaks automation, confuses users, and complicates debugging.

When you keep versions in sync, you:

  • Ensure smooth CI/CD deployments
  • Reduce version conflicts in dependencies
  • Automate and streamline release workflows

Following best practices prevents the dreaded “version mismatch” error and keeps your project organized.


The Right Way to Define Your Version

A common pitfall is defining the version in multiple places. Instead, define it in a single source of truth.

1️⃣ Store Version in __version__.py

Create a __version__.py file inside your package:

<span># my_package/__version__.py </span><span>__version__</span> <span>=</span> <span>"</span><span>1.2.3</span><span>"</span>
<span># my_package/__version__.py </span><span>__version__</span> <span>=</span> <span>"</span><span>1.2.3</span><span>"</span>
# my_package/__version__.py __version__ = "1.2.3"

Enter fullscreen mode Exit fullscreen mode

2️⃣ Use It in setup.py

Instead of manually entering a version, import it dynamically:

<span>from</span> <span>my_package.__version__</span> <span>import</span> <span>__version__</span>
<span>setup</span><span>(</span>
<span>name</span><span>=</span><span>"</span><span>my_package</span><span>"</span><span>,</span>
<span>version</span><span>=</span><span>__version__</span><span>,</span>
<span>...</span>
<span>)</span>
<span>from</span> <span>my_package.__version__</span> <span>import</span> <span>__version__</span>

<span>setup</span><span>(</span>
    <span>name</span><span>=</span><span>"</span><span>my_package</span><span>"</span><span>,</span>
    <span>version</span><span>=</span><span>__version__</span><span>,</span>
    <span>...</span>
<span>)</span>
from my_package.__version__ import __version__ setup( name="my_package", version=__version__, ... )

Enter fullscreen mode Exit fullscreen mode

3️⃣ Sync with pyproject.toml (for Poetry)

If you’re using Poetry, manually update pyproject.toml:

<span>[tool.poetry]</span>
<span>name</span> <span>=</span> <span>"my-package"</span>
<span>version</span> <span>=</span> <span>"1.2.3"</span>
<span>[tool.poetry]</span>
<span>name</span> <span>=</span> <span>"my-package"</span>
<span>version</span> <span>=</span> <span>"1.2.3"</span>
[tool.poetry] name = "my-package" version = "1.2.3"

Enter fullscreen mode Exit fullscreen mode

Poetry does not support dynamic version imports—so keeping this updated manually (or via automation) is necessary.


Aligning Versions with GitHub Tags

To ensure GitHub releases match your code, follow this release process:

  1. Update the version in __version__.py and pyproject.toml.
  2. Commit the change:
git commit <span>-am</span> <span>"Release version 1.2.3"</span>
   git commit <span>-am</span> <span>"Release version 1.2.3"</span>
git commit -am "Release version 1.2.3"

Enter fullscreen mode Exit fullscreen mode

  1. Create a tag matching the version:
git tag v1.2.3
git push origin main <span>--tags</span>
   git tag v1.2.3
   git push origin main <span>--tags</span>
git tag v1.2.3 git push origin main --tags

Enter fullscreen mode Exit fullscreen mode

  1. Ensure the tag and package version match before deploying.

If the tag and package version don’t match, CI/CD should catch the issue and stop the release.


Keeping Dependencies in Sync

Beyond versioning, managing dependencies properly prevents unexpected failures.

Lock Dependencies in requirements.txt

For reproducible builds, lock dependencies:

pip freeze <span>></span> requirements.txt
pip freeze <span>></span> requirements.txt
pip freeze > requirements.txt

Enter fullscreen mode Exit fullscreen mode

Separate Dev Dependencies

Use a separate file for development dependencies:

pip <span>install</span> <span>-r</span> requirements-dev.txt
pip <span>install</span> <span>-r</span> requirements-dev.txt
pip install -r requirements-dev.txt

Enter fullscreen mode Exit fullscreen mode

Alternatively, if using Poetry, do:

poetry add pytest <span>--dev</span>
poetry add pytest <span>--dev</span>
poetry add pytest --dev

Enter fullscreen mode Exit fullscreen mode

This ensures production installs don’t pull unnecessary dev dependencies.


Using bump-my-version for Automated Versioning

What is bump-my-version?

bump-my-version is the modern replacement for bump2version (which is no longer maintained).

It updates version numbers across all necessary files (e.g., __version__.py, setup.py, pyproject.toml).

How to Install It

pip <span>install </span>bump-my-version
pip <span>install </span>bump-my-version
pip install bump-my-version

Enter fullscreen mode Exit fullscreen mode

How to Use It

Increment version numbers automatically:

bump-my-version patch <span># Updates 1.2.3 → 1.2.4</span>
bump-my-version minor <span># Updates 1.2.3 → 1.3.0</span>
bump-my-version major <span># Updates 1.2.3 → 2.0.0</span>
bump-my-version patch   <span># Updates 1.2.3 → 1.2.4</span>
bump-my-version minor   <span># Updates 1.2.3 → 1.3.0</span>
bump-my-version major   <span># Updates 1.2.3 → 2.0.0</span>
bump-my-version patch # Updates 1.2.3 → 1.2.4 bump-my-version minor # Updates 1.2.3 → 1.3.0 bump-my-version major # Updates 1.2.3 → 2.0.0

Enter fullscreen mode Exit fullscreen mode

This ensures versioning consistency, preventing human errors in updates.


Validating Versions in CI/CD

To prevent mismatched versions between GitHub tags and your package metadata, add a validation step to GitHub Actions.

CI Workflow to Validate Versions

Create .github/workflows/version-check.yml:

<span>name</span><span>:</span> <span>Version Check</span>
<span>on</span><span>:</span>
<span>push</span><span>:</span>
<span>tags</span><span>:</span>
<span>-</span> <span>'</span><span>v*'</span> <span># Runs only on version tags</span>
<span>jobs</span><span>:</span>
<span>check-version</span><span>:</span>
<span>runs-on</span><span>:</span> <span>ubuntu-latest</span>
<span>steps</span><span>:</span>
<span>-</span> <span>uses</span><span>:</span> <span>actions/checkout@v3</span>
<span>-</span> <span>name</span><span>:</span> <span>Validate package version consistency</span>
<span>run</span><span>:</span> <span>|</span>
<span>TAG_VERSION=${GITHUB_REF#refs/tags/v}</span>
<span>PACKAGE_VERSION=$(python -c "import my_package.__version__ as v; print(v.__version__)")</span>
<span>if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then</span>
<span>echo "Version mismatch! GitHub tag is $TAG_VERSION but package version is $PACKAGE_VERSION."</span>
<span>exit 1</span>
<span>fi</span>
<span>name</span><span>:</span> <span>Version Check</span>

<span>on</span><span>:</span>
  <span>push</span><span>:</span>
    <span>tags</span><span>:</span>
      <span>-</span> <span>'</span><span>v*'</span>  <span># Runs only on version tags</span>

<span>jobs</span><span>:</span>
  <span>check-version</span><span>:</span>
    <span>runs-on</span><span>:</span> <span>ubuntu-latest</span>
    <span>steps</span><span>:</span>
      <span>-</span> <span>uses</span><span>:</span> <span>actions/checkout@v3</span>
      <span>-</span> <span>name</span><span>:</span> <span>Validate package version consistency</span>
        <span>run</span><span>:</span> <span>|</span>
          <span>TAG_VERSION=${GITHUB_REF#refs/tags/v}</span>
          <span>PACKAGE_VERSION=$(python -c "import my_package.__version__ as v; print(v.__version__)")</span>

          <span>if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then</span>
            <span>echo "Version mismatch! GitHub tag is $TAG_VERSION but package version is $PACKAGE_VERSION."</span>
            <span>exit 1</span>
          <span>fi</span>
name: Version Check on: push: tags: - 'v*' # Runs only on version tags jobs: check-version: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Validate package version consistency run: | TAG_VERSION=${GITHUB_REF#refs/tags/v} PACKAGE_VERSION=$(python -c "import my_package.__version__ as v; print(v.__version__)") if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then echo "Version mismatch! GitHub tag is $TAG_VERSION but package version is $PACKAGE_VERSION." exit 1 fi

Enter fullscreen mode Exit fullscreen mode

If the versions don’t match, the pipeline will fail, preventing a broken release.


Mistakes to Avoid

Hardcoding Versions in Multiple Files – Instead, use __version__.py

Pushing GitHub Tags Without Updating Files First

Ignoring Dependency Locking (requirements.txt)

Manual Version Updates Instead of Automation (bump-my-version)

Avoid these, and your releases will be smooth!


Final Checklist

Keep version centralized in __version__.py

Always sync pyproject.toml (for Poetry users)

Automate with bump-my-version

Validate version consistency in CI/CD

Lock dependencies for reliable builds


FAQs

1. Why is bump2version no longer recommended?

bump2version is no longer maintained. bump-my-version is the modern alternative with active support.

2. How do I ensure my GitHub release matches my package version?

Use GitHub Actions to verify that the Git tag matches __version__.py before releasing.

3. Should I use setup.py or Poetry?

  • If you use setuptools, update setup.py
  • If you use Poetry, manually update pyproject.toml

4. Do I still need requirements.txt if using Poetry?

No! Poetry manages dependencies internally, so requirements.txt is unnecessary.

5. Is bump-my-version required?

No, but it automates versioning, preventing human mistakes.


Conclusion

Keeping your Python packaging metadata in sync with GitHub release tags prevents deployment issues, enables automation, and ensures smooth releases.

By following best practices like centralized versioning, GitHub Actions validation, and automated version bumps, you’ll create a robust, foolproof versioning system!

Want to take it a step further? Integrate this workflow into your CI/CD pipeline today!

原文链接:How to Keep Your Python Package Metadata in Sync with GitHub Release Tags

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
Real dream is the other shore of reality.
真正的梦就是现实的彼岸
评论 抢沙发

请登录后发表评论

    暂无评论内容