Publishing Your Project to PyPI๏ƒ

๐Ÿ“ฆ PyPI (Python Package Index) is where you publish Python packages so others can install them with pip install yourproject.

This guide walks you through publishing your project from template-project to PyPI โ€” manually or automatically using GitHub Actions.


๐Ÿ“ Step 1: Prepare Your Project๏ƒ

To publish to PyPI, your project needs:

  • A pyproject.toml file with metadata

  • A README.md, LICENSE, and version number

  • A working __init__.py or version file

This template already includes most of what you need.

You can also follow the official tutorial: ๐Ÿ‘‰ Packaging Projects โ€” Python Packaging User Guide

Choosing a Build Backend๏ƒ

The official Python tutorial uses hatchling, like this:

[build-system]
requires = ["hatchling >= 1.26"]
build-backend = "hatchling.build"

In this template, we use setuptools instead:

[build-system]
build-backend = "setuptools.build_meta"
requires = [
  "setuptools>=42",
  "setuptools-scm[toml]>=3.4",
  "wheel",
]

This setup works well for scientific projects that use version tagging.


๐Ÿ“ Step 2: Edit Your Project Metadata๏ƒ

Update pyproject.toml under the [project] section:

Example from this template:

[project]
name = "template-project-efw"
description = "Example template project for docs, pip install and git"
readme = "README.md"
license = { file = "LICENSE" }
maintainers = [
  { name = "Eleanor Frajka-Williams", email = "eleanorfrajka@gmail.com" },
]
requires-python = ">=3.8"
classifiers = [
  "Programming Language :: Python :: 3 :: Only",
  "Programming Language :: Python :: 3.8",
  "Programming Language :: Python :: 3.9",
  "Programming Language :: Python :: 3.10",
  "Programming Language :: Python :: 3.11",
  "Programming Language :: Python :: 3.12",
]
dynamic = [
  "dependencies",
  "version",
]

[project.urls]
documentation = "https://github.com/eleanorfrajka/template-project"
homepage = "https://github.com/eleanorfrajka/template-project"
repository = "https://github.com/eleanorfrajka/template-project"

๐ŸŽฏ Change the name, description, maintainers, and URLs to match your own project.

Versioning with setuptools_scm๏ƒ

This template uses automatic versioning from git tags. Hereโ€™s the config:

[tool.setuptools_scm]
write_to = "template_project/_version.py"
write_to_template = "__version__ = '{version}'"
tag_regex = "^(?P<prefix>v)?(?P<version>[^\+]+)(?P<suffix>.*)?$"
local_scheme = "no-local-version"

๐Ÿ› ๏ธ Step 3: Build Your Package๏ƒ

Make sure you have the latest build module:

python3 -m pip install --upgrade build

Then from the project root:

python3 -m build

This generates a dist/ folder with .whl and .tar.gz files.


๐Ÿงช Step 4: Test on TestPyPI๏ƒ

Before publishing for real, try everything out on TestPyPI.

  1. Create an account at test.pypi.org/account/register

  2. Create an API token and store it securely

  3. Install or upgrade Twine:

python3 -m pip install --upgrade twine
  1. Upload your package:

python3 -m twine upload --repository testpypi dist/*
  1. Install from TestPyPI:

pip install -i https://test.pypi.org/simple/ --no-deps template-project-efw

โš ๏ธ If you see an error like:

Invalid distribution metadata: unrecognized or malformed field 'license-file'

Update your packaging tools:

pip install --upgrade packaging setuptools

๐Ÿš€ Step 5: Upload to PyPI๏ƒ

When youโ€™re ready to go live:

  1. Create an account at pypi.org

  2. Generate a separate API token

  3. Upload with Twine:

python3 -m twine upload dist/*

๐Ÿค– Optional: Automate Publishing with GitHub Actions๏ƒ

This template includes .github/workflows/pypi.yml, which:

  • Builds your package

  • Publishes to PyPI when you push a release tag (e.g. v0.1.0)

To use it:๏ƒ

  1. Register GitHub as a trusted publisher

  2. Push a tag:

git tag v0.1.0
git push origin v0.1.0
  1. GitHub will run the Action to publish your package.


โœ… Summary๏ƒ

  • Fill in pyproject.toml

  • Build your distribution with python3 -m build

  • Test on TestPyPI, then upload to PyPI

  • Use pypi.yml to automate releases

๐Ÿ“ฆ Now others can pip install your project!