メインコンテンツへスキップ

uvでPythonスクリプトが自己完結!?環境構築の手間を省く裏技

·3 分
2025/03 Python Uv 仮想環境 パッケージ管理 スクリプト

uvでPythonスクリプトが自己完結!?環境構築の手間を省く裏技

引用元:https://news.ycombinator.com/item?id=43519669

stared 2025-03-30T09:39:33

UVに限らず、コメント欄でコードの実行をコントロールするのってマジ勘弁って感じ😅。リンターとか開発者向けのメモは全然ありだけど、設定とか実行に関わるデータはもっと良い方法があると思うんだよね。

例えばこんな感じ。
UV_ENV = {
”dependencies”: { ”requests”: ”2.32.3”, ”pandas”: ”2.2.3” }
}

これなら、Pythonの文法として正しいし、標準的なデータ構造を使ってるから解析も楽ちん。それに、コメントを全部消してもコードがちゃんと動くっていう原則にもちゃんと従ってるのが良いよね👍

gorgoiler 2025-03-30T10:49:57

めっちゃ同意だけど、もう一歩踏み込んで考えるなら、それって結局ランタイムでは何もしてないマジック定数じゃん?UVが解析する為だけにあるみたいな。他のツールが未使用コードとして消しちゃう可能性もあるし。それって、マジックコメントと大差ない気がするんだよね🤔。

だったら、UVに直接指示を出せば良くない?
import uv

uv.exec(
dependencies=[“clown”],
python=“>=3.10”,
)

from clown import nose

最初の呼び出しは、uvパッケージを見つけられるPythonでOK。uvパッケージがvenvを設定して、環境変数とかでフラグ立てて再実行する感じ。
2回目の実行では、uv.execはフラグを検知して何もしない、みたいな。

hanikesn 2025-03-30T11:01:32

それにはちゃんと理由があるみたいだよ。
>https://peps.python.org/pep-0723/#why-not-use-possibly-restr…

gorgoiler 2025-03-30T11:48:10

リンクありがとね😊。PEPの主張に対する反論としては、(1)Pythonを実行しようとしてるんだから、Pythonパーサーは手元にあるはずだし、(2)当面は過去のバージョンのPythonも解析できるはず、ってことかな。まぁ、ちょっと強引な気もするけどね。依存関係と実際のコードで言語を分けるのは、長期的な安定性には役立つかもね。

atoav 2025-03-30T12:56:29

それって結局、PythonがUVを実行することになるってことでしょ?開発の観点から色々な影響がありそうじゃん?理論的にはそれが一番クリーンな方法だと思うけど、shebangもコメントみたいなもんだし、ここでドグマティックになる価値があるのかは微妙だよね🤔

stared 2025-03-30T12:48:26

その議論には賛成できないな🙅。JSON形式に限定すれば、アドホックな構文よりもずっとメンテナンスしやすいし、拡張性も高いと思うよ。最初は管理しやすくても、徐々に解析が複雑になっていくのは避けたいじゃん。

skeledrew 2025-03-30T13:52:21

UVの正当性のひとつは、Pythonに依存しないからブートストラップ問題がないってことだよね。現状、UVを使うには「UVのサイトからインストールコマンドを取得して実行(まだインストールしてない場合)。UVでスクリプトを実行。」の2ステップで完了する。これ以上シンプルにはできないでしょ。UVをインポート可能にするってことは、Pythonがすべてのシステムに簡単にインストールできる前提になるから、それならUVは必要なくなるよね。

loloquwowndueo 2025-03-30T13:42:17

それだと、本来UVに依存しなかったコードがUVに依存することになるよね。スクリプトのコメントに依存関係を示す仕様はPEP723で、ツールに依存しないんだよ。

nickpsecurity 2025-03-30T12:42:15

>”In your case that’s uv doing the parsing but another tool might delete it as unused code.”
それが狙いだよ。特定のツールのためだけにあるんだから。使われなかったら、実行中のアプリに影響を与えないようにしたい。コメントと同じだね。

simonw 2025-03-30T11:59:32

だって、UVをインストールしてないとコードが動かなくなっちゃうじゃん。

Retr0id 2025-03-30T13:38:16

