npm感覚でPython環境を構築!非PythonエンジニアがuvでPythonプロジェクト(Talk to the City)を動かす
uv を使った Python のパッケージ依存関係の解決方法を解説していきます。
業務やプライベートで扱う言語は Node.js がメインで、普段は npm や pnpm を使ってライブラリの依存関係を解決しています。
そんな私がある機会でTalk to the Cityを検証して欲しいと頼まれました。
Talk to the City は 2024 年の東京都知事選挙で安野たかひろ氏のチームが使ったことで注目された Python プロジェクトです。
Python の開発環境を作って README 通りに動作させてやれば良いかと進めていったところで絶望しました。
DevContainer を用いてクリーンな Python の実行環境を用意して試したのですが、2025 年 3 月 19 日現在、デモ通り動かしてもエラーが発生します。
ImportError: cannot import name 'cached_download' from 'huggingface_hub' (/workspaces/talk-to-the-city-reports/scatter/venv/lib/python3.10/site-packages/huggingface_hub/__init__.py)
エラーログの最終行にこの記述があり、どうやらbertopic==0.15.0
かsentence-transformers==2.2.2
のどちらかが、requirements.txt
に記載の無いhuggingface_hub
パッケージの新しめのバージョンを参照し、既に削除されたメソッドを使用しているようです。
上記の再現手順
git clone https://github.com/AIObjectives/talk-to-the-city-reports.git
VS Code で/scatter
をワークスペースとして開き、コマンドパレットから開発コンテナー: コンテナーでリビルドして再度開く Dev Containers: Rebuild and Reopen in Container
を実行して、Python3.11-bullseye のテンプレートを選択して DevContainer を作成
https://github.com/AIObjectives/talk-to-the-city-reports/blob/main/scatter/pipeline/inputs/example-polis.csv から csv ファイルを手動でダウンロードして/scatter/pipeline/inputs
に入れる。(Git LFS を使うのがめんどくさかったため)
DevContainer でターミナルを開き以下を実行
# 環境の用意
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python -c "import nltk; nltk.download('stopwords')"
cd pipeline
OPENAI_API_KEY='OPEN_AIのAPIキー' && python main.py configs/example-polis.json
依存関係の解決(requirements.txt
)は、現時点(2025 年 3 月 19 日)から見ると 2 年前がラストコミットです。LLM 分野のパッケージは更新が非常に早いでしょうから、動かなくなるのも仕方ありません。
uv を使って Python の実行環境をまるっと設定する
ここまでやってきて Python プロジェクトのめんどくさい点は、requirements.txt
を使ったパッケージ解決の部分と、その元となる実行環境を整える部分にあると思います。
また、最初の例では、DevContainer を用意しましたが、これぐらいの動作検証だったら大げさに仮想環境を立てることなく使用しているホストマシン(自分の場合は Mac)から直接 Python を実行したいです。
したいですが...
Python ではパッケージ管理を行うpip
が依存をローカルにインストールする機能を持っていないため狙った環境を揃えるのも一苦労です。
デフォルトで Python がvenv
を使用し、pip をローカルに扱える仮想環境を用意してくれています。
しかし、それだけでは Python のバージョンを切り替えることはできません。
また、いちいちプログラムを実行するために仮想環境に入らなければいけないのは普段は Node.js を使ってローカルから直に開発している身としては大変に感じます。
そこで、uv という最近、市民権を得ている Python のパッケージマネージャーがオススメです。
現在話題の AI エージェントツール、OpenManus のインストールでも uv が推奨されているほどには市民権を得ています。
uv を使えば、Python バイナリも uv がマシンに合わせて適切に落としてきてくれますし、pyproject.toml
でバージョンを指定して切り替えることもできます。
また、npm の出力するpackage-lock.json
のようにuv.lock
という依存関係を全て明記したファイルも生成してくれるので、今回のような依存関係で時間が経って実行できないという体験も少なくなるでしょう。
uv は、Python 本体の仮想環境(venv)やパッケージ管理ツール(pip)を内部で呼び出し、ラッパー的に操作する仕組みになっています。(たぶん)
requirements.txt から uv に移行する
Talk to the City のように uv が使われておらず既にrequirements.txt
のみでパッケージ管理がされている Python プロジェクトでしたら、新しく uv プロジェクトとしてセットアップします。
astral-sh/uv の READMEを参考に uv
コマンドを使えるようにした後に
uv init
を実行するとpyproject.toml
が生成されます。$ uv init
では、サンプル用のmain.py
が一緒に作られますが、不要であれば削除して構いません。
今回の場合は、Python3.10 の最新バージョンを使って欲しいので、pyproject.toml
を開いてrequires-python
のところを==3.10.*
のように指定します。
そして、以下のコマンドを使えば、requirements.txt
から読み取る形でpyproject.toml
のdependencies
にパッケージを転記してくれます。
uv add -r requirements.txt
[project]
name = "scatter"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = "==3.10.*"
dependencies = [
"bertopic==0.15.0",
"hdbscan==0.8.33",
"langchain==0.0.308",
"numpy==1.25.2",
"openai==0.28.1",
"pandas==2.1.1",
"path==16.7.1",
"scikit-learn==1.3.1",
"sentence-transformers==2.2.2",
"spacy==3.7.0",
"tiktoken==0.5.1",
"tqdm==4.66.1",
"umap-learn==0.5.4",
]
$ uv sync
というコマンドを実行するとホストマシンにpyconfig.toml
が使う依存をダウンロードしてきてくれます。
uv sync
これで、DevContainer で用意した環境と同じようにホストマシンでも実行できるようになりました。uv run main.py
のコマンドで uv 経由で venv の環境の中でプログラムを実行してくれます。
cd pipeline
OPENAI_API_KEY="OPEN_AIのAPIキー" uv run main.py configs/example-polis.json
uv で新しく依存関係を解決する
uv に移行はできましたが、Talk to the City の場合は参照元にしているrequirements.txt
に不備があるので DevContainer の例と同様に動きませんでした。
そこで動くかどうかは運任せになりますが、パッケージをアップデートすることにしました。
uv を使ってpyproject.toml
のdependencies
にソースコードから参照されているパッケージのみを追加して、残りの依存解決はuv.lock
に任せます。
まずは、requirements.txt
を見てプロジェクトが直接 Import しているパッケージを特定します。
ここの手順は AI にワンライナースクリプトにしてもらいました
grep -F -x -f <(find . -name '*.py' -exec grep -rhoE "^(from|import)\s+([a-zA-Z0-9_]+)" {} \; | awk '{print $2}' | cut -d'.' -f1 | sort -u) <(cut -d= -f1 requirements.txt | sed 's/-/_/g' | sort -u)
以下のパッケージがプロジェクトの.py
ファイルから直接 Import されていそうでした。
bertopic
hdbscan
langchain
numpy
openai
pandas
path
sentence_transformers
spacy
tiktoken
tqdm
pyproject.toml
のdependencies
とuv.lock
を一旦消して、これらをuv add
でこれらの依存を解決しながらインストールしてもらいます。
uv add -n bertopic hdbscan langchain numpy openai pandas path sentence_transformers spacy tiktoken tqdm
ここでまたエラーが出てしまいました。
RuntimeError: Cannot install on Python version 3.10.16; only versions >=3.6,<3.10 are supported.
とあるように Python3.10 だと依存するパッケージのビルドに失敗してしまうので、Python3.9 でトライしてみます。pyproject.toml
をrequires-python = "==3.9.*"
に変更すれば良いだけなので簡単です。
[project]
name = "scatter"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = "==3.9.*"
dependencies = []
変更後は$ uv sync
を実行してマシンにバイナリをダウンロードします。
その後、Python3.9 で$ uv run main.py configs/example-polis.json
を実行したらいくつかのエラーが出ました。
To install langchain-community run
pip install -U langchain-community
.
とエラーに出てきたので従います。
uv pip install -U langchain-community
次に
ModuleNotFoundError: No module named 'nltk'
と出てきて、Talk to the City の求めるセットアップを DevContainer に変えてから行ってなかったので行います。
uv pip install nltk
uv run python -c "import nltk; nltk.download('stopwords')"
このようにuv
コマンド越しにvenv
の仮想環境でpip
コマンドが使えるのは楽で良いです。
最終的に、$ uv run main.py configs/example-polis.json
の処理を最後まで成功させることができました。
まとめ
以上になります。
もし、「普段は Python をあまり触らないけれど、ちょっとした検証で Python プロジェクトを動かす必要がある」という方がいたら、ぜひ uv を使って環境構築をしてみてください。
(この記事のテキストは、ほぼ 100% 人間の手によって書かれています。)
Discussion
uvはRustで実装されていてPythonを直接は利用しません。uvから使えるvenvやpipコマンドはPython版と同様のインターフェースをしているだけで実際にはRustで実装されています。以下の両者は異なります。
また、理解したうえでやってらっしゃるかもしれませんが、uv add/syncとuv pipは混ぜて使用せずに基本的にはuv add/syncのみを使用するのがパッケージ管理としては正しく、npmやcargoなどと同じ挙動になります。uv pipはあくまでpipとの互換性のためだけにある機能です。
こちらの補足ありがとうございます!リンクする形で本文の方にも引用しておきますね。
こちらも補足ありがとうございます!
uvの仕組みを把握してプロジェクトを全てuv add/uv syncに移行せずとも、一時的に解決するだけならハック的に
uv pip
でpipを使った情報に沿って行えるのもPythonianでない方にuvをオススメしたくなった動機です😊。(pipと別物としてuvを学習するのではなくpipの延長線上という理解の上で操作できるインターフェースが魅力的ですね。)