Balíčkování Python projektu: pyproject.toml krok za krokem
Jak zabalit Python knihovnu nebo CLI nástroj – src layout, pyproject.toml, build backend, závislosti, vstupní body, wheel a publikace na PyPI.
setup.py je minulost. Moderní Python projekt popisuje jediný soubor pyproject.toml podle standardů PEP 517, 518 a 621. Ukážeme si, jak z několika modulů udělat instalovatelný balíček, který jde nasadit přes pip install a případně publikovat na PyPI.
Struktura projektu
Doporučovaná je tzv. src layout:
prevodnik/
├── pyproject.toml
├── README.md
├── LICENSE
├── src/
│ └── prevodnik/
│ ├── __init__.py
│ ├── jednotky.py
│ └── cli.py
└── tests/
└── test_jednotky.py
Proč src/? Testy pak nemohou omylem importovat kód z pracovní složky místo nainstalovaného balíčku. Chyby typu „u mě to funguje, po instalaci chybí soubor“ se objeví hned.
Minimální pyproject.toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "prevodnik"
version = "0.1.0"
description = "Převody jednotek z příkazové řádky"
readme = "README.md"
requires-python = ">=3.10"
license = "MIT"
authors = [{ name = "Jan Novák", email = "[email protected]" }]
dependencies = [
"typer>=0.12",
]
[project.optional-dependencies]
dev = ["pytest>=8", "mypy"]
[project.scripts]
prevodnik = "prevodnik.cli:app"
[project.urls]
Homepage = "https://github.com/jannovak/prevodnik"
Sekce po sekcích
[build-system]říká, čím se balíček sestaví. Hatchling je jednoduchý a rozumně výchozí. Alternativy:setuptools>=61(backendsetuptools.build_meta),flit_core,pdm-backend,uv_build. Hatchling i setuptools layoutsrc/najdou automaticky.[project]jsou standardizovaná metadata (PEP 621) – stejná pro všechny backendy.license = "MIT"jako SPDX výraz je novější forma (PEP 639). Starší verze backendů vyžadují tabulkulicense = { text = "MIT" }– pokud build hlásí chybu, aktualizujte backend nebo použijte starší zápis.dependenciesjsou závislosti potřebné za běhu.optional-dependenciesjsou volitelné skupiny, instalují se jakopip install "prevodnik[dev]".[project.scripts]vytvoří po instalaci spustitelný příkazprevodnik, který zavolá objektappz moduluprevodnik.cli.
Jak psát závislosti
dependencies = [
"httpx>=0.27,<1",
"pydantic>=2.5",
"tomli>=2; python_version < '3.11'",
]
U knihovny zadávejte co nejvolnější rozsahy – spodní hranici, kterou opravdu potřebujete. Přesné verze (==) by kolidovaly s jinými balíčky v prostředí uživatele.
U aplikace, kterou nasazujete, přesné verze patří do zamykacího souboru (uv.lock, requirements.txt z pip-compile), ne do pyproject.toml.
Poslední řádek ukazuje environment marker: tomli se nainstaluje jen na Pythonu starším než 3.11, kde chybí vestavěný tomllib.
Verze na jednom místě
Chcete číst verzi za běhu? Nepište ji do kódu podruhé:
# src/prevodnik/__init__.py
from importlib.metadata import version
__version__ = version("prevodnik")
Vývojová instalace
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
-e (editable) znamená, že změny v src/ se projeví hned bez reinstalace. Příkaz prevodnik už funguje v aktivním prostředí.
S uv:
uv sync --extra dev
uv run prevodnik --help
Konfigurace nástrojů
Do pyproject.toml patří i nastavení většiny vývojových nástrojů:
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.ruff]
line-length = 100
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B"]
[tool.mypy]
strict = true
Sestavení
pip install build
python -m build
Ve složce dist/ vzniknou dva soubory:
prevodnik-0.1.0.tar.gz– zdrojová distribuce (sdist),prevodnik-0.1.0-py3-none-any.whl– wheel, hotový k instalaci.
Před publikací ověřte, co ve wheelu skutečně je:
unzip -l dist/prevodnik-0.1.0-py3-none-any.whl
pip install dist/prevodnik-0.1.0-py3-none-any.whl # do čistého venv
Datové soubory (šablony, JSON) uvnitř balíčku čtěte přes importlib.resources.files("prevodnik") / "data.json", ne přes relativní cesty k __file__.
Publikace na PyPI
- Vytvořte si účet na test.pypi.org a pypi.org, zapněte 2FA a vygenerujte API token.
- Ověřte, že jméno balíčku je volné.
- Nahrajte nejdřív na TestPyPI:
pip install twine
twine check dist/*
twine upload --repository testpypi dist/*
pip install --index-url https://test.pypi.org/simple/ prevodnik
- Když je vše v pořádku,
twine upload dist/*.
Pro automatické publikování z GitHub Actions doporučuje PyPI tzv. Trusted Publishing (OIDC) – v CI pak nemusíte ukládat žádný token.
Alternativně: uv build a uv publish dělají totéž bez dalších nástrojů.
Časté chyby
ModuleNotFoundErrorpo instalaci – modul není uvnitř balíčku vesrc/nebo chybí__init__.py.- Nahrání stejné verze podruhé – PyPI to odmítne. Každá publikace potřebuje nové číslo verze a smazanou verzi nelze znovu použít.
- Zapomenutý README v sdistu –
readmev[project]musí ukazovat na existující soubor.
Pokud máte projekt na GitHubu a chcete ho převést ze setup.py na pyproject.toml, můžete ho naimportovat do Projektu v ColdHost AI, nechat úpravu navrhnout a výsledek poslat zpět jako pull request ke kontrole.