Pythonのバージョンによって文法が違うから、新しい構文だと古いPythonじゃ最初の数行すら実行できないかもね。例えばPython3.6でprint(”hello”) match 123: case _: passってやると、”hello”すら表示されないよ。

Retr0id 2025-03-30T18:16:56

>”自己完結型”スクリプトの肝は、どこでも動くこと。 uv は専用の cpython runtime を使うけど、uv の起動前にスクリプトが実行されると、それが台無し。
記事のテクニックなら、古い Ubuntu LTS 環境でも最新 Python のスクリプトが動くけど、GP のやり方じゃダメ。

dagw 2025-03-30T13:14:01

代わりに、uv に何をすべきか指示する呼び出しを作ったらどう?
大事なのは、これが uv 特有の機能じゃないってこと。 将来的には他のパッケージマネージャーも実装する Python の標準機能になる予定。 だから、どんな解決策も uv だけでなく、標準に準拠したパッケージマネージャー全てで動作する必要がある。

sorenjan 2025-03-30T10:13:57

これは uv の発明じゃなくて、uv は他のツールと同じように標準の PEP 723 を使ってるだけだよ。 https://peps.python.org/pep-0723/

stared 2025-03-30T14:43:19

前に言ったように、uv への批判じゃなくて、この全体的なアプローチへの批判だよ。

JimDabell 2025-03-30T12:30:47

それもそうだね。 命令的なコードを解析・評価するより、最小限の権限の原則に従って宣言的なデータにする方が、柔軟性があると思う。
コメントを使うのは、そもそも shebang 行と同じ。 45年も経つから、みんなシェルコメントだって気づかないだけ。

wavemode 2025-03-30T15:50:30

>コードからコメントを全部消しても、依存関係をちゃんとインストールすれば、挙動は変わらないはず
その通り。 コード自体の意味は変わらない。コードが動く環境が変わるだけ。 それはシェルの先頭にある#!/bin/bashコメントと変わらない。

petters 2025-03-30T10:08:01

完全に同意。 こういうのが標準化されると良いな。
問題は、uv は依存関係を見つけるために何も実行したくないから、かなり制限された Python のサブセットになる必要があるってこと。
そもそも、これが求められてるってことは、言語の弱点を示してる。 import 文自体が依存関係の情報を全部伝えるべき。

SAI_Peregrinus 2025-03-30T16:44:43

UV は PEP 723[1] を実装しただけ。 これは PyPA Inline Script Metadata[2] になった。 もはや仮のものではなく、標準化されたんだ! Python に、コメントじゃない方法でこの機能を提供する方法がなかったのは残念。 [1] https://peps.python.org/pep-0723/ [2] https://packaging.python.org/en/latest/specifications/inline

pedrosorio 2025-03-30T15:45:28

そもそもこれが必要なこと自体が、言語の弱点を浮き彫りにしてるよね。import文自体に依存関係に関するすべての情報を含めるべきじゃない?どの言語がスクリプトのimport文で依存関係のバージョンを伝えてるの?

もっとコメントを表示(1)
stared 2025-03-30T11:31:58

import文の前に、有効な静的構造であることを指定できるってこと。

nemetroid 2025-03-30T12:14:46

future statementsとか他のimportの間に入れるってこと?

Svoka 2025-03-30T13:38:45

だいたい賛成だけど、それってshebangを文字通り使ってるよね。

bityard 2025-03-30T13:43:53

これ、ここ数ヶ月のHNでめっちゃ話題になってるよね。最近の例だと、
https://news.ycombinator.com/item?id=43500124
https://news.ycombinator.com/item?id=42463975
uvは好きだけど、”自己完結型”って主張には異論があるんだ。
1) スクリプトはuvが既にインストールされてることを前提としてる。最悪、uvがインストールされてるかチェックして、されてなかったらcurlpipeでインストールするシェルスクリプトにすることもできるけど…ボイラープレートが増えるし、curlpipeパターン自体が微妙じゃん?
2) ホームディレクトリにvenvを自動作成するのも、自己完結型とは言えない。使い捨てスクリプトを実行して削除しても、venvは残って容量を食う。一時的な仮想環境が自動的にクリーンアップされるって記述もuvのドキュメントに見当たらないし。

networked 2025-03-30T14:23:39

