3.8 KiB
Simplified Versioning System
Problem Solved
Previously, the application version had to be manually updated in multiple places:
src/webdrop_bridge/__init__.py- source of truthpyproject.toml- package version.env.example- environment example- Run
scripts/sync_version.py- manual sync step
This was error-prone and tedious.
Solution: Single Source of Truth
The version is now defined only in one place:
# src/webdrop_bridge/__init__.py
__version__ = "1.0.0"
All other components automatically read from this single source.
How It Works
1. pyproject.toml (Automatic)
[tool.setuptools.dynamic]
version = {attr = "webdrop_bridge.__version__"}
[project]
name = "webdrop-bridge"
dynamic = ["version"] # Reads from __init__.py
When you build the package, setuptools automatically extracts the version from __init__.py.
2. config.py (Automatic - with ENV override)
# Lazy import to avoid circular imports
if not os.getenv("APP_VERSION"):
from webdrop_bridge import __version__
app_version = __version__
else:
app_version = os.getenv("APP_VERSION")
The config automatically reads from __init__.py, but can be overridden with the APP_VERSION environment variable if needed.
3. sync_version.py (Simplified)
The script now only handles:
- Updating
__init__.pywith a new version - Updating
CHANGELOG.mdwith a new version header - Optional: updating
.env.exampleif it explicitly setsAPP_VERSION
It no longer needs to manually sync pyproject.toml or config defaults.
Workflow
To Release a New Version
Option 1: Simple (Recommended)
# Edit only one file
# src/webdrop_bridge/__init__.py:
__version__ = "1.1.0" # Change this
# Then run sync script to update changelog
python scripts/sync_version.py
Option 2: Using the Sync Script
python scripts/sync_version.py --version 1.1.0
The script will:
- ✅ Update
__init__.py - ✅ Update
CHANGELOG.md - ✅ (Optional) Update
.env.exampleif it hasAPP_VERSION=
What Happens Automatically
When you run your application:
- Config loads and checks environment for
APP_VERSION - If not set, it imports
__version__from__init__.py - The version is displayed in the UI
- Update checks use the correct version
When you build with pip install:
- setuptools reads
__version__from__init__.py - Package metadata is set automatically
- No manual sync needed
Verification
To verify the version is correctly propagated:
# Check __init__.py
python -c "from webdrop_bridge import __version__; print(__version__)"
# Check config loading
python -c "from webdrop_bridge.config import Config; c = Config.from_env(); print(c.app_version)"
# Check package metadata (after building)
pip show webdrop-bridge
All should show the same version.
Best Practices
- Always edit
__init__.pyfirst - it's the single source of truth - Run
sync_version.pyto update changelog - keeps release notes organized - Use environment variables only for testing - don't hardcode overrides
- Run tests after version changes - config tests verify version loading
Migration Notes
If you had other places where version was defined:
- ❌ Remove version from
pyproject.toml[project]section - ✅ Add
dynamic = ["version"]instead - ❌ Don't manually edit
.env.examplefor version - ✅ Let
sync_version.pyhandle it - ❌ Don't hardcode version in config.py defaults
- ✅ Use lazy import from
__init__.py
Testing the System
Run the config tests to verify everything works:
pytest tests/unit/test_config.py -v
All tests should pass, confirming version loading works correctly.
Result: One place to change, multiple places automatically updated. Simple, clean, professional.