理系学生日記

おまえはいつまで学生気分なのか

RyeによるPython環境構築

僕がPythonを使っていたのは2015年までなのですが、その頃とは打って変わって、Pythonの環境構築に関するツールは充実してきた印象を受けています1。その中で、これ良さそうだなと思ったのがRyeでした。

Ryeとは

Ryeは一言で言えばpyenvとpoetryを組み合わせたようなものです。pyenvはPythonのバージョン管理ツールで、poetryはPythonのパッケージ管理ツールです。Ryeはこれら双方の機能を持ち、さらにPythonの仮想環境管理(virtualenv)機能も持っています。

Rye自体は、PythonのWebアプリ用フレームワークであるFlaskの作者であるArminが個人として作成しているもので、プロダクションレディなものではないと明言されています。ただ、使ってみると相当使いやすく、僕もしばらくの間は個人としてPythonを使っていきたいので、ちょうど良さそうです。

今日のエントリは以下のryeのバージョンでお届けします。

$ rye --version
rye 0.16.0
commit: 0.16.0 (2023-12-16)
platform: macos (aarch64)
self-python: cpython@3.11
symlink support: true

ryeのインストール

インストール自体は、MacならHomebrewでインストールできます。

$ brew install rye

あるいは、単にWebから直接インストールも可能です。

$ curl -sSf https://rye-up.com/get | bash

shimにPATHを通す

Ryeの挙動の鍵を握るのはshimsです。この点は後述するとして、まずはshimにPATHを通します。 これは、$HOME/.ryeに配置されるenvが実施してくれるので、シェルの設定ファイルにenvを読み込ませれば良いです。

$ echo 'source "$HOME/.rye/env"' >> ~/.zshrc

実際のenvファイルは以下のような内容です。単にPATHを通しているだけのシンプルな内容ですね。

# rye shell setup
case ":${PATH}:" in
  *:"$HOME/.rye/shims":*)
    ;;
  *)
    export PATH="$HOME/.rye/shims:$PATH"
    ;;
esac

ryeの補完を効かせる

Homebrewでインストールした場合、zshの補完はすぐに効くようになりました。 実際、インストール時点で$HOMEBREW_PREFIX/share/zsh/site-functions/_ryeが生成されていました。このため、zshの設定ファイルでprepend FPATH "$HOMEBREW_PREFIX/share/zsh/site-functions"しておきさえすれば補完対応は完了します。

$ rye
add        -- Adds a Python package to this project
build      -- Builds a package for distribution
config     -- Reads or modifies the global `config.toml` file
fetch      -- Fetches a Python interpreter for the local machine
help       -- Print this message or the help of the given subcommand(s)
init       -- Initialize a new or existing Python project with Rye
install    -- Installs a package as global tool
lock       -- Updates the lockfiles without installing dependencies
make-req   -- Builds and prints a PEP 508 requirement string from parts
pin        -- Pins a Python version to this project
publish    -- Publish packages to a package repository
remove     -- Removes a package from this project
run        -- Runs a command installed into this package
self       -- Rye self management
shell      -- Spawns a shell with the virtualenv activated
show       -- Prints the current state of the project
sync       -- Updates the virtualenv based on the pyproject.toml
toolchain  -- Helper utility to manage Python toolchains
tools      -- Helper utility to manage global tools
uninstall  -- Uninstalls a global tool
version    -- Get or set project version

Pythonプロジェクトを作成する

Pythonプロジェクトはrye initコマンドで作成します。実行すると、以下のようなファイルが作成されます。

$ rye init testpj
$ ls -a testpj
./  ../  .python-version  README.md  pyproject.toml  src/

.python-versionがプロジェクトで利用するpythonのバージョンを記述するファイルです。pyproject.tomlはPythonのパッケージ管理ファイルで、srcはソースコードを配置するディレクトリです。

バージョン指定したPythonをインストールする

Pythonのバージョン指定はrye pinで行います。

$ cd testpj
$ rye pin 'cpython@3.12.0'
$ cat .python-version
3.12.0

この段階でpythonを実行すると面白くて、cpython@3.12.0が未インストールの場合、インストールから開始されます。 何が起こっているのかというと、先ほどPATHを通したshims配下のpythonryeへのシンボリックリンクになっていて、あとはryeがよしなにインストール有無等判断してくれているようです。

