👖

poetryマルチレポからpantsモノレポへ移行してみるときのファーストステップ

2023/09/28に公開

概要

本記事では、poetryで管理された複数のリポジトリを、pantsモノレポに移行する際、まずは各リポジトリのプログラムを実行・テストするところまでの方法を紹介します。

  1. pantsのインストール
  2. リポジトリを構成する
  3. pantsの初期設定を行う
  4. 動作確認
  5. IDEの設定

以下の内容の詳細は本記事では扱いませんが参考になる情報へのリンクを紹介しておきます。(モノレポを意義を考えると、ここからが本番だと思います。)

また、なるべく参考にした公式documentへのリンクを貼るようにしたので、より正確で最新の情報はそちらを参照してください。

本記事では開発環境を以下のように想定します。

  • OS: Linux(Ubuntu 22.04)
  • IDE: Visual Studio Code

本記事で扱ったサンプルコードは以下を参照してください。

pantsのインストール

Linuxなら以下のようにinstallerのスクリプトをダウンロードして、インストールを実行できます。デフォルトでは~/binにpantsバイナリが入るので適宜PATHを設定します。

curl --proto '=https' --tlsv1.2 -fsSL https://static.pantsbuild.org/setup/get-pants.sh | bash

各OSごとの詳細は以下を参照ください。

公式ドキュメント参考箇所へのリンク

リポジトリを構成する

初期構成

以下のような構成を想定します。内容の詳細はリポジトリを参照してください。

内製ライブラリとアプリケーションコード(単体でサービスとして機能するもの)を分けて、シンプルな依存関係を想定しています。

  • libs配下に内製ライブラリ(fizzbuzzライブラリ)を入れる。
  • projects配下に独立したアプリケーションコードを入れる。
  • project_aではfizzbuzzライブラリを参照している。
  • project_bではfizzbuzzライブラリを参照していない。
.
├── libs
│   └── fizzbuzz
│       ├── fizzbuzz/
│       ├── pyproject.toml
│       ├── README.md
│       └── tests/
├── pants.toml
├── projects
│   ├── project_a
│   │   ├── pyproject.toml
│   │   └── src/
│   └── project_b
│       ├── pyproject.toml
│       └── src/

公式ドキュメント参考箇所へのリンク

pantsの初期設定を行う

pants.tomlの設定

基本的には公式ドキュメントおよび公式のpythonサンプルリポジトリにある通りになります。

TIPS

  • sourceの項目に「"pyproject.toml"」を指定する。
    • [source]は、どのディレクトリをソースコードのルートして見るかを指定する項目です。
pants.toml
[GLOBAL]
pants_version = "2.17.0"

backend_packages.add = [
  "pants.backend.build_files.fmt.black",  
  "pants.backend.python",
  "pants.backend.python.lint.docformatter",
  "pants.backend.python.lint.black",
  "pants.backend.python.lint.flake8",
  "pants.backend.python.lint.isort",
  "pants.backend.python.typecheck.mypy",
]


[source]
marker_filenames = ["pyproject.toml"]

[python]
interpreter_constraints = [">=3.9.*"]
enable_resolves = true
default_resolve = "python_default"

[python-bootstrap]
search_path = ["<PATH>", "<PYENV>"]

[python-infer]
# 2.17 is transitioning to a new, faster parser for dependency inference:
use_rust_parser = true

公式ドキュメント参考箇所へのリンク

BUILDファイルの設定

pantsは各フォルダにBUILDというテキストファイルを設置する必要があります。手動で行うのは大変なので、以下のコマンドで生成します。今は特に指定しませんが、BUILDファイルの内容を変更することで、パッケージ化の詳細指定などを行うことができます。

pants tailor ::

TIPS

  • :は、「そのディレクトリ内のすべてのファイル(サブディレクトリは含めない)」という意味
  • ::は、「そのディレクトリ内およびそのサブディレクトリ内のすべてのファイル」という意味

公式ドキュメント参考箇所へのリンク

動作確認

まずは各コードを動かしてみる

poetryと異なり仮想環境を明示的に作る必要はありませんが、依存関係を解決するためにlockfileというpants固有のファイルを作成する必要があります。

lockfileを作成するには以下を実施します。

pants generate-lockfiles
  • project_aのアプリケーションを動かす
pants run projects/project_a/src/main.py -- --start=0 --stop=100 --show-fizzbuzz
  • FizzBuzzのコードをテストする
