🐍

uv から始まる Python 開発環境構築

2024/08/28に公開

0. はじめに

株式会社ディー・エヌ・エーに入社し,MLOps エンジニアをやっている @a5chin です.
本記事では VS Code の Dev Container 上に uv で Python の開発環境を作成します.
CI/CD が入っていたりと,本記事で解説する内容よりもリッチな設定が以下のリポジトリに置いてあるので,ぜひ使って頂けたらと思います.
PR も大歓迎です!

https://github.com/a5chin/python-uv

0.1. 背景

2024/08/20 に Astral 社から以下のブログが発表されました.
Python のランタイム・パッケージングを uv 一つで置き換えることができるという発表でした.

Today, we're announcing a series of features that extend uv beyond a pip alternative, and into an end-to-end solution for managing Python projects, command-line tools, single-file scripts, and even Python itself.

https://astral.sh/blog/uv-unified-python-packaging

本記事では,以前に紹介した『【Rye + uv + Ruff】Docker で VS Code の Dev Container 上に快適な Python 環境を構築する』の続編で,Python パッケージツールを統一した uv を使って開発環境を整備し直していきます.
https://zenn.dev/dena/articles/rye_python_in_devcontainer

0.2. 成果物

成果物としては以前の『【Rye + uv + Ruff】Docker で VS Code の Dev Container 上に快適な Python 環境を構築する』と変わりありません.

Ruff
図 1: Dev Container 上で開発をすると Ruff による自動フォーマット[1]と pre-commit が走る

https://github.com/a5chin/python-uv/tree/main

0.3. 事前準備

本記事で作成したリポジトリを動かすためには,Docker Desktop と VS Code のダウンロード,VS Code 上で Dev Container のインストールが必要です.
また,以下コマンドでリポジトリを clone すると,今後進めやすくなるので clone することをおすすめします.

git clone https://github.com/a5chin/python-uv

0.3.1. Docker Desktop のダウンロード

https://www.docker.com/ja-jp/products/docker-desktop/

上記リンクからお使いの OS に合った Docker Desktop をダウンロードしてください↑

Docker Desktop は Mac や Windows に簡単にインストールできるアプリケーションです.
これにより,コンテナ化アプリケーションやマイクロサービスを構築し共有することができます.

0.3.2. VS Code のダウンロード

https://code.visualstudio.com/download

上記リンクからお使いの OS に合った VS Code をダウンロードしてください↑

VS Code は Microsoft 社から無償で提供されており,Windows, macOS, および Linux で使用できる,軽量ながら強力なソースコードエディターです.
拡張機能によって,全体的な機能に加えてさらに機能を追加することでより快適に開発することができます.

0.3.3. Dev Container のインストール

https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers

VS Code 上で VS Code の拡張機能である,Dev Container をインストールしてください.
VS Code 上で⇧⌘xと入力すると,サイドに Extensions が開くのでms-vscode-remote.remote-containersと入力して,出てきた拡張機能をインストールしてください.

Dev Container は Microsoft が開発している VS Code の拡張機能です.
Dev Container を使うことで,VS Code から Docker コンテナを開発環境として使用できます.

1. 結論

https://github.com/a5chin/python-uv/tree/main

Step Save commit GitHub Actions
Python Formatter (Ruff)
Python Linter (Ruff)
Docker Linter (Hadolint)
pytest
docker build

上記対応表の様に,私が設定した Dev Countainer 上で開発をすることによって,Format[1:1], Lint[2], Test[3], Build[4] を自動化しています.

1.1. 実際の操作画面

Python プログラムを保存して,git で commit した時の操作画面です.
高速でとても快適です!

Ruff
図 2: Dev Container 上で開発をすると Ruff による自動フォーマット[1:2]と pre-commit が走る

2. Docker で開発環境を整える

以下では,主に Docker について解説していきます.
Dev Container は Docker コンテナを開発環境として作成するからです.

2.1. uv を使える様にする

https://github.com/astral-sh/uv/tree/main
uv は,上記 GitHub リポジトリで Astral 社が開発している Python のプロジェクト管理ツールです.
Rust[5] で開発されているため,とても高速に動作します.

以下のフローで任意の Docker コンテナ内で uv を使える様にします.
公式イメージが新しく提供され出したので,Multi-stage Build で簡潔に書けるようなりました!

  1. uv の disstroless[6] な公式イメージから
  2. 必要なファイルをコピーする
.vscode/Dockerfile
+ FROM ghcr.io/astral-sh/uv:latest AS uv

  FROM mcr.microsoft.com/vscode/devcontainers/base:bookworm
+ COPY --from=uv --chown=vscode: /uv /uvx /bin/

2.2. プロジェクトの仮想環境を指定する

今回は Dev Container 上にプロジェクトを作成するため,明示的に /home 下を指定してパッケージをインストールします.

