Packaging & pyproject.toml
A Python package is a directory of modules that can be installed, versioned, and shared. Packaging turns your local code into something anyone can install with pip install mypackage. Understanding packaging is essential the moment your project grows beyond a single script or you want to share work with teammates or the public.
Package layout
Section titled “Package layout”A clean src-layout keeps your source isolated from tests and tooling, preventing accidental imports of uninstalled code.
flowchart TD root["mypackage/"] --> src["src/"] src --> pkg["mypackage/"] pkg --> init["__init__.py"] pkg --> core["core.py"] pkg --> utils["utils.py"] root --> tests["tests/"] tests --> conftest["conftest.py"] tests --> testcore["test_core.py"] root --> pyproj["pyproject.toml"] root --> readme["README.md"]
pyproject.toml
Section titled “pyproject.toml”pyproject.toml is the single source of truth for your package. The [build-system] table specifies the build backend, and [project] declares all metadata pip and PyPI need.
[build-system]requires = ["hatchling"]build-backend = "hatchling.build"
[project]name = "mypackage"version = "0.1.0"description = "A short description of mypackage"readme = "README.md"requires-python = ">=3.11"license = { text = "MIT" }authors = []dependencies = [ "httpx>=0.27",]
[project.optional-dependencies]dev = [ "pytest>=8", "mypy>=1.10",]
[project.urls]Homepage = "https://github.com/yourname/mypackage"Source files
Section titled “Source files”The public API is re-exported from __init__.py, keeping the import surface clean.
from mypackage.core import greet
__all__ = ["greet"]Business logic lives in dedicated modules such as core.py.
def greet(name: str) -> str: """Return a greeting string.""" return f"Hello, {name}!"Editable install, building, and publishing
Section titled “Editable install, building, and publishing”During development you want code changes to take effect without reinstalling. The -e flag achieves this. When you are ready to distribute, build creates the artifacts and twine uploads them.
# editable install — changes to src/ take effect immediatelypip install -e ".[dev]"
# build source distribution + wheelpython -m build
# publish to PyPI (requires a PyPI account + token)twine upload dist/*
# for practice, use TestPyPI first:twine upload --repository testpypi dist/*