はじめに
左下から来るぞ! nikkieです。
このブログでたびたび取り上げているPythonのinline script metadata。
今回はuvのドキュメントを読みます
目次
inline script metadata
PEP 723で提案・採択された、Pythonスクリプトに書けるコメントです1。
# /// script # dependencies = ["httpx", "rich"] # /// import httpx from rich.pretty import pprint resp = httpx.get("https://peps.python.org/api/peps.json") data = resp.json() pprint([(k, v["title"]) for k, v in data.items()][:10])
PEP 723をサポートしているuvやpipxといったツールでこのスクリプトを実行すると、ツールが仮想環境を用意して有効化し、依存ライブラリをインストールしてからスクリプトを実行してくれます。
自動化が好きでPythonスクリプトを頻繁に書いてきた私は、「仮想環境を人間が管理しなくていいのか!」と非常に感銘を受けました2
uvはpipxよりも積極的にPEP 723をサポートしているように見えたので、ドキュメントを読んでいきます。
% uv --version uv 0.4.12 (Homebrew 2024-09-18)
uvはinline script metadataを書いてくれる!
https://docs.astral.sh/uv/guides/scripts/#declaring-script-dependencies
touch script.py
して、中を以下のようにします。
※pyproject.tomlがなく、script.pyだけのディレクトリで動かしています3
import httpx from rich.pretty import pprint resp = httpx.get("https://peps.python.org/api/peps.json") data = resp.json() pprint([(k, v["title"]) for k, v in data.items()][:10])
inline script metadataを書いていないので、uv run
4で実行してもエラー
% uv run script.py Traceback (most recent call last): File "/.../script.py", line 1, in <module> import httpx ModuleNotFoundError: No module named 'httpx'
なんと次のコマンドで、uvがスクリプトを編集して、inline script metadataを追加してくれます!!
% uv add --script script.py httpx rich Updated `script.py`
+# /// script +# requires-python = ">=3.12" +# dependencies = [ +# "httpx", +# "rich", +# ] +# /// import httpx from rich.pretty import pprint resp = httpx.get("https://peps.python.org/api/peps.json") data = resp.json() pprint([(k, v["title"]) for k, v in data.items()][:10])
dependenciesだけでなく、requires-pythonも追加されました。
uvが生成したmetadataを編集していくというのも、十分考えられますよね
Guides「Running scripts」のメモ
気になった点をザーッと書き出します。
- Running a script with dependencies
- inline script metadataを書いていなくても、
uv run --with
で実行できる uv run --with httpx --with rich script.py
- inline script metadataを書いていなくても、
- Improving reproducibility
- PEP 723で見かけていないので、uv独自仕様と思われる
# /// script # [tool.uv] # exclude-newer = "2023-10-16T00:00:00Z" # ///
uv supports an exclude-newer field in the tool.uv section of inline script metadata to limit uv to only considering distributions released before a specific date.
意訳「特定の日付より前にリリースされた配布物だけに制限して扱わせるための、tool.uv
セクションのexclude-newer
をuvはサポートする」
思うに、実行時点で有効な依存の組み合わせでスクリプトを実行し続けるための仕組み、でしょうか
- Using different Python versions
uv run --python
- Using GUI scripts
On Windows uv will run your script ending with .pyw extension using pythonw:
終わりに
uvのGuideでinline script metadataに関係する箇所を読みました。
uvはめちゃめちゃ(一部やりすぎではと引くほどに)inline script metadataをサポートしています!
uv add --script <スクリプト.py> 依存ライブラリ ...
でinline script metadataが生えるのはとてもよさそうです!
exclude-newer
はPEP 723外に勢いよく飛び出しすぎてる気もしますが...
仮想環境を都度作ってスクリプトを書いてきた私からは、inline script metadataはとてもありがたく、ツールによるサポートも今後増えていくと期待しています。
- ドキュメント https://packaging.python.org/en/latest/specifications/inline-script-metadata/↩
- 広くPython使いに知ってほしいとPyCon JP 2024で話します ↩
-
uvがPythonプロジェクトとは認識していない状況です。なお、仮にpyproject.tomlがあっても
uv run --no-project
と指定すればよいと知りました↩ -
https://docs.astral.sh/uv/reference/cli/#uv-run より
uv run file.py
はuv run python file.py
というコマンドの実行と同じです↩