pants test libs/fizzbuzz::

TIPS

  • -- のあとにソースコードの実行時の引数パラメータを与えることができる。
  • 3rdpartyライブラリの依存関係は、pyproject.tomlからpantsが解決する
  • 内製ライブラリ(libs配下)かどうかは、pants.tomlの[source] 項目の指定で特定できるライブラリかどうかで、pantsが自動的に判断する

実行環境を確認してみる

pantsでコードを実行するとpex形式の実行環境が一時的に生成されます。デバッグとしてその実行環境を確認したい場合は、以下のように--keep-sandboxes=alwaysをつけて実行します。

pants --keep-sandboxes=always lint projects/project_a/src::

実行時にsandboxの場所が表示され、自動的には削除されなくなります。通常は/tmp/sandbox-xxxx(xxxxはハッシュ値)という場所に保存されます。

公式ドキュメント参考箇所へのリンク

実行環境を出力してみる

今回は、以下のコマンドで出力できます。

pants export --py-resolve-format=symlinked_immutable_virtualenv --resolve=python-default

TIPS

  • --py-resolve-format=symlinked_immutable_virtualenvはイミュータブルな環境として出力するOptionになります。
  • 環境の切り替えを行う場合、--resolveキーワードで指定します。

公式ドキュメント参考箇所へのリンク

pex形式でパッケージングする

BUILDファイルに設定を追記します。例えばproject_b直下のBUILDファイルに以下を追記します。

projects/project_b/BUILD
poetry_requirements(
    name="poetry",
)

+ pex_binary(
+     name="project_b",
+     entry_point="src/app.py",
+ )

その後、以下を実行することでdistフォルダにpex形式のファイルが出力されます。

pants package projects/project_b:project_b

公式ドキュメント参考箇所へのリンク

IDE設定

ここまででコードの動作は確認できましたが、このままではLinterやFormatterなどが効かないため不便です。

Linter・Formatterの設定

LinterやFormatterのバイナリパスを指定します。

以下を実行し、LinterやFormatterのバイナリを出力します。通常はdistフォルダに出力されます。

pants export

Visual Studio Codeであれば、.vscodeに設定用のJSONを用意しておくとよいでしょう。

.vscode/settings.json
{
    "python.linting.flake8Enabled": true,
    "python.linting.flake8Path": "dist/export/python/virtualenvs/tools/flake8/bin/flake8",
    "python.formatting.blackPath": "dist/export/python/virtualenvs/tools/black/bin/black",
    "isort.path": [
        "dist/export/python/virtualenvs/tools/isort/bin/isort"
    ],
    "python.linting.mypyPath": "dist/export/python/virtualenvs/tools/mypy/bin/mypy"
}

公式ドキュメント参考箇所へのリンク

内製ライブラリへのパス

libs内の内製ライブラリを使用する際、IDEはライブラリがどこに存在するのか分からないため、インテリセンスが効かず不便です。その際は、PYTHONPATHを上書きするファイル.envを用意します。

ROOTS=$(pants roots)
python3 -c "print('PYTHONPATH=\"./' + ':./'.join('''${ROOTS}'''.split('\n')) + ':\$PYTHONPATH\"')" > .env

なお、このままだとisortによるimport順序修正の際、内製ライブラリがアプリケーションコードと同じ階層にあると判断され、import順序が本来想定しない形になります。そのため、.isort.cfgに以下の設定を追記しておくとよいです。

.sort.cfg
known_first_party=fizzbuzz

公式ドキュメント参考箇所へのリンク

その他

複雑な依存関係の解決

一般にモノレポでは数百単位のライブラリ、プロジェクトを扱うこともあり依存関係が複雑化します。本記事ではpantsによって自動的に依存関係を解決していましたが、プロダクトの種類によっては自分たちでより詳細なコントロールをすることが適切な場合があります。

公式ドキュメントではLockfileを使った方法が推奨されています。

Lockfileは人間が解釈しやすいファイルではないため、よりメンテンナンス性の高い、pip-compileを使った方法を提案されているのが以下の記事になります。

変更箇所に応じて実行するCIを選択する

開発体験を損なわないために、変更箇所に応じて実行するCIジョブを選択する必要があります。本記事では紹介しませんが、モノレポを導入時には必ず検討する必要があります。

公式ドキュメント参考箇所へのリンク


以上でpantsによるプログラムの実行までできるようになりました。CIの設定などはまた別の記事で紹介できたらと思います。

Discussion