Pythonのプロジェクト管理ツールをuvにした際に、
uvにはpoetryのようにpoetry shell
のような仮想環境を自動認識する機能がないため、ちょっと調べた結果、
miseというツールを試しています。
- Pythonプロジェクト下での仮想環境下でのコマンド実行の必要性
- uvの仮想環境
- mise
- miseのインストール
- Pythonプロジェクト下でのmiseの使い方
- プロンプトへの表示
- GNU screenのCaptionに仮想環境名を表示
Pythonプロジェクト下での仮想環境下でのコマンド実行の必要性
Pythonのプロジェクトを作る際、自分のやり方として pre-commitを使って コードをチェックするようにしています。
pre-commit用のツールはpre-commit自体に管理してもらう事もできますが、 フォーマッターとかをコマンドラインから直接使ったりもしたいので それらのツールはプロジェクトのdevelopment用の依存関係に入れておいてインストールするようにしています。
そのようなツールも毎回書くのが大変なので 以下のようなパッケージを作ってまとめてインストールできるようにもしています。
で、これらのツールは仮想環境の中にインストールされるわけで、 直接実行するには仮想環境内に居る必要があります。
これはエディタなど開いた際なども仮想環境下でそのプロジェクトに必要なツールにパスが通っていることでそれを使えるので pre-commitに直接管理してもらうよりも便利です。
というわけで仮想環境下に簡単に入れるようにしたい、という話。
uvの仮想環境
uvは通常pyproject.tomlファイルのあるディレクトリに.venvディレクトリを作成し、その中に仮想環境を作成します。
仮想環境を有効にするには、.venv/bin/activate
を実行します。
出るにはdeactivate
を実行します。
ただしこの場合はプロジェクトのルートディレクトリに居るか、そこをきちんと指定する必要があります。
また、プロジェクトのディレクトリ以下にいる場合はuv run <command>
で仮想環境下としてコマンドを実行できます。
poetryの場合はデフォルトではキャッシュディレクトリに仮想環境を作成しますが、
同様にpoetry run
一方、activate
を実行するにはキャッシュディレクトリ下の仮想環境ディレクトリを参照する必要がありますが、
poetryでは直接そこを参照する方法はなく
(poetry env info
から取得することは出来ますが)、
通常はpoetry shell
というコマンドで仮想環境を有効にします。
ただし、この場合は仮想環境が有効なシェルを新たに立ち上げている形です。なので環境を出るときにはシェルを出るとき同様exit
などで出ます。
このpoetry shell
に相当する機能がuvにはありません。
これは今のところ意図的な仕様で、Issueにはなってますが、 導入は見送られそうな雰囲気です。
Add a command to activate the virtual environment, e.g., uv shell
· Issue #1910 · astral-sh/uv
一応、uv run $SHELL
とすれば現在のシェルと同じシェルを仮想環境下で立ち上げることになるのでpoetry shell
と同じような事ができます。
poetry shell
が実際どの程度のことをしているかはわからないですが、実用上は同じ状態だと思って良いはず。
上のIssueでは新たなプロセスを立ち上げることに懸念点があり、その際にどの程度今の環境を引き継ぐべきか、シェルやOSなど毎に何を考慮すればよいのか、など考えることが沢山あって難しいという感じです。
確かにそうだな、と思うのと、逆に実用上はuv run $SHELL
で事足りるので、無理に入れる必要はなさそう。
必要ならこれのエイリアスとか作って簡単に実行できるようにしておけばよいかと。
mise
uv run $SHELL
、もしくはactivate
することでも良いのですが、
せっかくなのでこれを機に仮想環境を自動認識するツールを使ってみることにしました。
このような仮想環境を自動認識するツールとしては direnv が有名で古くから良く使われているものだと思います。
direnvは以前ちょっと使ったことがあったのでまた使い始めようかと思って調べてたところ、 mise という同じ様なことが出来る新しいツールがあるとのことで試しています。
流行りのRust製で高速。
なんとなく、mice
的な感じでマイスと読むのかな、と思っていたら、
フランス語で料理などの準備をする、的な意味で
ミーズと読むようです。
いろいろな機能があって、pyenvのように必要なバージョンのPythonをインストールしたり、poetryのように仮想環境を管理したり、direnvのようにプロジェクトのディレクトリ下に入った際に自動で環境を切り替えたり、といったことが出来ます。
取り敢えず現状は環境の切り替えだけのために使っています。
miseのインストール
Homebrewがあれば
1
|
|
で。
直接インストールスクリプトでいれる場合は
1
|
|
など、いろいろな方法でのインストール方法が用意されています。
インストールしたらシェルのセットアップファイルに必要な設定を追加します。
Bashなら
1
|
|
中身を見てみるとわかりますが、PROMPT_COMMAND
に_mise_hook
関数を追加しています。
この関数の中では、
1
|
|
のようなコマンドを実行しています。
これは基本的にexport PATH=...
といったようにPATHを設定します。
これによって、cd
とかでディレクトリを変更した際、そこがプロジェクトのディレクトリ下であるかどうかを判定し、
ディレクトリ下ならそのプロジェクトの仮想環境のPATHを設定し、
逆にそこから出た際には元のPATHに戻す、といったことを行っています。
uv
のプロジェクトだけなら<project>/.venv/bin
をPATHに追加したり外したりするだけなので
その分だけ自作しても良いかな、とも思いましたが、
uv
のプロジェクトのディレクトリ下かどうか、と判定するのは割と面倒で
やっぱりmiseを使おう、と
1。
Pythonプロジェクト下でのmiseの使い方
プロジェクトのルートディレクトリに.mise.tomlファイルを作成します。
1 2 |
|
これでそのプロジェクト下に入った際、
1 2 3 4 |
|
と言われるのでmise trust
を実行します。
そうするとそれ以降、そのプロジェクト下に入った際に自動的に仮想環境が有効になります。 また、そのプロジェクトから出た際には元の環境に戻ります。
プロンプトへの表示
. .venv/bin/activate
を実行した際にはシェルのプロンプトに仮想環境の名前が表示されるようになります。
poetry shell
の場合も同じようにプロンプトに仮想環境の名前が表示されます。
miseを使った場合にはプロンプトは変更されません。
direnvの場合も直接プロンプトは変更されませんが、
プロジェクト下に入った際、仮想環境が有効化されると
VIRTUAL_ENV
以外にVIRTUAL_ENV_PROMPT
という環境変数が設定されるので、それを使ってプロンプトを変更することが出来ます。
miseの場合はVIRTUAL_ENV
は設定されるのですが、VIRTUAL_ENV_PROMPT
は設定されません。
なのでちょっと手をいれる必要があります。
Python environments activating, but zsh prompt not updated · Issue #2027 · jdx/mise
一旦Pythonのvenv限定ですが、 以下の様な関数でプロンプトに仮想環境の名前を表示することが出来ます。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
uvで作る場合、通常.venv/pyvenv.cfgにprompt = ...
という行が追加されそこにプロジェクト名があるのでそれを使っています。
また、ちょっと手動で仮想環境を作ってactivateしたとか、直接activateした場合、プロンプトが設定されるので重複してしまいますが、
その場合にはVIRTUAL_ENV_PROMPT
が設定されているので、その場合は上の関よる追加は無いようにしています。
これで、my_project
というプロジェクトのディレクトリ下に入ると
1
|
|
のようにプロンプトが変更されます。
GNU screenのCaptionに仮想環境名を表示
とプロンプトに表示も出来ますが、 個人的にプロンプト部分に色々表示されて変わるのは好きではないです。
また、ターミナル作業は基本的に常にGNU screenを使っているので、 そのCaptionに仮想環境名を表示するようにしてみます。
まず、.screenrcではcaption
に%h
を含めてウィンドウのhardstatusを表示するようにしておきます。
このhardstatusは
1
|
|
のようにすることでコマンドで変更することが出来ます。
%t
でタイトルを表示できますが、こちらは
1
|
|
で変更できます。
どちらでも同じようなものなのですが、%h
の方は大概のターミナルアプリ自体のタイトルに表示されるものでもあるのでそちらへも表示できるよう%h
を使うことにします。
逆に%h
は全体のhardstatus
の設定の方にいれておきます。
こちらには全ウィンドウの情報が表示されるようにするのでなるべく情報は少ないほうが良いので。
これを使って、.bashrcとかに以下のような設定を追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
.screenrcの関連部分は以下のようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
これで、環境外だと
環境内に入ると
といった感じにウィンドウのCaption部分に仮想環境名が表示されるようになります。
-
uv run env
とするとプロジェクトのディレクトリ下ならVIRTUAL_ENV
が設定されているのでそれを使って判定することがある程度は可能です。uv run echo $VIRTUAL_ENV
だとuv run env
にVIRTUAL_ENV
が設定されている場合も何も表示されません。 これだとuv run
の前に今の$VIRTUAL_ENV
が展開されてしまうからの模様。uv run eval ...
のようにすると1 2
error: Failed to spawn: `eval` Caused by: No such file or directory (os error 2)
とエラーになってしまいます。
なので
uv run env
で全環境変数を取得して、その中にVIRTUAL_ENV
があるかどうかを判定します。VIRTUAL_ENV
があり、かつPATH
に$VIRTUAL_ENV/bin
がない場合は追加する、逆にuv run env
にVIRTUAL_ENV
がない場合は外す、など。. .venv/bin/activate
していた場合はディレクトリ関係なく常にVIRTUAL_ENV
が設定される状態になります。 なのでこの場合は上の設定を入れてもプロジェクト外に出てもそのままactivateされたまま残ります。(普通にactivateしたときと同じ)uv run $SHELL
したときも常にVIRTUAL_ENV
が設定されるので常時PATHが通った状態を保つことになります。そんな感じで一応できそうですが、ちょっとしたシェルスクリプトでも おそらくmiseの方が高速にやってくれるだろうと思います。 ↩