$ ls -l $(which python)
lrwxr-xr-x 1 kiririmode staff 32  1  6 08:37 /Users/kiririmode/.rye/shims/python -> /Users/kiririmode/.rye/shims/rye*

インストールが終われば、当該プロジェクトでpythonを利用できるようになります。

$ python -V
Python 3.12.0

依存関係を管理する

Pythonにおける依存関係は、rye addで指定します。 例えばflask v.2系の最新バージョンを指定してみましょう。

$ rye add 'flask>=2.0,<3'
Added flask>=2.0 as regular dependency

この段階ではflaskはインストールされず、pyproject.tomlに依存関係が記述されるのみです。このように、依存関係指定はpyproject.tomlで管理されます。

$ grep -A2 '^dependencies' pyproject.toml
dependencies = [
    "flask>=2.0, <3",
]

では、実際のインストールはどうするのかというと、rye syncで実行します。

$ rye sync
Reusing already existing virtualenv
Generating production lockfile: /Users/kiririmode/src/github.com/kiririmode/blog/kiririmode.hatenablog.jp/entry/20240106/testpj/requirements.lock
(略)
Installing collected packages: testpj
Successfully installed testpj-0.1.0
Done!

これでflaskがインストールされました。 例えば、.venv配下にはflaskの実行ファイルが存在しています。

$ ls .venv/bin/flask
.venv/bin/flask*```

venv配下のモジュールを使う

インストールしたvirtualenv配下の実行ファイルは、npm runのようにrye runで実行できます。

準備

ここではflaskでWebアプリを実行してみたいので、以下のようなhello.pysrc/testpj配下に作成します。

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

実行 (rye run)

では、これを実行してみましょう。 単純にflaskを実行しても、そのようなファイルは見つかりません。

$ flask --app hello run
zsh: command not found: flask

ここでrye runを使うと、virtualenv配下のflaskを実行できます。

$ cd src/testpj
$ rye run flask --app hello run
 * Serving Flask app 'hello'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit

また、実際にsys.prefixを見ると、この段階でvirtualenvが意識されていることがわかります。 いちいちactivateする必要がないというのは楽ですね。

$ python -c "import sys; print(sys.prefix)"
/Users/kiririmode/src/github.com/kiririmode/blog/kiririmode.hatenablog.jp/entry/20240106/testpj/.venv

無事にflaskでWebアプリが起動できました。

実行 (rye shell)

virtualenvをactivateして利用したい場合は、rye shellを使います。 rye shellはvirtualenvをactivateした状態でシェルを起動してくれるため、rye runを介さなくてもflaskを起動できます。

$ rye shell
Spawning virtualenv shell from /Users/kiririmode/src/github.com/kiririmode/blog/kiririmode.hatenablog.jp/entry/20240106/testpj/.venv
Leave shell with 'exit'

$ flask --app hello run
 * Serving Flask app 'hello'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit

Pythonプロジェクトの設定

Ryeにおいては、個々のPythonプロジェクトの設定は、pyproject.tomlに記述します。 プロダクション用の依存関係であるproject.dependenciesや開発用の依存関係であるproject.dev-dependencies、また、project.scriptsにはrye runで実行できるスクリプトを記述します。

tool.rye.scriptsには、npm runと同様に、rye runで実行できるスクリプトを記述します。

例えばpyproject.tomlに次のように記述します。

[tool.rye.scripts]
devserver = { cmd = "flask --app ./src/testpj/hello.py run --debug" }

そうすると、rye run devserverflaskが起動できるようになります。

VSCode設定

このようにしてryeを使って開発できる環境を整えていくわけですが、VSCodeをみると、Pythonのコードにおいてvirtualenv配下のモジュールが解決できていません。

これはVSCodeが適切なPythonインタプリタを見つけられていないことが要因です。 VSCodeのコマンドパレットからPython: Select Interpreterを用いて適切なインタプリタを選択しても良いでしょうし、setting.jsonに次のようなエントリを追加しても良いでしょう。

  "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python"

上記はワークスペースの配下に.venvがあることを前提にしており、VS CodeのworkspaceFolder変数を利用しています。そのほかの変数については以下を参照ください。

まとめ

Ryeはpyenvとpoetryを組み合わせたようなもので、Pythonのバージョン管理、パッケージ管理、仮想環境管理を一括で行えるツールです。


  1. 私があまり調べていなかっただけで、その頃から充実していた可能性もありますが。