Packaging Python Projects
Packaging lets you distribute your code to others via PyPI or as a wheel file. Modern Python packaging uses pyproject.toml and build backends.
# Project structure for a distributable package
my-library/
โโโ src/
โ โโโ mylibrary/
โ โโโ __init__.py
โ โโโ core.py
โ โโโ utils.py
โโโ tests/
โ โโโ test_core.py
โโโ README.md
โโโ LICENSE
โโโ pyproject.tomlpyproject.toml
# pyproject.toml โ the modern packaging config
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.backends.legacy:build"
[project]
name = "my-awesome-library"
version = "1.0.0"
description = "A library that does awesome things"
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.9"
authors = [
{name = "Your Name", email = "you@example.com"}
]
keywords = ["python", "utilities", "awesome"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
]
dependencies = [
"requests>=2.28.0",
]
[project.optional-dependencies]
dev = ["pytest", "mypy", "black", "ruff"]
[project.urls]
Homepage = "https://github.com/you/my-awesome-library"
Documentation = "https://docs.my-awesome-library.com"
[project.scripts]
my-tool = "mylibrary.cli:main" # Command-line entry pointBuilding and Publishing
# Install build tools
pip install build twine
# Build distribution packages
python -m build
# Creates:
# dist/my_awesome_library-1.0.0-py3-none-any.whl (wheel)
# dist/my_awesome_library-1.0.0.tar.gz (source)
# Test on TestPyPI first (safe!)
twine upload --repository testpypi dist/*
pip install --index-url https://test.pypi.org/simple/ my-awesome-library
# Publish to PyPI (for real)
twine upload dist/*
# After publishing, anyone can install with:
# pip install my-awesome-libraryCode Quality Tools
# The modern Python code quality stack:
# black โ auto-formatter (opinionated, no configuration)
pip install black
black my_module.py # Format file
black . # Format entire project
black --check . # Check without modifying
# ruff โ fast linter (replaces flake8, isort, and more)
pip install ruff
ruff check . # Check for issues
ruff check --fix . # Auto-fix what can be fixed
ruff format . # Format (ruff can also format)
# mypy โ static type checker
pip install mypy
mypy my_module.py # Type check
mypy --strict . # Strict mode
# pre-commit โ run checks before git commit
pip install pre-commit
# .pre-commit-config.yaml:
# repos:
# - repo: https://github.com/psf/black
# - repo: https://github.com/charliermarsh/ruff-pre-commit
# Configure in pyproject.toml
# [tool.black]
# line-length = 88
# target-version = ["py39", "py310", "py311"]
#
# [tool.ruff]
# select = ["E", "F", "I"]
# line-length = 88
#
# [tool.mypy]
# strict = trueSemantic Versioning
Use SemVer: MAJOR.MINOR.PATCH. Increment MAJOR for breaking changes, MINOR for new features (backward compatible), PATCH for bug fixes.
# 1.0.0 โ Initial stable release
# 1.0.1 โ Bug fix (no API changes)
# 1.1.0 โ New feature added (backward compatible)
# 2.0.0 โ Breaking API change
# Keep CHANGELOG.md
# ## [2.0.0] - 2024-01-15
# ### Breaking Changes
# - `old_function()` removed, use `new_function()` instead
#
# ## [1.1.0] - 2024-01-01
# ### Added
# - New `search()` functionKey Takeaways
- pyproject.toml is the standard: replaces setup.py and setup.cfg
- python -m build creates dist files: wheel (.whl) and source (.tar.gz)
- Test on TestPyPI before PyPI
- black + ruff + mypy: the modern Python code quality trio
- SemVer: communicate breaking changes clearly
Practice Exercises
- Take a utility module you've written during this course and package it: write pyproject.toml, README.md, and build it. Don't publish yet, just build locally.
- Set up black and ruff on your project. Run them and fix any issues they find.
- Write a
CHANGELOG.mdfor a hypothetical project showing 3 versions with changes. - Create a command-line entry point in pyproject.toml and test that the command works after installing in a venv.
๐ Course Complete!
You've completed Python Mastery โ all 34 lessons across 10 modules. You've gone from print("Hello, World!") to generators, async/await, type hints, testing, and packaging.
What's Next?
- Build something real: pick a project and apply everything you've learned
- Contribute to open source: find a Python project on GitHub and fix a bug
- Go deeper: SQLAlchemy, FastAPI, Django, NumPy, machine learning
- Read Python source: CPython's source is educational; so are big libraries
- PEP 8: Python's style guide โ know it and follow it