LINUX.ORG.RU

Создание пакетов для Python-приложений с помощью pyproject.toml

 ,

Создание пакетов для Python-приложений с помощью pyproject.toml

3

1

Вам больше не нужны 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'

Примерная структура проекта:

.
├── 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/*

Официальная документация:

★★

Проверено: hobbit ()
Последнее исправление: rtxtxtrx (всего исправлений: 11)
Ответ на: комментарий от rtxtxtrx

Не вполне ясно конечно чем плохо просто создать venv и там «нормально» поставить, но ладно.

А pip научился pyproject понимать тоже?

michwill ★★★★★
()

Чуток подправил, завтра планирую подтвердить.

hobbit ★★★★★
()

А PyProject поддерживает интеграцию с пакетными менеджерами для других ЯП? Пример цепочки: C++ библиотека, которая собирается через conan (ну или Rust + cargo), python-обертка над библиотекой, которая использует плюсовый пакет как зависимость, и python-приложение, которое использует обертку.

maxis11
()
Ответ на: комментарий от maxis11

Ну сошки всякие и бинарники можно засунуть:

[tool.setuptools.package-data]
'src' = ['*.so']

Как и любые другие файлы.

rtxtxtrx ★★
() автор топика
Последнее исправление: rtxtxtrx (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.