そうだよね、uvをインストールする必要があるし、インストールされてなかったら手動かcurl | shでインストールする必要があるかも。
これは妥当な不満だと思う。
パッケージマネージャーがuvをリポジトリに含めるようになれば、問題は少なくなるかもね。
例えば、uvは既にAlpine LinuxHomebrewで利用可能だよ。
https://repology.org/project/uv/versions
あと、インラインスクリプトのメタデータはPythonの標準だよ。
uvがシステムにない、パッケージ化もされてないけど、スクリプトに適したバージョンのPythonがある場合は、pipxでスクリプトを実行できるよ。
https://pipx.pypa.io/stable/examples/#pipx-run-examples
pipxはもっと広くパッケージ化されてる。
https://repology.org/project/pipx/versions

Gud 2025-03-30T19:49:57

curl | shはマジで嫌なやり方だから絶対に使っちゃダメ。

Myrmornis 2025-03-31T02:17:30

Dockerfileでは便利で適切な場合も多いよ。

tempaccount420 2025-03-30T21:43:07

そうじゃなかったら、10種類のディストリビューションすべてがプログラムをパッケージ化して、それが更新されるのを気長に待つしかないじゃん。

sgarland 2025-03-31T14:39:12

いやいや、自分でパッケージングして署名キー付きで配布する方が良くない?.debとか.rpm作れば、エンドユーザーの大部分カバーできるじゃん。

tempaccount420 2025-03-31T15:31:12

それって現状より悪くない?開発者の多くはArch LinuxとかNixOSとか、一般の人にはマイナーなディストリ使ってるし。作者が持ってるドメインのHTTPSリンクからcurl | shするより、署名キー付きの.deb/.rpmの方がなんで良いの?.deb/.rpmだって任意のシェルコマンド含んでるじゃん。

sgarland 2025-03-31T18:26:34

もしシェルスクリプトにキー検証が組み込まれてたら、出所検証の観点からは大差ないかもね。でもそれってレアじゃん?それに、OSのパッケージマネージャー使えば、アンインストールがめっちゃ簡単。

dagw 2025-03-31T11:38:19

俺は10個もOS/ディストリ使ってないけど、俺のツールの潜在的なユーザー全体で見れば、10個以上なんて余裕でありえる。

photonthug 2025-03-30T13:59:38

docker+uvで同じような問題を解決しようとしたけど、なんとなくできたよ。ランダムな開発環境だとuvよりdockerの方が一般的だからね(特にtfaがgong projectだって言ってるし)。
これ動くけど、何もキャッシュしないから毎回ダウンロードするのが面倒なんだよね。ボリューム使えば直せるかも?
>https://hugojosefson.github.io/docker-shebang/#python

krupan 2025-03-30T17:47:52

普通、プログラムを実行する前に何かインストールする必要があるよね。だからuvをインストールするのも、そんなに悪いことじゃないと思うな。でも、プログラムを実行する時にインターネットから色々ダウンロードするから、これって自己完結型とは言えないよね!
俺にとって、完全な自己完結型ってAppImageみたいなもの。

dazzawazza 2025-03-30T14:22:53

100%同意。py2exeみたいなものを使うと、自己完結型の“pythonスクリプト”が作れる。開発者にとっては問題が多いけど、ユーザーにとっては問題が少ない。

gcr 2025-03-30T17:02:31

細かいことだけど、uvのパッケージの重複排除機能のおかげで、仮想環境は固有の依存関係がない限り容量を消費しない。

benhurmarcel 2025-03-30T13:47:09

>uvのドキュメントには、一時的な仮想環境が自動的にクリーンアップされるという記述が見当たらない。
それは良い指摘だね。少なくとも、スクリプトを何回か実行したら再利用されるのかな。

maxed 2025-03-30T15:46:15

詳しく見てみたんだけど、uvは必要なパッケージをキャッシュディレクトリ(~/.cache/uv)にインストールしてるみたい(まだそこになければ)。だから、uv clearとかでキャッシュを消さない限りパッケージは残るんじゃないかな。venvディレクトリを新しく作るわけじゃなくて、uvはパッケージを中央の場所にリンクさせて、既にあれば再利用するっぽいね。

dagw 2025-03-30T13:52:58

