🐍

uvxでポータブルなPythonアプリケーションを作る

に公開

はじめに

これは「mohikanz Advent Calendar 2025」6日目の記事です。

Pythonでアプリケーションを配布したいときの悩み

Pythonで作成したCLIツールやスクリプトを同僚などに配布したいとき、以下のような悩みに遭遇すると思います。

  • 相手の環境にPythonがインストールされているとは限らない
  • Pythonや依存ライブラリのバージョンがばらばら
  • 「まず仮想環境を構築して...」といった手順は、非エンジニアや非Pythonエンジニアには敷居が高い

こういった悩み自体はPython以外でも起こりうるものですが、Pythonにはお手軽なパッケージマネージャが標準で存在しないことが悩みを加速します。

uvとは

uvxの前に、前提となるuvというパッケージマネージャについて説明します。
詳しい説明記事は世の中にたくさんあるので、要点を掻い摘まんで説明すると、

  • Rustで記述された高速なPython向けパッケージマネージャ
  • Pythonのバージョン管理 (pyenv相当)、仮想環境管理 (venv相当)、パッケージ管理 (pip/poetry等に相当) をこれ1つで完結できる

といった特徴があります。

uvxとは

uvxはuvに含まれるサブコマンドで、単一のコマンドからPythonパッケージを実行可能なアプリケーションとして動かすための仕組みを提供します。
Node.jsのエコシステムにおけるnpxに相当するものと考えると分かりやすいかもしれません。

pipenv/poetryといった他のパッケージマネージャを使う場合と比べて、エンドユーザにPython自体の環境構築・管理を要求しないのが大きな利点です。

また、GitHub上に存在するアプリケーションを直接実行することも可能です。
uvxが実際に利用されているアプリケーションの例としてSerena MCP Serverがありますが、コードをcloneすることなく、以下のように実行することができます。

uvx --from git+https://github.com/oraios/serena serena start-mcp-server --help

ポータブルなアプリケーションの作り方

以下に、実際にuvxを用いてアプリケーションを作成する場合の例を示します。
全体のソースコードは https://github.com/kiakiraki/uvx-demo に格納されています。

プロジェクト全体は以下のように構成されています。

uvx-demo/
├── pyproject.toml          # プロジェクト設定
├── README.md               # 説明
└── uvx_demo/               # メインパッケージ
    ├── __init__.py
    └── main.py             # CLI エントリーポイント

uv自体の細かな操作方法についてはこの場では説明しませんので、必要に応じて公式ドキュメントなどを参照してください。

プロジェクト設定ファイルの作成

pyproject.toml にプロジェクト情報とエントリーポイントを定義します。

[project]
name = "uvx-demo"
version = "0.1.0"
# 依存パッケージがあればここに列挙する
dependencies = ["pyfiglet"]

[project.scripts]
uvx-demo = "uvx_demo.main:main"

ポイントは [project.scripts] です。

  • uvx-demo が「コマンド名」
  • "uvx_demo.main:main" が「実際に呼び出される関数」

これにより、uvx_demo.main モジュールの main() 関数が起動されるようになります。

パッケージ構造の作成

Pythonパッケージのディレクトリを作成します。

mkdir uvx_demo

uvx_demo/__init__.py を作成します。

"""uvx-demo: A portable Python CLI application demo using uvx."""

__version__ = "0.1.0"

メインアプリケーションの実装

uvx_demo/main.py を作成します。

"""Main CLI application for uvx-demo."""

import pyfiglet


def main() -> None:
    """Display uvx ASCII art."""
    # Generate ASCII art using pyfiglet
    ascii_art = pyfiglet.figlet_format("UVX", font="slant")
    print(ascii_art)
    print("Welcome to uvx-demo!")
    print("This is a portable Python CLI application that can be run with uvx.")


if __name__ == "__main__":
    main()

ローカルでの実行確認

アプリケーションを手元で実行してみます。

$ uv run uvx-demo

     __  ___    ___  __
    / / / / |  / / |/ /
   / / / /| | / /|   /
  / /_/ / | |/ //   |
  \____/  |___//_/|_|


  Welcome to uvx-demo!
  This is a portable Python CLI application that can be run with uvx.

uvxによる直接実行

以下のような一行でプログラムを実行できます。

uvx --from git+https://github.com/kiakiraki/uvx-demo uvx-demo

応用的な使い方

GitHub上の特定ブランチやタグを指定して実行する

uvxの--fromには、ブランチ名・タグ名・コミットハッシュを指定することができます。

uvx --from git+https://github.com/kiakiraki/uvx-demo@ブランチ名 uvx-demo
uvx --from git+https://github.com/kiakiraki/uvx-demo@タグ名 uvx-demo
uvx --from git+https://github.com/kiakiraki/uvx-demo@コミットハッシュ uvx-demo

一つのリポジトリ内に複数のコマンドを同居させる

アプリケーションがサブディレクトリに存在する場合

例えば、リポジトリ構成が以下のようになっているとします。

repo-root/
├── cli-tool/
│   ├── pyproject.toml
│   └── cli_tool/...
└── web-app/
    ├── pyproject.toml
    └── web_app/...

GitHub上のサブディレクトリを指定する場合は、以下のようにsubdirectoryオプションを利用します。

# cli-tool サブディレクトリを対象に実行
uvx --from git+https://github.com/owner/repo@main#subdirectory=cli-tool cli-command

# web-app サブディレクトリを対象に実行
uvx --from git+https://github.com/owner/repo@main#subdirectory=web-app web-command

1つのサブディレクトリに複数コマンドがある場合

以下のように、一つのディレクトリに複数のコマンドが存在するとします。

uvx-multi-app/
├── pyproject.toml
└── uvx_multi_app/
    ├── __init__.py
    ├── cli.py       # CLI 用エントリポイント
    └── web.py       # Web UI 用エントリポイント

このパターンでは、pyproject.tomlの[project.scripts]で複数スクリプトを定義します。

[project]
name = "uvx-multi-app"
version = "0.1.0"

[project.scripts]
my-cli = "uvx_multi_app.cli:main"
my-web = "uvx_multi_app.web:main"

実行時には、以下のようにコマンドを選択します。

# CLI 版を実行
uvx --from git+https://github.com/owner/uvx-multi-app my-cli

# Web UI 版を実行
uvx --from git+https://github.com/owner/uvx-multi-app my-web

まとめ

uvxを活用することで、Pythonアプリケーションの配布はとてもシンプルになります。

  • 開発者: 依存関係地獄や環境差異のサポートから解放される。
  • ユーザー: 環境構築なしで、コマンド一発でツールを利用できる。

Pythonで業務効率化ツールなどを作ったら、是非uvxを利用してみてください。

Discussion