This document describes the process for building, signing, and publishing TechCompressor releases to PyPI and GitHub Releases.
# Install build tools
pip install --upgrade pip
pip install build twine
# Optional: Install signing tools
# gpg --version # Verify GPG installed-
PyPI Account: https://pypi.org/account/register/
-
PyPI API Token: https://pypi.org/manage/account/token/
- Scope: Entire account or specific to techcompressor project
- Store in
~/.pypirc(see below)
-
GitHub Personal Access Token: https://github.com/settings/tokens
- Scope:
repo(full repository access) - For creating releases via API
- Scope:
Create or edit ~/.pypirc:
[distutils]
index-servers =
pypi
testpypi
[pypi]
username = __token__
password = pypi-AgE... # Your PyPI API token
[testpypi]
username = __token__
password = pypi-AgE... # Your TestPyPI API token (for testing)Security: Set appropriate permissions:
chmod 600 ~/.pypircBefore building release artifacts:
- Update version in
techcompressor/__init__.py - Update version in
pyproject.toml - Verify both match:
grep -r "1.0.0" techcompressor/__init__.py pyproject.toml
- Update
CHANGELOG.mdwith release notes - Update
RELEASE_NOTES.mdwith highlights - Verify
README.mdis current - Check all docs in
docs/are up-to-date
- Run full test suite:
pytest - Run smoke tests:
pytest tests/test_release_smoke.py - Check test coverage:
pytest --cov=techcompressor --cov-report=term-missing - Run benchmark:
python bench.py --quick - Verify no TODOs or FIXME comments:
grep -r "TODO\|FIXME" techcompressor/
- Verify
requirements.txtis current - Check for security vulnerabilities:
pip-audit(optional) - Test with minimum dependency versions
- Test with latest dependency versions
# Remove build artifacts
rm -rf dist/ build/ *.egg-info
# Remove Python cache
find . -type d -name __pycache__ -exec rm -rf {} +
find . -type f -name "*.pyc" -delete
# Check git status
git status # Should be clean (no uncommitted changes)# Build wheel and source distribution
python -m build
# Output will be in dist/:
# - techcompressor-1.0.0-py3-none-any.whl (wheel)
# - techcompressor-1.0.0.tar.gz (source distribution)# Check package contents
tar -tzf dist/techcompressor-1.0.0.tar.gz
unzip -l dist/techcompressor-1.0.0-py3-none-any.whl
# Verify metadata
twine check dist/*
# Output should be:
# Checking dist/techcompressor-1.0.0-py3-none-any.whl: PASSED
# Checking dist/techcompressor-1.0.0.tar.gz: PASSED# Create clean virtual environment
python -m venv test_env
source test_env/bin/activate # On Windows: test_env\Scripts\activate
# Install from built wheel
pip install dist/techcompressor-1.0.0-py3-none-any.whl
# Test installation
python -c "import techcompressor; print(techcompressor.__version__)"
techcompressor --version
pytest # Run tests
# Cleanup
deactivate
rm -rf test_env# Sign distribution files
gpg --detach-sign -a dist/techcompressor-1.0.0.tar.gz
gpg --detach-sign -a dist/techcompressor-1.0.0-py3-none-any.whl
# Verify signatures
gpg --verify dist/techcompressor-1.0.0.tar.gz.asc dist/techcompressor-1.0.0.tar.gz
gpg --verify dist/techcompressor-1.0.0-py3-none-any.whl.asc dist/techcompressor-1.0.0-py3-none-any.whl# Export public key
gpg --armor --export your-email@example.com > techcompressor-signing-key.asc
# Upload to keyserver (optional)
gpg --send-keys YOUR_KEY_IDBefore publishing to production PyPI, test with TestPyPI:
# Upload to test repository
twine upload --repository testpypi dist/*
# Or with explicit URL
twine upload --repository-url https://test.pypi.org/legacy/ dist/*# Create clean environment
python -m venv test_testpypi
source test_testpypi/bin/activate
# Install from TestPyPI
pip install --index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
techcompressor
# Test
python -c "import techcompressor; print(techcompressor.__version__)"
techcompressor --version
# Cleanup
deactivate
rm -rf test_testpypi- All tests pass
- Version is correct
- CHANGELOG is updated
- TestPyPI installation works
- No uncommitted changes in git
# Create annotated tag
git tag -a v1.0.0 -m "Release v1.0.0"
# Verify tag
git tag -l v1.0.0
git show v1.0.0
# Push tag to GitHub
git push origin v1.0.0# Upload to production PyPI
twine upload dist/*
# Output:
# Uploading distributions to https://upload.pypi.org/legacy/
# Uploading techcompressor-1.0.0-py3-none-any.whl
# Uploading techcompressor-1.0.0.tar.gz# Check PyPI page
# https://pypi.org/project/techcompressor/1.0.0/
# Test installation
pip install techcompressor==1.0.0
# Verify
python -c "import techcompressor; print(techcompressor.__version__)"- Go to: https://github.com/DevaanshPathak/TechCompressor/releases/new
- Tag: Select
v1.0.0(created earlier) - Title:
TechCompressor v1.0.0 - Description: Copy from
RELEASE_NOTES.md
Upload to the release:
techcompressor-1.0.0-py3-none-any.whltechcompressor-1.0.0.tar.gztechcompressor-1.0.0.tar.gz.asc(signature, if created)techcompressor-1.0.0-py3-none-any.whl.asc(signature, if created)
- Check "Set as the latest release"
- Uncheck "This is a pre-release" (unless beta)
- Click Publish release
# Install GitHub CLI: https://cli.github.com/
# Create release
gh release create v1.0.0 \
--title "TechCompressor v1.0.0" \
--notes-file RELEASE_NOTES.md \
dist/techcompressor-1.0.0-py3-none-any.whl \
dist/techcompressor-1.0.0.tar.gz
# Or interactive
gh release create v1.0.0 --generate-notes# Fresh install
pip install --upgrade techcompressor
# Test
techcompressor --version
techcompressor --benchmark
techcompressor-gui # Verify GUI launches- Update README badges (version, downloads, etc.)
- Update documentation sites (if applicable)
- Announce release in GitHub Discussions
Example tweet/post:
🎉 TechCompressor v1.0.0 is now available!
Multi-algorithm compression (LZW, Huffman, DEFLATE)
🔒 AES-256-GCM encryption
📦 Custom archive format
💻 CLI & GUI interfaces
🧪 137 passing tests
pip install techcompressor
Docs: https://github.com/DevaanshPathak/TechCompressor
#Python #Compression #OpenSource
- Watch for installation issues
- Monitor PyPI download stats
- Check GitHub issues/discussions
For urgent bug fixes (e.g., v1.0.1):
# 1. Fix bug on main branch
# 2. Update version to 1.0.1
# 3. Run smoke tests
pytest tests/test_release_smoke.py
# 4. Build and publish
rm -rf dist/
python -m build
twine check dist/*
twine upload dist/*
# 5. Tag and release
git tag -a v1.0.1 -m "Hotfix v1.0.1: Fix XYZ"
git push origin v1.0.1
gh release create v1.0.1 --notes "Hotfix for XYZ issue" dist/*# Clean everything
rm -rf dist/ build/ *.egg-info
find . -type d -name __pycache__ -exec rm -rf {} +
# Reinstall build tools
pip install --upgrade build twine
# Retry
python -m build# Check credentials
cat ~/.pypirc
# Check network
curl https://upload.pypi.org/legacy/
# Verbose mode
twine upload --verbose dist/*Cannot delete or replace on PyPI!
Options:
- Publish hotfix version (e.g., 1.0.1)
- Mark version as "yanked" on PyPI (prevents new installs, allows existing)
- Contact PyPI support for special cases
- Never commit
~/.pypircto git - Use API tokens, not passwords
- Rotate tokens periodically
- Use different tokens for TestPyPI and PyPI
- Check file hashes after upload
- Verify signatures
- Test installation from PyPI immediately
- Document who published (maintainer name)
- Keep build logs
- Archive signed artifacts
Publishing is done manually following the steps above. This ensures careful validation and control over each release. TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} run: twine upload dist/*
## References
- PyPI Packaging Guide: https://packaging.python.org/
- Twine Documentation: https://twine.readthedocs.io/
- GitHub Releases: https://docs.github.com/en/repositories/releasing-projects-on-github
- PEP 440 (Versioning): https://peps.python.org/pep-0440/
---
**Last Updated**: October 25, 2025
**Document Version**: 1.0