.devcontainer/devcontainer.json
  {
      "name": "uv",
      "build": {
          "context": "..",
          "dockerfile": "Dockerfile",
      },
      "containerEnv": {
+         "UV_PROJECT_ENVIRONMENT": "/home/vscode/.venv"
      },
  }

2.3. 開発環境のライブラリを使える様にする

以下のライブラリを .python-version で指定した Python と pyproject.toml, uv.lockで指定したパッケージを uv sync コマンド を使ってインストールします.
また,VS Code 上で自動フォーマットをしたり,エラーを表示させるために拡張機能が必要なので別途インストールします.

  • pre-commit
  • pyright
  • pytest
  • ruff
.devcontainer/devcontainer.json
  {
      "name": "uv",
      "build": {
          "context": "..",
          "dockerfile": "Dockerfile",
      },
      "customizations": {
          "vscode": {
              "extensions": [
+                 "charliermarsh.ruff",  // ruff の拡張機能
+                 "ms-python.python",  // pyright に拡張機能が入っています
              ]
          }
      },
      "containerEnv": {
          "UV_PROJECT_ENVIRONMENT": "/home/vscode/.venv"
      },
+     "postCreateCommand": "uv sync --frozen",
  }

2.3.1. Ruff の設定

https://github.com/astral-sh/ruff/tree/main

ruff
図 3: Lint[2:1] する際のスピード比較

Ruff は,上記 GitHub リポジトリで Astral 社が開発している Python 用の Formatter[1:3], Linter[2:2] です.
Rust[5:1] で書かれているため高速で,なんと Pylint[7] の 200 倍以上のスピードです!

https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules

Ruff の設定はruff.tomlファイルで設定を書くことができ,基本的に公式から流用しています.
しかし,上記ドキュメントには Conflict してしまう設定は ignore することを推奨すると書かれていたので,追記しています.

ruff.toml
  # Exclude a variety of commonly ignored directories.
  exclude = [
      ".bzr",
      ".direnv",
      ".eggs",
      ".git",
      ".git-rewrite",
      ".hg",
      ".ipynb_checkpoints",
      ".mypy_cache",
      ".nox",
      ".pants.d",
      ".pyenv",
      ".pytest_cache",
      ".pytype",
      ".ruff_cache",
      ".svn",
      ".tox",
      ".venv",
      ".vscode",
      "__pypackages__",
      "_build",
      "buck-out",
      "build",
      "dist",
      "node_modules",
      "site-packages",
      "venv",
  ]

  # Same as Black.
  line-length = 88
  indent-width = 4

  # Assume Python 3.12
  target-version = "py312"

  [lint]
  # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`)  codes by default.
  select = ["ALL"]
+ ignore = [
+     "COM812", "COM819",
+     "D100", "D203", "D213", "D300",
+     "E111", "E114", "E117",
+     "ISC001", "ISC002",
+     "Q000", "Q001", "Q002", "Q003",
+     "W191",
+ ]

  # Allow fix for all enabled rules (when `--fix`) is provided.
  fixable = ["ALL"]
  unfixable = []

  # Allow unused variables when underscore-prefixed.
  dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"

  [format]
  # Like Black, use double quotes for strings.
  quote-style = "double"

  # Like Black, indent with spaces, rather than tabs.
  indent-style = "space"

  # Like Black, respect magic trailing commas.
  skip-magic-trailing-comma = false

  # Like Black, automatically detect the appropriate line ending.
  line-ending = "auto"

2.3.2. pre-commit の設定

pre-commit とは,文字通り git コマンドでコミットする前の行動を指定することができます.
今回は以下を commit 前に走らせるように設定します.

  • Docker
    • lint(hadolint)
  • Python
    • format(ruff)
    • lint(ruff)
.devcontainer/devcontainer.json
  {
      "name": "uv",
      "build": {
          "context": "..",
          "dockerfile": "Dockerfile",
      },
+     "features": {
+         "ghcr.io/dhoeric/features/hadolint:1": {}
+     },
      "customizations": {
          "vscode": {
              "extensions": [
                  "charliermarsh.ruff",
                  "ms-python.python",
              ]
          }
      },
      "containerEnv": {
          "UV_PROJECT_ENVIRONMENT": "/home/vscode/.venv"
      },
      "postCreateCommand": "uv sync --frozen",
+     "postStartCommand": "uv run pre-commit install",
  }
.pre-commit.yaml
default_stages: [commit]

repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.8.0
    hooks:
      - id: ruff
        name: Ruff check
        description: "Run 'ruff check' for extremely fast Python linting"
        args: [--fix]

      - id: ruff-format
        name: Ruff format
        description: "Run 'ruff format' for extremely fast Python formatting"

  - repo: https://github.com/RobertCraigie/pyright-python
    rev: v1.1.389
    hooks:
      - id: pyright
        name: Pyright type check
        description: "Type Check by Pyright"

  - repo: https://github.com/hadolint/hadolint
    rev: v2.12.0
    hooks:
      - id: hadolint
        name: Lint Dockerfiles
        description: Runs hadolint to lint Dockerfiles
        language: system
        types: ["dockerfile"]
        entry: hadolint

