PyPI Release (Maintainers Only)
This document goes through the steps necessary to upload a release to PyPI. It is assumed that the project is in an installable state, and is ready to be uploaded. This should normally be done as part of the release workflow, but may be done separately.
() Pre-flight checks
1.a) Ensure a clean git tree
If the following prints anything, fix it before continuing:
git status --porcelain
1.b) Read the version number
The canonical version is in pyproject.toml.
VERSION="$(python - <<'PY'
import tomllib
with open("pyproject.toml", "rb") as f:
print(tomllib.load(f)["project"]["version"])
PY
)"
echo "Preparing to publish version: ${VERSION}"
2) Ensure Fresh Build Artifacts
Remove any old build outputs:
rm -fr dist/ build/ *.egg-info
3) Build Distribution
uv run python -m build
This should create the following files:
dist/buffaloexample-${VERSION}*.whldist/buffaloexample-${VERSION}.tar.gz
4) Test Distribution
Use twine, version 6.1 or higher, to check these files
uv run twine check dist/*
If this fails, inspect the wheel metadata:
python - <<'PY'
import zipfile, glob
whl = glob.glob("dist/*.whl")[0]
with zipfile.ZipFile(whl) as z:
meta = [n for n in z.namelist() if n.endswith(".dist-info/METADATA")][0]
print(z.read(meta).decode("utf-8", errors="replace")[:400])
PY
5) Upload Release
Caution: Do not put the credentials used to authenticate to PyPI into the command line (shell history) or commit them to the project repository.
You can either use shell variables that are integrated into your shell session, password manager integration, or some other secure mechanism, or you can use the ~/.pypirc file to store them.
Use twine to upload the release.
5.a) Upload to TestPyPI (Recommended)
To check that the release is good and check that it installs, try it on TestPyPI first
uv run twine upload --repository testpypi dist/*
5.b) Upload to PyPI
Once the release has been confirmed to work, upload it to PyPI
uv run twine upload dist/*
6) Installation Test
To ensure that the package is available, run the following test based on where the release was published.
These are example methods for testing if the installation was successful. Modify these as needed for the specific needs of the project.
6.a) If published to PyPI
To check for a Python library:
python -m venv /tmp/pypi-venv
source /tmp/pypi-venv/bin/activate
pip install "BuffaloExample==${VERSION}"
python -c "import buffaloexample; print('import OK')"
Then to check for an application (still in the virtual environment):
command -v hello-world
6.b) If published to TestPyPI
To check for a Python library:
python -m venv /tmp/testpypi-venv
source /tmp/testpypi-venv/bin/activate
pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple "BuffaloExample==${VERSION}"
python -c "import buffaloexample; print('import OK')"
Then to check for an application (still in the virtual environment):
command -v hello-world
7) If Error With Package
If there is an error with the package after uploading to PyPI, then you have to bump the version on the next attempt after the problem has been fixed. You cannot re-upload the same version.