たぶん、uvはvenvを作るときにスクリプト名、Pythonのバージョン、依存関係のハッシュを作るんだと思う。だから、どれも変わらなければvenvを再利用するんじゃないかな。

kissgyorgy 2025-03-30T06:50:53

Nixでも同じことやってるよ。shebang行はこんな感じ:
#! nix-shell -i python3 -p ”python312.withPackages (pkgs: [ pkgs.boto3 pkgs.click ])”
これで、必要なのはシステムにNixが入ってることだけ。PythonすらインストールされてなくてもOK!

もっとコメントを表示(2)
skowalak 2025-03-30T11:24:44

それはそうだけど、PyPIパッケージにはまだnixpkgsでパッケージ化されてないものもたくさんあるから、uvほど万能なアプローチではないよね。

falcor84 2025-03-30T12:21:45

> you don’t even need Python to be installed!
TFAの場合もまさにそうで、uvがPythonのインストールをその場で行ってくれる。

skavi 2025-03-30T08:27:12

うん、同じテクニックはどの言語にも使えるよ。一番わかりやすいのはbashで依存関係を全部指定するやつだけど、nix shebangを使ってRustのシングルファイルスクリプトをハックしたこともある。
https://nixos.wiki/wiki/Nix-shell_shebang

Tractor8626 2025-03-30T12:53:25

Nihをインストールする方が、uvをインストールするよりもずっと大変だよ。

maleldil 2025-03-30T19:35:40

Nixはセットアップと理解にいろいろ必要。uvはPATHにあるバイナリだけ。

execat 2025-03-30T11:19:07

nix shell(flakeベースのコマンド)でnix-shellの代わりに同じことをするにはどうすればいいの?

skavi 2025-03-31T07:48:35

それ、ちょっぴり面倒なんだよねー。詳しくはこのリンク見てみて!
https://nix.dev/manual/nix/2.22/command-ref/new-cli/nix3-she

skeledrew 2025-03-30T13:59:02

もしかして #! /usr/bin/env -S nix shell って手もあるかも?

bheadmaster 2025-03-31T09:49:56

他のコメントにもあるように、“自己完結型”って言うにはuvがインストールされてる前提じゃん?
マジで自己完結させたいなら、Nuitkaコンパイラがおすすめだよ[0]。プロダクション環境のgRPCサービスで使ってるけど問題なし! ”nuitka –onefile run.py”でOK。マジ卍。コンパイラだから、Pyinstallerより速いし。
作者のGitHub[1]には「最高のPythonコンパイラを作るのが俺の使命!」って書いてあるよ。
[0] https://nuitka.net/
[1] https://github.com/kayhayen

tiltowait 2025-03-30T05:26:31

このパターン、マジで好きなんだけど、LSP (pyright, in Helix) で動かすのがマジ無理ゲー。uv経由でエディタ起動してもダメだった (uv run hx script.py)。
uv run --with 必要なやつ hx script.py とかできるけど、めんどくさすぎ。

mayli 2025-03-30T07:35:18

俺の自作uveスクリプト、マジ汚いけど晒すわ。
bash
$ cat ~/.local/bin/uve
#!/bin/bash
temp=$(mktemp)
uv export –script $1 –no-hashes > $temp
uv run –with-requirements $temp vim $1
unlink $temp

エディタがuv python find --scriptに対応してくれたら最高。

Galanwe 2025-03-30T11:25:34

trap .. EXIT 使ってunlinkみたいな処理を遅延させるの、マジ便利だよ。スクリプトが途中で止まってもちゃんと動くし。

lioeters 2025-03-30T13:17:35

なるほど、こんな感じ?
temp=$(mktemp)
trap 'unlink $temp' EXIT
# Do things

Galanwe 2025-03-30T13:37:14

そーそー。cleanup処理が複雑なら関数にしてもOK。

icameron 2025-03-30T04:46:54

これマジ使える!uvってPythonプロジェクトのデプロイで長期的にも安全な選択肢?昔anacondaで痛い目見たから心配なんだよねー。5年くらい前に依存関係管理に使ってたんだけど、ルール変わって従業員200人以上の企業は有料になっちゃったんだよね。

godelski 2025-03-30T05:55:28

