# poetryでPyPIにPublishする

Date: 2023-11-01
URL: https://s.conao3.com/blog/2023/7c1a85
Author: conao3 (Naoya Yamashita)

# はじめに

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

# プロジェクト作成

ライブラリなので、他のプロジェクトにimportして便利に使えるような機能を考える。
今回はClojureの[->>(thread-last)](https://clojuredocs.org/clojure.core/-%3E%3E)を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
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` に保存する。
(型は諦めました。誰か強い人教えて下さい)

```python
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です。
(`--build` は `poetry 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](https://pypi.org/project/thread-last/)

# 使ってみる

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

# Appendix

-   なぜ `src` というフォルダを掘るのか: [Good Integration Practices](https://docs.pytest.org/en/7.1.x/explanation/goodpractices.html)
