はじめに
こんにちは、ニフティ株式会社 基幹システムグループの小倉です。今回は、業務で扱うことの多いPython開発環境に対して、個人的に快適でモダンな開発環境を考えてみたので、共有しようと思います。
使用するツールについて
Visual Studio Code | 今回使用するエディタになります。 |
Docker | コンテナ技術を提供するツールです。 |
Poetry | PoetryはPythonパッケージマネージャの1つです。普段の開発ではpipenvを用いることが多いですが、Poetryでは依存解決を高速に行える点と他のパッケージの設定ファイルをまとめて管理できるメリットがあるため今回は使用してみました。 |
Ruff | Ruffは、Rustで記述されたPython用Linterです。Rustを使用しているだけあって処理速度は既存のLinterライブラリの中で最速です。また、スター数も伸びていて、AWS SAMやFastAPI等の有名なオープンソースプロジェクトでも使用されています。 |
Black | BlackはPEP8に準拠したFormatterライブラリです。autopep8やyapfなどの他のFormatterより制限が厳しく、個人で自由に設定できる項目が少ないです。このため、フォーマットに関して、チーム内でルールを決める時間を省けます。 |
Mypy | MypyはPythonの静的型チェックを実行するライブラリです。mypyを用いることで、型ヒント不足や型の矛盾の検知が可能になり、コードの可読性向上や堅牢性向上に繋がります。 |
Pytest | Pythonの単体テストでよく使われているライブラリです。 |
Poethepoet | Poetryと相性の良いタスクランナーです。PoetryにはPipenvのScriptのようなタスクランナー機能がないので、Poethepoetを使って実現しています。 |
事前準備
- Visual Studio Code(以下VSCode)、Dockerのインストール
- VSCode拡張機能のDev Containersのインストール
環境構築
開発環境としては、Dockerを用いたPythonコンテナ環境を構築し、VSCode拡張機能のDev ContainerのRemote先に今回のコンテナ環境を指定します。このように、Dev Containerを経由することで、コンテナ環境下でもローカル環境と同様にVSCodeの便利な拡張機能を使用した開発が可能になります。
作業ディレクトリ構成
作業ディレクトリは以下のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
. |____app | |____Dockerfile | |____pyproject.toml | |____tests | | |______init__.py | | |____test_main.py | |______init__.py | |____.gitignore | |____main.py |____.devcontainer | |____devcontainer.json |____compose.yaml |
Dockerfile
まず、ベースとなるPythonコンテナ環境を作成するため、以下のようにDockerfileを記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
FROM python:3.11-slim WORKDIR /app RUN apt update -y && \ apt install -y curl ENV POETRY_HOME /etc/poetry RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=$POETRY_HOME python3 - ENV PATH="$POETRY_HOME/bin:$PATH" ENV PYTHONPATH /app COPY ./app /app RUN poetry config virtualenvs.create false && \ poetry install |
compose.yaml
compose.yamlに関しては以下のように記述しています。
1 2 3 4 5 6 7 8 9 10 |
services: app: container_name: "python-dev" build: context: . dockerfile: app/Dockerfile working_dir: /app volumes: - ./app:/app tty: true |
pyproject.toml
pyproject.tomlではpoetryによる開発環境用と本番環境用のライブラリの記述以外にも、今回使用するRuff、Black、Mypy、Pytest、Poethepoetの設定もまとめて管理します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
[tool.poetry] name = "python-dev-demo" version = "0.1.0" description = "python dev-container env" authors = ["Your Name <you@example.com>"] readme = "README.md" [tool.poetry.dependencies] python = "^3.11" pydantic = "^1.10.4" [tool.poetry.group.dev.dependencies] mypy = "^0.991" ruff = "^0.0.237" black = "^22.12.0" pytest = "^7.2.1" pytest-cov = "^4.0.0" poethepoet = "^0.18.1" [tool.mypy] warn_return_any = true warn_unused_configs = true disallow_untyped_defs = true strict = true [tool.ruff] select = [ # pyflakes "F", # pycodestyle errors, warnings "E", "W", # isort # "I", # flake8-2020 "YTT", # flake8-bugbear "B", ] target-version = "py311" line-length = 120 [tool.black] line-length = 120 target-version = ["py311"] [tool.pytest.ini_options] testpaths = [ "tests", ] [tool.poe.tasks.pytest] shell = "pytest -v --cov=. --cov-branch" interpreter = "bash" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" |
Poetry
環境ごとにライブラリの依存関係を分離するためにはtool.poetry.group.<group>
を使用します。
Mypy
strict = true
にすることでmypyのオプションのエラーチェックフラグをすべて有効にし、厳重な型チェックが可能になります。ただし、いくつかのオプションはstrict モードでも無効になっています。無効になっているフラグに関しては、 mypy --help
の出力で確認することができます。
Ruff
Ruffでは、現時点で500を超えるlint ルールをサポートしており、select
に追加したいルールに紐づくコード名を記述するで有効にすることができます。デフォルトでは Pyflakes(F) と pycodestyle (E)が有効になっています。
Black
基本的な設定としては、line-length
によって1行の文字数制限を変更できます。
Pytest
testpaths
でテストディレクトリの設定しています。
今回はついでにカバレッジを取得するPytest-covもInstallしています。
Poethepoet
基本的な使い方としては、今回のpyproject.tomlで定義しているように[tool.poe.tasks.<task_name>]
で設定し、poe <task_name>
で実行できます。
今回の例では、pytest -v --cov=. --cov-branch
コマンドでpytestのテスト結果とカバレッジを毎回叩くのが面倒なので、poe pytest
で実行できるようにしています。
devcontainer.json
- devcontainerの設定にはdevcontainer.jsonを使用します。
- 今回の用途ではまず、compose.yamlの場所、compose.yamlで定義するservice名とワークディレクトリを指定しています。
- devcontainer環境で使用したいVScode拡張機能を
extensions
、その拡張機能の詳細設定をsettings
で定義します。 - 今回は拡張機能として、Python拡張機能とruffの拡張機能を入れています。
- 拡張機能の詳細設定としては、デフォルト設定の不要な機能無効化、それぞれのライブラリのインタープリタパスとpyproject.tomlで定義したライブラリの設定を拡張機能側に反映させています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
{ "name": "Python-dev Template", "dockerComposeFile": ["../compose.yaml"], "service": "app", "workspaceFolder": "/app", "customizations": { "vscode": { "extensions": [ "ms-python.python", "charliermarsh.ruff" ], "settings": { "editor.formatOnSave": true, "[python]": { "editor.codeActionsOnSave": { "source.fixAll": true, } }, "python.defaultInterpreterPath": "/usr/local/bin/python", // "python.formatting.provider": "none", "python.formatting.provider": "black", "python.formatting.blackPath": "/usr/local/bin/black", "python.formatting.blackArgs": ["--config=${containerWorkspaceFolder}/pyproject.toml"], "python.linting.mypyPath": "/usr/local/bin/mypy", "python.linting.mypyArgs": ["--config=${containerWorkspaceFolder}/pyproject.toml"], "python.linting.mypyEnabled": true, "python.linting.enabled": true, "python.testing.pytestPath": "/usr/local/bin/pytest", "python.testing.pytest": ["--config=${containerWorkspaceFolder}/pyproject.toml"], "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "ruff.args": ["--config=${containerWorkspaceFolder}/pyproject.toml"], "ruff.path": ["/usr/local/bin/ruff"], "ruff.interpreter": ["/usr/local/bin/python"] } } } } |
動作確認
以上の設定が完了したら、コマンドパレッド(command + option + P)を開き、Reopen in Container
を実行することで、以下の画像のようにdevcontainer環境に入れます。
Dev Container環境に入ると以下のような機能が利用できるようになっています。
- それぞれのライブラリのルールに違反したコードに波線ハイライト
- e
ditor.formatOnSave
によってBlackによる保存の際に自動フォーマット - Pythonコード内で保存した際にruffによる自動修正
- Pytestの機能として、画面左側のフラスコマークをクリックすることでテスト対象のディレクトリ、ファイル名、テスト名が表示されデバッグやテストがGUIから実行可能
おわりに
ここまで、Dev Containerを使ってPythonのDocker開発環境を構築しました。
今回は必要最低限の設定しかしていないので、このコードを参考に独自にカスタマイズしていただければ幸いです。