uvはMITかApache-2.0ライセンスだよ[0]。開発が止まったり、ライセンスが変わったりする可能性はあるけど、過去のバージョンはオープンソースが保証されてる。心配ならフォークして同期すればOK。でも、他のOSSプロジェクトも同じだし、気にしすぎないで良いと思うよ。condaは元々オープンソースじゃなかったし、バイナリ配布だったはず。
[0] https://github.com/astral-sh/uv?tab=readme-ov-file#license

globular-toast 2025-03-30T09:17:51

オープンソースだからってメンテされるとは限らないよね。uvはRustで書かれてるってのがちょっと特殊。Pythonに興味あるRustの開発者がアクティブにいるかにかかってるってことじゃん?
PyPI使ってるから、パッケージ管理とか開発ツールとしては使ってもいいかな。最悪pipとかに戻ればいいし。でも、パッケージのランタイム依存としては使わないかな。それにはpyinstaller使う。
こういうのって、開発者がリポジトリで使うユーティリティスクリプト向けだと思う。個人のユーティリティをuvに縛り付けたくないし。依存関係が必要ならパッケージ作る方が楽だしね。

skeledrew 2025-03-30T14:04:32

マジですごいのは、インラインメタデータの形式がPEPで認められてるってこと。だから、uvがダメになっても、他のツールでサポートできる可能性があるってことだね。

scarlehoff 2025-03-30T06:30:20

anacondaの件はリポジトリの引き上げでしょ(conda-forgeのパッケージは今でも無料で使える)。
uvはpypi使ってるだけだから、uvからpipとかpoetryに変えるだけ。パッケージは全部同じところから来るし。

01HNNWZ0MV43FF 2025-03-30T05:21:12

俺の理解だと、プロジェクトがContributor Licensing Agreement(CLA)を結んでる場合、著作権をプロジェクトのオーナーに譲渡することになるから、ライセンスの変更が可能になるんだよね。(最終的には、考えうる限り最悪の金持ちに買収される運命)。
uvのコントリビューションガイドとかissuesを覗いてみたけど、CLAは見当たらなかった。PyTorchでは、コントリビューションガイドの冒頭にCLAの記載があったよ。
あと、Anacondaの最後のFOSSバージョンのコミュニティフォークがあっても良かったはず。Redisではそうだったし、RedisはCLA使ってるし。
https://github.com/redis/redis/blob/unstable/CONTRIBUTING.md
みんな、絶対にCLAにサインしちゃダメだよ。どうせなら、コピーレフトプロジェクトに貢献しようぜ。ただ働きするには給料高すぎるって。

もっとコメントを表示(3)
throwaway48476 2025-03-30T08:12:06

CLAが無いとライセンス変更はできないけど、オープンソースライセンスってそもそも取り消せないじゃん。

hansvm 2025-03-30T15:10:46

それって法廷でほとんど試されてないんだよね。最近の判決では、少なくともOSSには対価性があるから、正当な理由なしに一方的に終了することはできないってことになってるけど、USCにはその正当化事由が規定されてる(ただし、2~10年の事前通知とか、特定の期間内に行う必要があるとか、厄介な要件がある)、取り消し不能って書いてあるライセンスでも。

holysoles 2025-03-30T04:04:02

これって、小さいユーティリティをコンテナ化する代わりに使うには良いパッケージングの選択肢になりそうだね。同僚全員にuvをインストールさせるように説得しなきゃ。

throwaway48476 2025-03-30T07:50:57

Uvはマジで速いよ。それが後押しになるはず。

tiltowait 2025-03-30T05:24:02

俺たちにとっての問題は、SCAの脆弱性スキャナがまだuvに対応してないってことなんだよね。

cmgbhm 2025-03-30T12:51:03

uvの依存関係をrequirements.txtとしてエクスポートする中間SCAステージを追加すればいいんじゃない?

mos_6502 2025-03-30T14:57:01

これってRubyのbundler/inlineみたいなもんかな?[1] Pythonで同じようなのが出てきて嬉しいなー。めっちゃ便利そう!
[1] https://bundler.io/guides/bundler_in_a_single_file_ruby_scri

dharmab 2025-03-30T04:04:55

誰かこれWindowsで動かせた人いる?ゲームMOD用のツールで使いたかったんだけど、shebangのトリックがうまくいかなくてさ。

