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
- Why Versioning is Crucial
- The Right Way to Define Your Version
- Aligning Versions with GitHub Tags
- Keeping Dependencies in Sync
-
Using
bump-my-version
for Automated Versioning - Validating Versions in CI/CD
- Mistakes to Avoid
- Final Checklist
- 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:
# my_package/__version__.py
__version__ = "1.2.3"
2οΈβ£ Use It in setup.py
Instead of manually entering a version, import it dynamically:
from my_package.__version__ import __version__
setup(
name="my_package",
version=__version__,
...
)
3οΈβ£ Sync with pyproject.toml
(for Poetry)
If you're using Poetry, manually update pyproject.toml
:
[tool.poetry]
name = "my-package"
version = "1.2.3"
π 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:
-
Update the version in
__version__.py
andpyproject.toml
. - Commit the change:
git commit -am "Release version 1.2.3"
- Create a tag matching the version:
git tag v1.2.3
git push origin main --tags
- 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 > requirements.txt
Separate Dev Dependencies
Use a separate file for development dependencies:
pip install -r requirements-dev.txt
Alternatively, if using Poetry, do:
poetry add pytest --dev
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 install bump-my-version
How to Use It
Increment version numbers automatically:
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
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
:
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
β 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! π
Top comments (0)