PyPI Publishing Setup Guide¶
Complete guide to setting up automated PyPI publishing for the MSN Weather Wrapper package.
Overview¶
The project uses GitHub's trusted publishing (OIDC) for secure PyPI uploads with no stored secrets. The first release requires manual setup, but subsequent releases are fully automated.
Quick Setup (First Release)¶
Step 1: Create PyPI Account¶
- Go to PyPI.org
- Register a new account
- Verify your email address
Step 2: Upload First Release Manually¶
The first release must be uploaded manually to claim the package name on PyPI.
# Install build tools
pip install build twine
# Build package
python -m build
# Upload to PyPI (interactive)
python -m twine upload dist/*
You'll be prompted for your PyPI username and password.
Step 3: Configure Trusted Publishing (OIDC)¶
After the first manual upload:
- Go to PyPI Account Settings
- Scroll to Publishing section
- Click Add a new pending publisher
- Configure:
- PyPI Project Name:
msn-weather-wrapper - Owner: Your GitHub username
- Repository name:
msn-weather-wrapper - Workflow name:
publish-release.yml - Environment name: Leave blank (or use
pypi) - Click Add
IMPORTANT: The pending publisher must be confirmed from PyPI before the first automated release!
Step 4: Verify in GitHub¶
Your repository is now configured for trusted publishing. No token storage needed!
Automated Publishing Workflow¶
Once OIDC is configured, releases are fully automatic:
- Developer creates PR with changes
- PR merged to main
- auto-version-release.yml triggers:
- Determines version bump
- Creates and merges version bump PR
- Pushes version tag
- publish-release.yml triggers on tag:
- Uses OIDC to authenticate to PyPI
- Builds Python package
- Publishes to PyPI
- Creates GitHub Release
- Package available on PyPI ✅
Version Management¶
Conventional Commits¶
Use conventional commit prefixes in PR titles for automatic version bumping:
| Prefix | Type | Bump | Example |
|---|---|---|---|
feat: |
New Feature | Minor (0.X.0) | feat: add weather alerts |
fix: |
Bug Fix | Patch (0.0.X) | fix: correct temp parsing |
feat!: |
Breaking Feature | Major (X.0.0) | feat!: redesign API |
fix!: |
Breaking Fix | Major (X.0.0) | fix!: change response format |
docs: |
Documentation | Patch (0.0.X) | docs: update README |
chore: |
Maintenance | Patch (0.0.X) | chore: update deps |
Default: Patch version (0.0.X)
Testing Before Release¶
Test Locally¶
# Build the package
python -m build
# Verify package integrity
python -m twine check dist/*
# Optional: Test on TestPyPI first
python -m twine upload --repository testpypi dist/*
Verify Package Metadata¶
# Check what will be published
tar -tzf dist/*.tar.gz | head -20
# Verify wheel contents
unzip -l dist/*.whl | head -20
Troubleshooting¶
OIDC Configuration Issues¶
Problem: Pending publisher not confirmed
Solution:
- Go to PyPI Account Settings
- Look for pending publishers
- Click the pending publisher
- Click Confirm to activate it
Problem: First automated release fails with auth error
Solution:
- Ensure OIDC pending publisher is confirmed (not just added)
- Wait a few minutes after confirming for caching to update
- Check
publish-release.ymllogs for specific error
Package Upload Issues¶
Problem: Version already exists on PyPI
Solution:
- Versions are immutable on PyPI
- Create a new version bump (auto-version handles this)
- Cannot override or delete existing versions
Problem: Package name already taken
Solution:
- Update
project.nameinpyproject.toml - Ensure uniqueness on PyPI
- Re-test with TestPyPI first
Version Tag Issues¶
Problem: Tag not created automatically
Solution:
- Check
auto-version-release.ymllogs - Verify version bump PR was merged
- Manually create tag if needed:
Manual Release Process¶
If automated release fails, you can manually publish:
# Build package
python -m build
# Get OIDC token (if using trusted publishing)
# This is handled automatically by the workflow
# For manual releases, use password/token auth
# Upload to PyPI
python -m twine upload dist/*
# Create GitHub release manually
gh release create v1.2.3 --title "Release v1.2.3" dist/*
Security Best Practices¶
✅ Do¶
- Use GitHub OIDC trusted publishing (no tokens stored)
- Keep
pyproject.tomlversion synchronized with git tags - Review
publish-release.ymllogs for each release - Test on TestPyPI before first production release
- Use conventional commits for clear version history
❌ Don't¶
- Never store PyPI tokens in GitHub secrets
- Never manually bump versions (let automation handle it)
- Never release without running full CI/CD pipeline
- Never use the same version twice
Useful Commands¶
# Check current package version
grep '^version' pyproject.toml
# Build package locally
python -m build
# Check package contents
tar -tzf dist/*.tar.gz
unzip -l dist/*.whl
# Verify metadata
python -m twine check dist/*
# Upload to TestPyPI
python -m twine upload --repository testpypi dist/*
# Upload to PyPI
python -m twine upload dist/*
# List releases
gh release list
# Check publish workflow runs
gh run list --workflow publish-release.yml
Additional Resources¶
- PyPI Documentation
- Trusted Publishing Guide
- Python Packaging Guide
- setuptools Documentation
- twine Documentation
Related Documentation¶
- CI/CD Workflows - Complete workflow documentation
- Versioning Guide - Version management process
- Development Guide - Local development setup