quickslowdown 2025-03-30T04:47:37

WindowsとLinuxでよく使ってるよー。手順はこんな感じ:
>uv init –script <script_name>.py
>uv add –script <script_name>.py
>uv add –script <script_name>.py –dev <dev_pkg1> <dev_pkg2> …
>uv run <script_name>.py
参考になるといいな!
Source: https://docs.astral.sh/uv/guides/scripts/

networked 2025-03-30T13:56:40

残念ながら、uv add --dev--scriptと一緒には使えないみたい:
>uv -V
uv 0.6.10
>uv add –script foo.py –dev ruff
エラーが出るんだよね。
Pythonのインラインスクリプトのメタデータは、開発依存関係を標準化してないみたい。pyproject.tomlで開発環境を整える方法について最近コメントしたから見てみて! https://news.ycombinator.com/item?id=43503171

quickslowdown 2025-03-30T15:20:41

–debフラグがスクリプトで使えないのは興味深いね。記憶だけで書いちゃったけど、スクリプトに開発依存関係をインストールした気がしてた。ただの勘違いだったみたい。訂正ありがとう。

mixmastamyk 2025-03-30T16:50:24

ちょっと脱線するけど、シェルの例では山括弧は避けるべきだよ。間違って入力しちゃうと全部パーになっちゃうからね。

sorenjan 2025-03-30T10:26:28

Windowsの通常のCPythonインストーラーはpy launcherをインストールして、.pyファイルに関連付けるんだよね。py launcherはshebang行をサポートしてる。
数日前に同じトピックのブログ記事が投稿されてたよ。それによると-Sは省略しないといけないみたい。試してないけど、.pyファイルをuv runで開くようにファイル関連付けを変更したよ。参考:https://thisdavej.com/share-python-scripts-like-a-pro-uv-and… https://news.ycombinator.com/item?id=43500124 https://docs.python.org/3/using/windows.html#python-launcherhttps://peps.python.org/pep-0397/

dharmab 2025-03-30T17:06:47

へー、面白いね。俺が使ってるワークフローはCPythonインストーラーをスキップしてuvだけ使ってるよ。

sorenjan 2025-03-30T20:49:53

Windowsはshebang行をサポートしてないと思うけど、uvを.pyファイルに関連付ければ同じ結果になるよ。こんな感じかな:
ftype Python.File=C:¥Path¥to¥uv.exe run %L %*
CPythonインストーラーを使ってない場合はPython.Fileファイルタイプが定義されてないかもしれないから、assocで設定する必要があるかも:
assoc .py=Python.File

magicalhippo 2025-03-30T04:35:50

でも拡張ハンドラーの登録はサポートしてるみたいだよ[1]。だから、スクリプトに例えば.pyuvって名前を付けて、”.pyuv”ファイルのハンドラーとして“uv run –script %1”とか、uvを実行するのに必要なものを登録すれば、うまくいくんじゃないかな。uvが変なことしてなければ。
インストール段階でこれをやるとか。
[1]:https://learn.microsoft.com/en-us/windows/win32/shell/fa-fil…

dlachausse 2025-03-30T04:20:36

PyInstallerみたいなのを使うのもアリだよ。
https://pyinstaller.org

gus_massa 2025-03-30T15:03:58

役に立つかわかんないけど、誰かがRacketで同じようなことをPoweScriptでやる方法を投稿してたよ。

https://onor.io/2025/01/more-scripting-with-racket.html

skeledrew 2025-03-30T14:08:01

WSLからならShebangはちゃんと動くはず。

yallpendantools 2025-03-30T16:49:45

このユースケースのおかげでuvを好きになったんだけど、公式の(しかも、めっちゃ役立つ!) PEPが公式のPythonツールでサポートされてないのは、PythonのZenに反してると思うんだよね。
Pythonが“batteries included”じゃなかったのは初めてだよ。
今では、システムに二つのPython依存性マネージャーがあるし。Pythonの依存性管理については語るべきことが山ほどあるのは知ってるけど、requirements.txtがある限り、pip+venvで何年もやってこれたんだ。

記事一覧へ

海外テックの反応まとめ
著者
海外テックの反応まとめ
暇つぶしがてらに読むだけで海外のテックニュースに詳しくなれるまとめサイトです。