From Zero to One: Building and Publishing a Python Package
By Yangming Li
Introduction
Packaging your Python code is the best way to share, reuse, and distribute your work. This guide walks you through every step of building, testing, documenting, and publishing a modern Python package, following best practices and official recommendations.
1. Project Structure & Initialization
Start with a clean directory layout. The recommended structure is:
my_package/
├── src/
│ └── my_package/
│ ├── __init__.py
│ └── core.py
├── tests/
├── pyproject.toml
├── setup.py # optional but helpful
├── README.md
└── LICENSE
This structure ensures your package is importable, testable, and future-proof.
2. Writing Core Functionality
In core.py
, define your main functions:
def add(a, b):
return a + b
Expose them in __init__.py
:
from .core import add
__all__ = ["add"]
This allows users to import directly: from my_package import add
3. Configuration: setup.py vs pyproject.toml
Modern (recommended):
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
version = "0.1.0"
description = "Example Python package"
readme = "README.md"
requires-python = ">=3.7"
dependencies = []
Legacy (setup.py):
from setuptools import setup, find_packages
setup(
name="my_package",
version="0.1.0",
packages=find_packages("src"),
package_dir={"": "src"},
install_requires=[],
)
Use pyproject.toml
for modern, future-proof packaging.
4. Testing
Add tests in tests/
using pytest
or unittest
:
def test_add():
from my_package import add
assert add(2, 3) == 5
Testing ensures your package works as expected and is essential for CI/CD.
5. Documentation & Licensing
- README.md: Explain installation, usage, and examples.
- LICENSE: Choose a license (MIT, Apache, etc.).
- .gitignore: Ignore build artifacts (
dist/
,*.egg-info/
).
6. Build & Deploy
Install build tools and create a distribution:
pip install wheel build twine
python -m build
Upload to PyPI or TestPyPI:
# Test PyPI
python -m twine upload --repository testpypi dist/*
# Production
python -m twine upload dist/*
Once published, users can install with pip install my-package
.
7. Versioning & Automation
- Use Git and tag-based versioning.
- Maintain a
CHANGELOG.md
. - Set up CI/CD (e.g., GitHub Actions) for linting, testing, building, and publishing.
A simple GitHub Actions workflow for testing and publishing:
# .github/workflows/python-package.yml
name: Python Package
on:
push:
tags:
- 'v*'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest
pip install -e .
- name: Test with pytest
run: pytest
publish:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python -m build
twine upload dist/*
8. Recommended Resources
Conclusion
By following these steps and referencing the official guides, you can confidently create, test, document, and release a Python package from scratch. Happy packaging!
References
- Python Packaging Authority. (2023). Packaging Python Projects. Python Packaging User Guide. https://packaging.python.org/tutorials/packaging-projects/
- Beuzen, T., & Timbers, T. (2022). Python Packages. https://py-pkgs.org/
- pyOpenSci. (2023). Python Packaging Guide. https://pyopensci.org/python-package-guide/
- Hillard, D. (2022). Publishing Python Packages. Manning Publications.
- PyPA. (2023). PEP 518 -- Specifying Minimum Build System Requirements for Python Projects. https://peps.python.org/pep-0518/