Вам больше не нужны poetry и pipenv - достаточно лишь pyproject.toml.
Долгое время создание своих Python-пакетов было довольно сложным процессом, требовавшим написания setup.py
. А зависимости прописывались в requirements.txt
. Позже появились утилиты типа pipenv
и poetry
, которые упростили этот процесс. Был предложен формат файла pyproject.toml
, который в конце концов стал официальным.
pyproject.toml
от poetry отличается от формата PEP.
Для управления зависимостями больше не нужны сторонние утилиты типа poetry
, pipenv
, flit
или «официальный» hatch
. pip
давно умеет устанавливать зависимости из это файла, а теперь и утилиты для сборки и публикации пакетов его поддерживают.
Пример pyproject.toml
:
[build-system]
# Тут мы указываем сборщики
# setuptools-scm тут может и не очень нужен, но указан на будущее
requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"
[project]
name = "dummy_project"
authors = [{name = "John Doe", email="john.doe@gmail.com"}]
# Лежат в корне проекта
readme = "README.md"
license = {file = "LICENSE"}
# Требуемая версия python
requires-python = ">=3.11.7"
# См. категории на pypi:
# https://pypi.org/classifiers/
# Для примера укажем категорию к которой принадлежит лицензия
classifiers = [
"License :: OSI Approved :: Apache Software License"
]
# Зависимости пакета, можно указывать версии с помощью операторов == и >=
dependencies = [
"requests",
]
# тут указываются динамические "свойства" пакета
# см. [tool.setuptools.dynamic]
dynamic = ["version"]
# Необязательные зависимости можно установить из корня проекта:
# pip install -e '.[dev]'
# pip install -e '.[test]'
# флаг -e нужен для создания ссылки вместо непосредственной установки (лишнего копирования файлов)
[project.optional-dependencies]
# Зависимости для тестирования
test = [
"pytest",
]
# А это для разработки
dev = [
"black",
"pylint",
]
[project.urls]
# Тут можно указать ссылку на репозиторий на гитхаб
Repository = "https://github.com/user/dummy-project.git"
# Версию пакета можно вытаскивать из кода
[tool.setuptools.dynamic]
version = {attr = "dummy_project.__version__"}
# При установке будут автоматически созданы исполняемые файлы в ~/.local/bin или в /usr/bin
[project.scripts]
# <команда> = <модуль откуда импортируем функцию>:<имя функции>
dummy-project-cli = 'dummy-project.cli:cli'
- https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html
- Исходники должны находиться в текущем каталоге либо папке
src/dummy_project
.
Примерная структура проекта:
.
├── pyproject.toml
├── LICENSE
├── README.md
└── src
└── dummmy_project
├── cli.py
├── __init__.py
└── lib.py
Можно еще набросать что-то простое для проверки CLI:
src/dummy_project/cli.py
:
import argparse
def cli(argv: list[str] | None = None) -> None:
parser = argparse.ArgumentParser()
parser.add_argument('--name', default="World")
args = parser.parse_args(argv)
print(f"Hello, {args.name}!")
Естественно, вместо pipx можно использовать обычный pip. Первый просто автоматически создает виртуальное окружение. Это аналог npx из мира Node.js.
С помощью pipx можно произвести тестовую установку проекта:
pipx install .
Проверим cli:
$ dummy-project-cli --name "Dummy"
Hello, Dummy!
Даже если проект не содержит исполняемых скриптов, использование pipx
предпочтительно. Пример запуска проекта на flask
:
pipx run --pypackages flask run
Для публикации и загрузки на pypi потребуются пакеты build
и twine
:
# Всегда лучше использовать стандартный пакетный менеджер для установки пакетов, содержащих какие-то утилиты (но не надо через него ставить django!!!)
yay -S python-build twine
# В неполноценных дистрах используем тот же pipx
pipx install build
pipx install twine
Выполняем сборку:
pyproject-build
# Если установлено как-то неправильно и не работает pyproject-build, то можно попробовать
python -m build
В результате будет создан каталог dist/
(а еще <project>.egg-info
и тд).
Теперь загружаем проект:
twine upload --skip-existing dist/*
--skip-existing
пропускает загрузку уже загруженных версий.
Чтобы загрузить проект в PyPI, нужно зарегистрироваться на сайте и созданный в профиле api token (кнопка Add API token
) сохранить в ~/.pypirc
:
[pypi]
username = __token__
password = pypi-...
Эти команды можно выполнить вместе:
pyproject-build && twine upload --skip-existing dist/*
Официальная документация: