rye を使ったPythonの開発環境を VSCode Dev Container で構築する

2023/06/02に公開

rye がよさそう

Rye は、Rust の Rustup と Cargo からインスピレーションを得て、Python に新しいタイプのパッケージング エクスペリエンスを構築する実験的な取り組みです。まだ製品化の準備ができていませんが、フィードバックや提案をいただければ幸いです。

個人的にも Python にはよくお世話になっておりますが、ざっくり印象として「バージョン管理が面倒」「パッケージ管理が面倒」[1] 「それらのためのツールがいくつか並立している」という課題というか、悩み事が常についてまわっていると思ってまして、実際にプロジェクトで使う際にも、その時点その時点でのベストプラクティスを調べつつ、環境を構築しているというのが実態でした。[2]

実験的な取り組みは大好物なので、さっそく試してみます。

Dev Container を作る

私はよくやりがちですが、自分のマシンにいろいろインストールしたくないので、できることはすべて Dev Container でやろうとします。今回もこれでいきます。

devcontainer.json
{
    "name": "rye-workspace",
    "build": {
        "dockerfile": "Dockerfile"
    },
    "customizations": {
        "vscode": {
            "extensions": [
                "gruntfuggly.todo-tree",
                "eamodio.gitlens",
                "ryokat3.vscode-qiita-markdown-preview",
                "christian-kohler.path-intellisense",
                "ms-azuretools.vscode-docker",
                "ms-python.python",
                "ms-toolsai.jupyter"
            ]
        }
    },
    "remoteUser": "vscode",
    "postCreateCommand": "/bin/sh .devcontainer/postCreateCommand.sh"
}
Dockerfile
FROM mcr.microsoft.com/devcontainers/base:bullseye
RUN apt-get update \
    && apt-get install -y libwebkit2gtk-4.0-dev libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev git vim curl bash \
    && apt-get clean -y && rm -rf /var/lib/apt/lists/* 
postCreateCommand.sh
#!/bin/bash

curl -sSf https://rye-up.com/get | RYE_INSTALL_OPTION="--yes" bash

echo 'source "$HOME/.rye/env"' >> ~/.bashrc
. "$HOME/.rye/env"
Dockerfileについて

こちらの記事でも書きましたが、実際にはbashプロンプトをいろいろ便利にするためにコマンドをいくつか追加しています。手元のDockerfileの全体像は以下のようになっています。ご参考まで🙇

Dockerfile
FROM mcr.microsoft.com/devcontainers/base:bullseye
RUN apt-get update \
    && apt-get install -y libwebkit2gtk-4.0-dev libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev git vim curl bash \
    && apt-get clean -y && rm -rf /var/lib/apt/lists/* 

RUN echo "source /usr/share/bash-completion/completions/git" >> ~/.bashrc

WORKDIR /usr/share/bash-completion/completions

RUN curl -O https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh
RUN curl -O https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash
RUN chmod a+x git*.*
RUN ls -l $PWD/git*.* | awk '{print "source "$9}' >> ~/.bashrc

RUN echo "GIT_PS1_SHOWDIRTYSTATE=true" >> ~/.bashrc
RUN echo "GIT_PS1_SHOWUNTRACKEDFILES=true" >> ~/.bashrc
RUN echo "GIT_PS1_SHOWUPSTREAM=auto" >> ~/.bashrc

RUN echo 'export PS1="\[\033[01;32m\]\u@\h\[\033[01;33m\] \w \[\033[01;31m\]\$(__git_ps1 \"(%s)\") \\n\[\033[01;34m\]\\$ \[\033[00m\]"' >> ~/.bashrc

devcontainer.jsonextentionsは、お好みのものをよしなに並べてください。

ryeの環境構築を Dev Container にする際のポイントはdevcontainer.jsonpostCreateCommandと、postCreateCommand.shです。
postCreateCommandに指定したコマンドは、コンテナのビルド後に自動実行してくれます。公式のinstallationに沿ったインストール手順をpostCreateCommand.shに記述しておいて実行してもらいます。

Dev Container を起動する

上のように作成したファイルを.devcontainerディレクトリに格納し、Dev Container を起動します。
起動が完了したら、ターミナルでryeのバージョンを確認してみます。

$ rye --version
rye 0.4.0
commit: 0.4.0 (cdc5c37bc 2023-05-29)
platform: linux (x86_64)
self-python: cpython@3.10
symlink support: true

無事、インストールできたようです!

ryeのコマンド紹介と実演

ここまでできれば、あとはryeを使って開発を進めていくだけです。
公式のDocumentationにもありますが、このあと使うだろうコマンドをいくつか紹介しておきますので、ご参考ください。

  • プロジェクトの作成: rye init {project-name}
  • Python インタプリタバージョンの指定: rye pin {py-version}
  • パッケージの追加指定: rye add {package-name}
  • パッケージの削除指定: rye remove {package-name}
  • 仮想環境の作成・更新、パッケージのインストール: rye sync

pip/pipenvとの大きな違いは、ryesyncを実行するまでパッケージのインストールやアンインストールを行わないことです。
addremoveで行うのはあくまでもパッケージの内容を記載したpyproject.tomlの編集のみで、実際のパッケージ操作はrye syncを実行して初めて行われるようになっています。

まずはプロジェクトの作成から始めます。

プロジェクトの作成

$ rye init sample-project
success: Initialized project in /workspaces/rye-template/sample-project
  Run `rye sync` to get started

Python バージョンの指定

$ rye pin 3.11
pinned 3.11.3 in /workspaces/rye-template/sample-project/.python-version

この時点ではまだインストールされません。

ライブラリの指定

$ rye add pandas ipykernel matplotlib
Added pandas~=2.0.2 as regular dependency
Added ipykernel~=6.23.1 as regular dependency
Added matplotlib~=3.7.1 as regular dependency

実行環境と同じく、この時点ではインストールされません。

実行環境とライブラリのインストール

$ rye sync
Downloading cpython@3.11.3
Checking hash
success: Downloaded cpython@3.11.3
Initializing new virtualenv in /workspaces/rye-template/sample-project/.venv
Python version: cpython@3.11.3
Generating production lockfile: /workspaces/rye-template/sample-project/requirements.lock
Creating virtualenv for pip-tools
Generating dev lockfile: /workspaces/rye-template/sample-project/requirements-dev.lock
Installing dependencies
Looking in indexes: https://pypi.org/simple/
Obtaining file:///. (from -r /tmp/tmpj5_otvvd (line 1))
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done
  Preparing editable metadata (pyproject.toml) ... done
Collecting numpy==1.24.3 (from -r /tmp/tmpj5_otvvd (line 2))
  Downloading numpy-1.24.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (17.3 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17.3/17.3 MB 13.2 MB/s eta 0:00:00
Collecting pandas==2.0.2 (from -r /tmp/tmpj5_otvvd (line 3))
  Downloading pandas-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.2/12.2 MB 12.8 MB/s eta 0:00:00

・・・中略・・・

Building wheels for collected packages: sample-project
  Building editable for sample-project (pyproject.toml) ... done
  Created wheel for sample-project: filename=sample_project-0.1.0-py3-none-any.whl size=1124 sha256=ad662f09eef2104b8c4f5699e8cf6c4520dd087d5da174e356f894f9e8530092
  Stored in directory: /tmp/pip-ephem-wheel-cache-pu3ysosl/wheels/97/54/f5/d849319cdfa096e074df352654ee2e7c919da8951f090690c6
Successfully built sample-project
Installing collected packages: pytz, tzdata, six, sample-project, python-dateutil, pandas, numpy
Successfully installed numpy-1.24.3 pandas-2.0.2 python-dateutil-2.8.2 pytz-2023.3 sample-project-0.1.0 six-1.16.0 tzdata-2023.3
Done!

rye syncを実行すると、Python実行環境のインストールはパッケージのダウンロードが行われます。
ここまでの作業で、pandasipykernelmatplotlibをインストールした実行環境ができました。

せっかくなので

Jupyter Notebookをちょっと動かしてみます。最近は対話型AIや画像生成AIなどの分野で、Google Colabと合わせてとてもよく見かけるようになりました。

コマンドパレットから「Create: New Jupyter Notebook」を選択します。

create jupyter notebook

新しい Notebook が開くので、

new notebook

こんな感じでコードを入力してみます。

coding

Untitled-1.ipynb
import pandas as pd

url = "https://www.e-stat.go.jp/stat-search/file-download?statInfId=000031523105&fileKind=1"
df = pd.read_csv(url, encoding="shift-jis")

df = df.drop(df.index[-1], axis=0)
df

Run Allで実行しようとすると、実行環境を選ぶダイアログが表示されます。
ryeが構築してくれたvenvを選択します。

run all

結果が表示されました。[4]

csv result

まとめ

以上です!

今回はryeを使って、Python実行環境の作成・ライブラリのインストール・実際のコーディングまで試すことができました。

例えば別のマシンで同じ環境を構築したいとなったとき、ryeをインストールさえしておけば、ソースコード一式に.python-versionpyproject.tomlだけ移してrye syncとすると同じバージョンの環境が構築できるはずです。
今までのPython開発環境には無い、かなりの強みと利便性を感じます。

ぜひご参考いただければ幸いです。

おまけ

ryeは「ライ麦」だそうです。公式サイトのアイコンもライ麦の形をしてますね。

rye

最後に、ryeの開発者でありFlaskの開発者でもある @mitsuhiko氏のコメントを引用して終わらせていただきます。


I just want it solved, and I want to never have to think about Python packaging and project management every again. And until there is a standard tool we all rally around, I don't see that happen.

Pythonのパッケージングやプロジェクト管理について、二度と考える必要がないようにしたいのです。そして、私たち全員が参加できる標準的なツールができるまでは、それが実現することはないでしょう。rye(またはryeのようなもの)がそれになり得るかどうかは分かりませんが、私はオファーを出しています。


ではまた!

参考記事

脚注
  1. nodeなどと同様、Python インタプリタのバージョンとパッケージのバージョンは整合している必要があるので、複数人で開発する場合にはそれぞれの環境で不整合を起こさせない仕組みが必要になります。 ↩︎

  2. Python 自体の管理なら venv, pyenv, Conda、パッケージなら pip, pipenv, Conda, Poetry・・・最近は「pyenv + poetry」がおすすめなんでしょうか。 ↩︎

  3. 新しいウィンドウもDev Container に接続した状態で開きます。このウィンドウはryeが作成した.venvを利用できるようになり、以降の作業がスムーズに進みます。 ↩︎

  4. 国勢調査による人口推移データです。 ↩︎

Discussion