とことんDevOps | 日本仮想化技術のDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けする「とことんDevOps」では、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果、TipsなどDevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、コンテナ開発、IaCなど
読者登録と各種SNSのフォローもよろしくお願いいたします。

知識がpip freezeのまま止まっていたのでpoetryの便利さを知らなかった人の話

FastAPIを使ったAPIサーバーを構築することになり、久々にPythonをしっかり触ることになりそうなので、古い知識のアップデートついでに調べたことを備忘録としてまとめました。
古い知識の1つにpipを使ったパッケージ管理があります。
Pythonを使い始めた当時にパッケージ管理を調べていたらpip freezeを使ったやり方をよく見かけていたので、その記憶をアップデートすることなくそのまま使っていました。

当時は、Hello Worldに毛が生えたくらいのプログラムしか書いていなかったのでそこまで気にならなかったのですが、本格的にプログラムを書くようになってくるとあれこれパッケージをたくさん使用するようになります。
それと合わせて自分のローカルマシン上だけの開発に留まらず、仮想化やCI/CDなどその先に向けた準備として再現性ある環境作りを行いながらメンテナンス性も重視していく必要があります。

しかし、pip freezeを実行して出力した内容を改めて眺めてみるとpip install時に指定したパッケージ以外にも関連するパッケージも表示されてしまいます。
個人的には、親パッケージ以外が一覧上に表示されると読みにくさがあるので、どうしても好きになれないですし、削除する際にどれを削除したらいいのかを特定するのが一手間かかります。

その時にあれこれ調べていたらpoetryというツールを見つけたので触ってみたところ、npmと使い勝手が似ているので違和感なく使うことができました。

github.com

pipを使っていた時のやり方を前半で書いて、後半にpoetryの使い方を紹介しようと思います。

pipではどうやってたの?

よく入門書とかブログを見ていたらよく見かけるやり方と思うのですが、このような感じでやっていました。

pip install <パッケージ名>
pip freeze > requirements.txt
pip install -r requirements.txt

pip installで使いたいパッケージをあれこれ適当にインストールします。仮想化技術などを使用して環境を立ち上げたり、潰したりしたい時は一括でインストールできるように情報をまとめる必要があるので、pip freezeコマンドを実行してインストールしたパッケージ情報を出力します。

試しにfastapi[all]をインストールしたときのイメージがこんな感じです。
依存関係が全て見えているような感じになります。

anyio==3.7.1
certifi==2023.7.22
click==8.1.6
dnspython==2.4.1
email-validator==2.0.0.post2
fastapi==0.100.1
h11==0.14.0
httpcore==0.17.3
httptools==0.6.0
httpx==0.24.1
idna==3.4
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.3
orjson==3.9.2
pydantic==2.1.1
pydantic-extra-types==2.0.0
pydantic-settings==2.0.2
pydantic_core==2.4.0
python-dotenv==1.0.0
python-multipart==0.0.6
PyYAML==6.0.1
sniffio==1.3.0
starlette==0.27.0
typing_extensions==4.7.1
ujson==5.8.0
uvicorn==0.23.2
uvloop==0.17.0
watchfiles==0.19.0
websockets==11.0.3

環境を新しく立ち上げるときにpip installにオプションで-r requirements.txtを付け加えて、先ほど出力したファイルを指定することでまとめてインストールすることができます。

詳しい仕組みまでは調べていないのですが、子の依存関係まで出力されているのでパッと親となるパッケージが判別しにくくなっているのかなと思います。

poetryではどうやるの?

使用するOSなどによってやり方は異なりますが、今回はLinux系の手順を例に書いていきます。

インストールは

curl -sSL https://install.python-poetry.org | python3 -

を実行して行います。
インストール場所やバージョンを指定したい場合は、変数を設定することで変更することができます。
よく使いそうな変数に絞って記載しています。

変数名 説明
POETRY_HOME インストール先のディレクトリを変更する
POETRY_VERSION インストールするバージョンを指定する

インストールが完了したら、poetry --versionなどのコマンドを実行して動作確認します。

初めて使う最初のみ次のコマンドを実行します。

poetry init

するとpyproject.tomlというファイルが作成されます。これはnpmでいうpackagae.jsonのようなものです。

パッケージをインストールする際は、poetry add <パッケージ名>を実行して、新しく環境を立ち上げ直す際などにpoetry installを実行するとまとめてインストールしてくれます。

pyproject.tomlに依存関係の情報がまとめられますが、このような感じでインストール時に指定したパッケージのみが表示されているのでわかりやすくなりました。

・・・
[tool.poetry.dependencies]
python = "^3.11"
fastapi = {extras = ["all"], version = "^0.100.1"}
・・・

それ以外にも依存関係のツリーをみようとしたら

poetry show fastapi --tree

を実行するだけで表示することもできます。

fastapi 0.100.1 FastAPI framework, high performance, easy to learn, fast to code, ready for production
├── email-validator >=2.0.0
│   ├── dnspython >=2.0.0 
│   └── idna >=2.0.0 
├── httpx >=0.23.0
│   ├── certifi * 
│   ├── httpcore >=0.15.0,<0.18.0 
│   │   ├── anyio >=3.0,<5.0 
│   │   │   ├── idna >=2.8 
│   │   │   └── sniffio >=1.1 
│   │   ├── certifi * (circular dependency aborted here)
│   │   ├── h11 >=0.13,<0.15 
│   │   └── sniffio ==1.* (circular dependency aborted here)
│   ├── idna * (circular dependency aborted here)
│   └── sniffio * (circular dependency aborted here)
├── itsdangerous >=1.1.0
├── jinja2 >=2.11.2
・・・(長いので途中まで)・・・

記憶が確かであればpipコマンドは標準ではサポートしておらず、別でツールをインストールする必要があったような気がします。

おわりに

日頃からPythonを使いこなしているか方からすると、poetryのようなツールを活用することは基本のキなのかもしれませんが、個人的にはまた1つ知識のアップデートなるいい機会になりました。
また改めて触り直す機会を作るにはなかなか難しいところではありますが、過去に触ったツールなども時々触ってみたいものですね。