uv addでアプリの依存パッケージを入れたのに、uvx pytestではModuleNotFoundErrorになる。その場合は、まずpyproject.tomlがあるプロジェクトルートでpytestを開発依存に追加し、プロジェクト環境から実行します。
uv add --dev pytest
uv run -m pytestuv run pytestでもプロジェクトの.venvを使います。この記事では、なぜuvxだけでimportに失敗することがあるのかと、-mの意味を混同せずに整理します。
原因はpytestではなく、実行環境が分かれていること
uvxはuv tool runの別名です。uv公式のToolsでは、ツールを一時的な仮想環境に入れ、現在のプロジェクトから隔離して実行すると説明されています。そのため、プロジェクトの.venvにある依存パッケージは、uvx pytestの環境へ自動では共有されません。
一方、uv runはプロジェクト環境を作成・更新したうえでコマンドを実行します。pytestやmypyのように、対象プロジェクトやその依存へアクセスする必要があるツールについて、uv公式もuvxではなくuv runを案内しています。
| コマンド | 使う環境 | プロジェクト依存 |
|---|---|---|
uvx pytest | 隔離されたtool環境 | .venvから自動共有されない |
uv run pytest | プロジェクトの.venv | pyproject.tomlの宣言を利用 |
uv run -m pytest | プロジェクトの.venv | 同上。さらにPythonの-mでpytestを起動 |
正しい設定手順
既存プロジェクトではpytestだけを開発依存へ追加する
pyproject.tomlがすでにあるなら、uv initをやり直す必要はありません。プロジェクトルートで次を実行します。
uv add --dev pytest
uv run -m pytestアプリ本体が使うパッケージも、グローバル環境へ入れるのではなくプロジェクト依存として宣言します。たとえばidnaが実行時に必要なら次の形です。
uv add idna==3.10uv公式の依存関係管理によると、通常のuv addは依存をproject.dependenciesへ追加し、uv add --devは開発用のdevグループへ追加します。uv runでは既定でdevグループも環境へ含まれます。
空のフォルダーから最小再現する
動作を切り分けたい場合だけ、新しい空フォルダーで次を実行します。既存プロジェクトに対してこの初期化手順は不要です。
mkdir uvx-pytest-demo
cd uvx-pytest-demo
uv init
uv add idna==3.10
uv add --dev pytesttest_dependency.pyを作り、次の内容を保存します。
import idna
def test_dependency():
assert idna.encode("example.com") == b"example.com"続けて、隔離ツール環境とプロジェクト環境を比較します。
uvx pytest -q
uv run -m pytest -q
uv run pytest -q編集側の再現では、Windows、uv 0.13.0、CPython 3.13.7、pytest 9.1.1、idna 3.10を使用しました。uv tool run pytest -qはテスト収集時に次のエラーとなり、終了コードは2でした。uvxはuv tool runと同じ動作なので、同じ隔離の問題を確認できます。
ModuleNotFoundError: No module named 'idna'同じ条件でuv run -m pytest -qとuv run pytest -qは、どちらも1 passedでした。ツール側とプロジェクト側のPythonはともに3.13.7へそろえているため、この再現での差はPython版ではなく、idnaを持つ環境を使ったかどうかです。実行時間は環境やキャッシュの影響を受けるため、性能差の根拠にはしません。
プロジェクト環境を直接確認するには、次のようにPythonの場所と依存の版を表示できます。編集側の再現では、プロジェクトの.venv配下のPythonと3.10が表示されました。
uv run python -c "import sys, idna; print(sys.executable); print(idna.__version__)"
uv runへの変更と-mの効果は別
今回の中心的な修正は、uvxからuv runへ変えてプロジェクト環境を使うことです。-mは依存パッケージを隔離ツール環境へ追加する機能ではありません。
pytest公式によると、pytestコマンドとpython -m pytestの主な違いは、後者が現在のディレクトリをsys.pathへ追加する点です。uvのuv run -mはpython -m相当であり、このPython標準の起動方法をプロジェクト環境内で使います。
uv run:どの環境で動かすかを決める-m pytest:そのPythonでpytestモジュールをどう起動するかを決める
したがって、uv run pytestでもプロジェクト依存は利用できます。一方、現在ディレクトリをimport探索に含めたいケースでは、uv run -m pytestとの差が表れることがあります。
uvx pytestですべて失敗するわけではない
uvxを使うと必ず全テストが失敗する、という説明は正確ではありません。uv公式のツールガイドも、srcディレクトリを使わない単純なflat layoutでは、プロジェクト自体のインストールが不要なためuvxで動く場合があると説明しています。
この記事で扱っているのは、project.dependenciesに宣言した第三者パッケージがプロジェクトの.venvにはある一方、隔離されたtool環境にはなく、テスト収集時にimportできないケースです。
uv run -m pytestでも直らないとき
実行環境を直してもエラーが残るなら、次の別原因を順に確認します。
- 依存宣言漏れ:
uv run python -c "import パッケージ名"でも失敗するなら、そのパッケージがproject.dependenciesなど適切な依存グループに入っているか確認します。 srcレイアウトの自作パッケージが未インストール:src/your_packageをimportする構成では、プロジェクトがパッケージとして環境へ入る設定になっているか確認します。- 同名ファイルによる隠蔽:
pytest.py、idna.py、または依存パッケージと同名のフォルダーがプロジェクト内にないか確認します。 - 違う場所から実行:
pyproject.tomlのあるプロジェクトルートで実行しているか確認します。
PYTHONPATHの無条件追加、グローバルなpip install、uv cache cleanを最初の修正にはしません。前二者は依存宣言の不備を隠しやすく、uv cache cleanで隔離tool環境を削除しても次回は自動作成されるため、プロジェクト依存が共有されない原因は直りません。まずuv runで正しいプロジェクト環境を使い、そこでimportできるかを確かめるのが近道です。
まとめ
uv addした依存を使うpytestは、原則としてプロジェクトルートからuv run -m pytestで実行します。uv run pytestも同じプロジェクト環境を使います。uvx pytestは便利ですが、隔離されたツール環境で動くため、プロジェクトの.venvにある依存を当然には参照できません。
公式資料
仕様確認日:2026年10月16日


コメント