Conao3 Note

poetryでPyPIにPublishする


はじめに

2023年のPython環境構築: pyenv + poetryを書いた当時はPyPIにライブラリを公開することがほとんどなかったので、publishについては意図的に省いていた。 最近やってみると予想外に簡単だったので小物をどんどん公開するようにしている。この記事では私のいつものフローについて解説する。

プロジェクト作成

ライブラリなので、他のプロジェクトにimportして便利に使えるような機能を考える。 今回はClojureの ->>(thread-last) をPythonで実装して公開するライブラリを作ってみることにした。

mkdir python-thread-last
cd python-thread-last
poetry init

poetry init のプロンプトは以下の通り。 もし私の様にフォルダ名に python- という接頭辞を付けたなら Package name のところで python- という接頭辞を削ること。

This command will guide you through creating your pyproject.toml config.
Package name [python-thread-last]: thread-last
Version [0.1.0]:
Description []: thread-last for Python
Author [Naoya Yamashita <conao3@gmail.com>, n to skip]:
License []: Apache-2.0
Compatible Python versions [^3.11]: ^3.12
Would you like to define your main dependencies interactively? (yes/no) [yes]
You can specify a package in the following forms:
- A single name (requests): this will search for matches on PyPI
- A name and a constraint (requests@^2.23.0)
- A git url (git+https://github.com/python-poetry/poetry.git)
- A git url with a revision (git+https://github.com/python-poetry/poetry.git#develop)
- A file path (../my-package/my-package.whl)
- A directory (../my-package/)
- A url (https://example.com/packages/my-package-0.1.0.tar.gz)
Package to add or search for (leave blank to skip):
Would you like to define your development dependencies interactively? (yes/no) [yes]
Package to add or search for (leave blank to skip):
Generated file
[tool.poetry]
name = "thread-last"
version = "0.1.0"
description = "thread-last for Python"
authors = ["Naoya Yamashita <conao3@gmail.com>"]
license = "Apache-2.0"
readme = "README.md"
packages = [{include = "thread_last"}]
[tool.poetry.dependencies]
python = "^3.12"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Do you confirm generation? (yes/no) [yes]

おまじないファイル作成

おまじない的に必要なファイル群を作成する。 もし私の様に - が含まれるパッケージ名にした場合は _ に置換してフォルダを作成する。

mkdir -p src/thread_last
touch src/thread_last/__init__.py
touch src/thread_last/lib.py
echo '# python-thread-last' >> README.md
curl https://www.apache.org/licenses/LICENSE-2.0.txt > LICENSE
echo '.venv' >> .gitignore
echo '__pycache__' >> .gitignore
echo 'dist' >> .gitignore

pyproject.tomlの編集

これで poetry install ができる。。はずなのだが、 src というフォルダを掘っているせいでpyproject.tomlと整合性が合わなくなっているので修正する。

diff --git a/pyproject.toml b/pyproject.toml
index f70b45c..a1e31ba 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ description = "thread-last for Python"
authors = ["Naoya Yamashita <conao3@gmail.com>"]
license = "Apache-2.0"
readme = "README.md"
-packages = [{include = "thread_last"}]
+packages = [{include = "src/thread_last"}]
[tool.poetry.dependencies]
python = "^3.12

poetry install

poetry install でvenvの作成、インストールを一発でやってくれる。 プロジェクトに問題がなければ成功するはず。

$ poetry install
The currently activated Python version 3.11.2 is not supported by the project (^3.12).
Trying to find and use a compatible version.
Using python3 (3.12.0)
Creating virtualenv thread-last in /home/conao/dev/repos/python-thread-last/.venv
Installing dependencies from lock file
Installing the current project: thread-last (0.1.0)

実装

以下の内容を src/thread_last/lib.py に保存する。 (型は諦めました。誰か強い人教えて下さい)

import functools
from typing import Any, Callable
def thread_last(x: Any, *fns: Callable[[Any], Any]) -> Any:
return functools.reduce(lambda v, f: f(v), fns, x)

publish

いよいよpublishです。 (--buildpoetry build をpublishの直前に実行してくれるオプション)

poetry publish --build

表示は以下の通り。

Building thread-last (0.1.0)
- Building sdist
- Built thread_last-0.1.0.tar.gz
- Building wheel
- Built thread_last-0.1.0-py3-none-any.whl
Publishing thread-last (0.1.0) to PyPI
- Uploading thread_last-0.1.0-py3-none-any.whl 100%
- Uploading thread_last-0.1.0.tar.gz 100%

公開できた。thread-last - PyPI

使ってみる

時間切れ。また後で追記します。

Appendix