2.3.4. Pyright の設定

Microsoft が開発しているの静的型チェックを行うツールです.
以下に mypy との比較を示しますが,今回は Dev Container との互換性と速度を考慮して Pyright を採用しました.

pyright mypy
開発元 Microsoft Python
開発言語 Python + TypeScript Python + C
スター数(2024/12) 135,000 186,000
スピード 早い
VS Code との互換性 良い
対応しているエディタ 多い
対応している Python バージョン 3.x 2.x, 3.x

Star History Chart

pyrightconfig.json
{
    "pythonVersion": "3.12",
    "pythonPlatform": "All",
    "venv": ".venv",
    "include": [],
    "exclude": [
        "**/__pycache__",
        ".pytest_cache",
        ".ruff_cache",
        ".venv"
    ],
}

2.3.5. VSCode の設定

保存時に .py ファイルを自動フォーマット[1:4]するために必要な設定の最小構成を以下に示します.

.vscode/settings.json
{
    "python.defaultInterpreterPath": "/home/vscode/.venv/bin/python",
    "[python]": {
        "editor.codeActionsOnSave": {
            "source.fixAll": "explicit",
            "source.organizeImports": "explicit"
        },
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.formatOnSave": true,
        "editor.tabSize": 4
    }
}

2.4. ARG を用いる

ARGDockerfile 内で使用できる変数で,変数の値によって生成するイメージの中身を変えることが可能です.
破壊的な変更を避ける目的で,バージョンを固定します.

.devcontainer/Dockerfile
+ ARG UV_VERSION=0.5.4
+ ARG DEBIAN_VERSION=bookworm


+ FROM ghcr.io/astral-sh/uv:$UV_VERSION AS uv


+ FROM mcr.microsoft.com/vscode/devcontainers/base:$DEBIAN_VERSION
  COPY --from=uv --chown=vscode: /uv /uvx /bin/
.devcontainer/devcontainer.json
{
    "name": "uv",
    "build": {
        "context": "..",
        "dockerfile": "Dockerfile",
+       "args": {
+           "UV_VERSION": "0.5.4",
+           "DEBIAN_VERSION": "bookworm"
+       }
    },
    "features": {
        "ghcr.io/dhoeric/features/hadolint:1": {}
    },
    "customizations": {
        "vscode": {
            "extensions": [
                "charliermarsh.ruff",
                "ms-python.python",
            ]
        }
    },
    "containerEnv": {
        "UV_PROJECT_ENVIRONMENT": "/home/vscode/.venv"
    },
    "postCreateCommand": "uv sync --frozen",
    "postStartCommand": "uv run pre-commit install",
}

3. おまけ

ブランチ毎に機能を分けていく予定なので,機能を追加次第更新していきます.

3.1. jupyter ブランチ

Jupyter Notebook もフォーマットできるようにしました.
主に Jupyter Notebook を使用する時に切り替えるブランチです.

https://github.com/a5chin/python-uv/tree/jupyter

jupyter

3.2. rye ブランチ

『【Rye + uv + Ruff】Docker で VS Code の Dev Container 上に快適な Python 環境を構築する』で作成した成果物です.
必要がなくなってしまったので,泣く泣くのアーカイブ用です.

https://github.com/a5chin/python-uv/tree/rye

4. まとめ

本記事では,VS Code の Dev Container 上に uv と Ruff を使って爆速で快適な Python 環境を構築する方法について解説しました.
よりリッチな設定が以下のリポジトリにあるので,ぜひ使ってください!(PR も歓迎です)
皆さんが快適な Python ライフを送れることを願います💫

https://github.com/a5chin/python-uv/tree/main

脚注
  1. 一貫性のあるコーディングスタイルを強制させることです. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  2. 潜在的なバグや不適切なコーディングスタイルを検出し,それらを修正することでコードの品質を向上できます. ↩︎ ↩︎ ↩︎

  3. コードの機能をテストし,期待通りに動作することを確認することです. ↩︎

  4. Docker イメージを構築することを指します.イメージからコンテナを作成することができます. ↩︎

  5. 性能,メモリ安全性,安全な並行性を目指して設計されたマルチパラダイムのプログラミング言語です.C, C++ 言語に代わるシステムプログラミング言語を目指しています. ↩︎ ↩︎

  6. OSに関連するパッケージやツールが含まれていないため,イメージサイズが小さいという特徴があります. ↩︎

  7. Python における Linter の一種です. ↩︎

GitHubで編集を提案
DeNA Engineers

Discussion