この記事は Sansan Advent Calendar 2022 19日目の記事です。
前日は fujisyo32 さんの
でした。
今年は特に画像周りで拡散モデルの話題で持ち切りでしたね。言語生成周りの研究も非常に興味深いです。
はじめに
私が所属する研究開発部では、Python のパッケージマネージャとして Poetry を標準的に利用しています。
Rust のように toml でパッケージを人間が認識しやすい形で管理できる点は非常に魅力的であり、setup.py
, requirements.txt
, setup.cfg
, MANIFEST.in
等を代替できるため非常に便利です。
しかしながら最近、Poetry を用いたインストールやパッケージ追加等の依存解決に凄まじく時間を要しており、なんとか速度削減して開発のサイクルを早めることは出来ないかなと感じております。
そこで今回は、以前からあくまで個人的に試したいと思っていた高速なパッケージマネージャである PDM を試してみたいと思います。
PDM とは
PDM も Poetry と同様に pyproject.toml によってパッケージを管理する Python パッケージマネージャです。
Poetry との大きな差異としては、次の2点が挙げられます。
- PEP 582 に基づき、仮想環境を使わずに利用できる仕組みを搭載 (利用するかは選択可能)
- 依存解決を含めて、動作が非常に高速
一方で CLI ツールとしては Poetry と操作感が非常に似ており Poetry ユーザであれば簡単に利用することが可能です。早速試していきましょう。
PDM を試す
紹介時の PDM のバージョンは 2.3.3
です。
インストール
インストール方法は公式HP等を参照してください。よくある curl で持ってくるやつです。
$ curl -sSL https://raw.githubusercontent.com/pdm-project/pdm/main/install-pdm.py | python Installing PDM (2.3.3): Creating virtual environment Installing PDM (2.3.3): Installing PDM and dependencies Installing PDM (2.3.3): Making binary at /Users/nersonu/.local/bin Usage: pdm [-h] [-V] [-c CONFIG] [-v] [-I] [--pep582 [SHELL]] {add,build,cache,completion,config,export,import,info,init,install,list,lock,publish,remove,run,search,self,plugin,show,sync,update,use,venv} ... ____ ____ __ ___ / __ \/ __ \/ |/ / / /_/ / / / / /|_/ / / ____/ /_/ / / / / /_/ /_____/_/ /_/ Commands: {add,build,cache,completion,config,export,import,info,init,install,list,lock,publish,remove,run,search,self,plugin,show,sync,update,use,venv} add Add package(s) to pyproject.toml and install them build Build artifacts for distribution cache Control the caches of PDM completion Generate completion scripts for the given shell config Display the current configuration export Export the locked packages set to other formats import Import project metadata from other formats info Show the project information init Initialize a pyproject.toml for PDM install Install dependencies from lock file list List packages installed in the current working set lock Resolve and lock dependencies publish Build and publish the project to PyPI remove Remove packages from pyproject.toml run Run commands or scripts with local packages loaded search Search for PyPI packages self (plugin) Manage the PDM program itself (previously known as plugin) show Show the package information sync Synchronize the current working set with lock file update Update package(s) in pyproject.toml use Use the given python version or path as base interpreter venv Virtualenv management Options: -h, --help show this help message and exit -V, --version show the version and exit -c CONFIG, --config CONFIG Specify another config file path(env var: PDM_CONFIG_FILE) -v, --verbose -v for detailed output and -vv for more detailed -I, --ignore-python Ignore the Python path saved in the .pdm.toml config --pep582 [SHELL] Print the command line to be eval'd by the shell Successfully installed: PDM (2.3.3) at /Users/nersonu/.local/bin/pdm
PDM でプロジェクトを立ち上げる
プロジェクトのルートディレクトリで pdm init
すれば、対話式でプロジェクトを立ち上げることが出来ます。
$ pdm init Creating a pyproject.toml for PDM... Please enter the Python interpreter to use 0. /Users/nersonu/.pyenv/shims/python3 (3.10) 1. /Users/nersonu/.pyenv/shims/python (3.10) 2. /Users/nersonu/.pyenv/versions/3.10.9/bin/python3.10 (3.10) 3. /Users/nersonu/.pyenv/shims/python3.10 (3.10) 4. /Users/nersonu/.pyenv/shims/python3.9 (3.9) 5. /usr/local/bin/python3.9 (3.9) 6. /Users/nersonu/.pyenv/versions/3.9.13/bin/python3.9 (3.9) 7. /usr/bin/python3 (3.8) 8. /usr/bin/python2.7 (2.7) 9. /Users/nersonu/Library/Application Support/pdm/venv/bin/python (3.10) Please select (0): 0 Using Python interpreter: /Users/nersonu/.pyenv/shims/python3 (3.10) Would you like to create a virtualenv with /Users/nersonu/.pyenv/versions/3.10.9/bin/python3? [y/n] (y): y Is the project a library that will be uploaded to PyPI [y/n] (n): n License(SPDX name) (MIT): Author name (nersonu): Author email (nersonu@gmail.com): Python requires('*' to allow any) (>=3.10): >=3.9 Changes are written to pyproject.toml. $ ls pyproject.toml
特徴的な点としては、利用する Python インタプリタを指定することです。
ここで指定したインタプリタは、.pdm.toml
に書かれます。
[python] path = "/Users/nersonu/.pyenv/shims/python3"
なお、ユーザごとに利用するインタプリタが異なることから、このファイルは git などで commit しないように気をつけましょう。
また、 Poetry や Rust の Cargo のように src
ディレクトリや README ファイルは生成されません。
生成された pyproject.toml はこのようになっています。
[tool.pdm] [project] name = "" version = "" description = "" authors = [ {name = "nersonu", email = "nersonu@gmail.com"}, ] dependencies = [] requires-python = ">=3.9" license = {text = "MIT"}
pyproject.toml の形式は PEP 621 に基づいており、Poetry とは若干形式が異っていますね。
仮想環境については、 pdm init
の際に生成するようにした (以下)
Would you like to create a virtualenv with /Users/nersonu/.pyenv/versions/3.10.9/bin/python3? [y/n] (y): y
ため、pdm run
でルートに作られた .venv
を利用して実行することができます。
$ pdm run which python /Users/aomi/workspace/try_pdm/init_pdm/.venv/bin/python
パッケージの追加
poetry add
と同じような形で pdm add
でパッケージの追加が可能です。
$ pdm add numpy pandas Adding packages to default dependencies: numpy, pandas 🔒 Lock successful Changes are written to pdm.lock. Changes are written to pyproject.toml. Synchronizing working set with lock file: 5 to add, 0 to update, 0 to remove ✔ Install six 1.16.0 successful ✔ Install python-dateutil 2.8.2 successful ✔ Install pytz 2022.7 successful ✔ Install pandas 1.5.2 successful ✔ Install numpy 1.23.5 successful 🎉 All complete! $ ls pdm.lock pyproject.toml
pdm.lock が生成され、poetry.lock と同様に依存関係等がここに残されます。
また、 pyproject.toml は以下のように更新されています。
[tool.pdm] [project] name = "" version = "" description = "" authors = [ {name = "nersonu", email = "nersonu@gmail.com"}, ] dependencies = [ "numpy>=1.23.5", "pandas>=1.5.2", ] requires-python = ">=3.9" license = {text = "MIT"}
Poetry と同様に、開発用ライブラリとライブラリのグループ管理が可能です。
Poetry と若干異なるところは、開発用ライブラリをグループと同様に依存関係に含めるか、独立させるかオプションの指定の仕方で選べるところです。
今回は依存関係に含めない形で、開発用ライブラリとして pytest
をインストールする形を紹介します。
$ pdm add -d pytest Adding packages to dev dev-dependencies: pytest 🔒 Lock successful Changes are written to pdm.lock. Changes are written to pyproject.toml. Synchronizing working set with lock file: 7 to add, 0 to update, 0 to remove ✔ Install exceptiongroup 1.0.4 successful ✔ Install iniconfig 1.1.1 successful ✔ Install tomli 2.0.1 successful ✔ Install pluggy 1.0.0 successful ✔ Install packaging 22.0 successful ✔ Install attrs 22.1.0 successful ✔ Install pytest 7.2.0 successful 🎉 All complete!
pyproject.toml では tool.pdm.dev-dependencies
の項に追加されています。
[tool.pdm] [tool.pdm.dev-dependencies] dev = [ "pytest>=7.2.0", ] [project] ...
グループ追加 (ここでは "plot" という名前にしています) は以下のように行えます。
$ pdm add -G plot matplotlib seaborn Adding packages to plot dependencies: matplotlib, seaborn 🔒 Lock successful Changes are written to pdm.lock. Changes are written to pyproject.toml. Synchronizing working set with lock file: 13 to add, 0 to update, 0 to remove ✔ Install cycler 0.11.0 successful ✔ Install pyparsing 3.0.9 successful ✔ Install kiwisolver 1.4.4 successful ✔ Install contourpy 1.0.6 successful ✔ Install seaborn 0.12.1 successful ✔ Install fonttools 4.38.0 successful ✔ Install pillow 9.3.0 successful ✔ Install matplotlib 3.6.2 successful 🎉 All complete!
最終的な pyproject.toml は次のようになりました。
[tool.pdm] [tool.pdm.dev-dependencies] dev = [ "pytest>=7.2.0", ] [project] name = "" version = "" description = "" authors = [ {name = "nersonu", email = "nersonu@gmail.com"}, ] dependencies = [ "numpy>=1.23.5", "pandas>=1.5.2", ] requires-python = ">=3.9" license = {text = "MIT"} [project.optional-dependencies] plot = [ "matplotlib>=3.6.2", "seaborn>=0.12.1", ]
なお、 project.optional-dependencies
の中に dev を含めたい場合は -dG
で出来るようです。
virtualenv との併用
pyenv local hoge
のように、 pyenv
や pyenv-virtualenv
を利用している場合の挙動を確認しておきましょう。
$ pyenv local try_pdm $ pip -V pip 22.3.1 from /Users/nersonu/.pyenv/versions/3.10.9/envs/try_pdm/lib/python3.10/site-packages/pip (python 3.10)
試しに pdm init
してみると、仮想環境を生成する質問がなくなり、生成されなくなりました。
$ pdm init Creating a pyproject.toml for PDM... Please enter the Python interpreter to use 0. /Users/nersonu/.pyenv/shims/python3 (3.10) 1. /Users/nersonu/.pyenv/shims/python (3.10) 2. /Users/nersonu/.pyenv/versions/3.10.9/bin/python3.10 (3.10) 3. /Users/nersonu/.pyenv/shims/python3.10 (3.10) 4. /Users/nersonu/.pyenv/shims/python3.9 (3.9) 5. /usr/local/bin/python3.9 (3.9) 6. /Users/aomi/.pyenv/versions/3.9.13/bin/python3.9 (3.9) 7. /usr/bin/python3 (3.8) 8. /usr/bin/python2.7 (2.7) 9. /Users/nersonu/Library/Application Support/pdm/venv/bin/python (3.10) Please select (0): Using Python interpreter: /Users/nersonu/.pyenv/shims/python3 (3.10) Is the project a library that will be uploaded to PyPI [y/n] (n): License(SPDX name) (MIT): Author name (nersonu): Author email (nersonu@gmail.com): Python requires('*' to allow any) (>=3.10): >=3.9 Changes are written to pyproject.toml.
このまま pdm run
でコマンド実行してみたところ、既に設定した仮想環境を利用できました。
既にプロジェクトで仮想環境が設定されている場合、認識して使ってくれるようですね。
PEP 582 の世界を体験する
PEP 582 とは
__pypackages__
というディレクトリをルートに置いておき、ここに保存されているパッケージを使おうという考えです。
こうすることで、仮想環境作ってそこでライブラリを入れて……という一連の流れをスキップ出来ます。
PEP 582 に対応しているツールはほとんどなく、PDM はこれを実現している希少なソフトウェアと言えるかもしれません。早速体験してみます。
PDM で PEP 582 の機能を有効にする
公式ページには、 bash でのやり方が載っていますが、自分は zsh を使っているので適当に .zshrc
に突っ込んでみます。
$ pdm --pep582 >> ~/.zshrc $ exec $SHELL
プロジェクトを作ってみる
先に __pypackages__
ディレクトリを作っておきます。
$ mkdir __pypackages__
pdm init
してみます。
pdm init Creating a pyproject.toml for PDM... Please enter the Python interpreter to use 0. /Users/nersonu/.pyenv/shims/python3 (3.10) 1. /Users/nersonu/.pyenv/shims/python (3.10) 2. /Users/nersonu/.pyenv/versions/3.10.9/bin/python3.10 (3.10) 3. /Users/nersonu/.pyenv/shims/python3.10 (3.10) 4. /Users/nersonu/.pyenv/shims/python3.9 (3.9) 5. /usr/local/bin/python3.9 (3.9) 6. /Users/nersonu/.pyenv/versions/3.9.13/bin/python3.9 (3.9) 7. /usr/bin/python3 (3.8) 8. /usr/bin/python2.7 (2.7) 9. /Users/nersonu/Library/Application Support/pdm/venv/bin/python (3.10) Please select (0): Using Python interpreter: /Users/nersonu/.pyenv/shims/python3 (3.10) Would you like to create a virtualenv with /Users/nersonu/.pyenv/versions/3.10.9/bin/python3? [y/n] (y): n You are using the PEP 582 mode, no virtualenv is created. For more info, please visit https://peps.python.org/pep-0582/ Is the project a library that will be uploaded to PyPI [y/n] (n): n License(SPDX name) (MIT): Author name (nersonu): Author email (nersonu@gmail.com): Python requires('*' to allow any) (>=3.10): Changes are written to pyproject.toml.
You are using the PEP 582 mode, no virtualenv is created.
For more info, please visit https://peps.python.org/pep-0582/
ちゃんと有効化されてそうです。試しに numpy でも追加してみましょう。
$ pdm add numpy Adding packages to default dependencies: numpy 🔒 Lock successful Changes are written to pdm.lock. Changes are written to pyproject.toml. Synchronizing working set with lock file: 1 to add, 0 to update, 0 to remove ✔ Install numpy 1.23.5 successful 🎉 All complete! ... $ tree -L 3 __pypackages__ __pypackages__ └── 3.10 ├── bin │ ├── f2py │ ├── f2py3 │ └── f2py3.10 ├── include └── lib ├── numpy └── numpy-1.23.5.dist-info
numpy が __pypackages__
配下に入っていますね。面白い。
PEP 582 を実際に使用することはなかなか無いと思いますが、初学者にとって仮想環境に触れずに済むようなパッケージ管理は非常に魅力的です。 これを実現できる PDM なかなか良さげですね。
速度比較
前回の記事を流用します。実は、比較先の一番左が PDM でした。 nersonu.hatenablog.com
Python のパッケージマネージャの速度比較をしている Web ページから引用しています。画像は前2つは前回と同じです。
Poetry で一番ネックな部分である install 周りが超速いです。素晴らしいですね。
一方でパッケージの単純追加は Poetry に負けています (これだけ Poetry 1.3.1)。
それにしても install が速いです。
Poetry を使っていると、コンテナをビルドする際の poetry install
がとてつもなく時間がかかるため、こういった点は PDM に軍配が上がるんだろうなと感じています。
おわりに
今回は PDM を試しましたが、なかなか面白く、高速で良い感じでした。 いつか機会があれば業務でも導入してみたいですね。
明日は id:kur0cky さんです。皆様、よいクリスマスを。