私が普段使っているPythonの開発環境の構築について説明します。DockerとPoetryを利用して構築し、1人または少人数で利用することを想定した開発環境です。
本稿では、はじめに最低限の構成でJupyterLabを起動する方法までを説明します。後にオプションとしてVS CodeやGitHub Codespacesの各種設定やフォーマッター、テスト、API構築などのトピックを扱います。使っているエディタなどに合わせて、必要なところだけ参考にしてください。
なぜDocker+Poetryという構成が良いのか、他の選択肢にはどういった物があるのかという点については、Pythonの開発環境の3つの観点をおさえようという記事に詳しく説明されています。
実行環境
- Debian 11.7
- Docker version 24.0.6
- Docker Compose version v2.21.0
Linux(ChromeOS)およびWindows 11 WSL2を想定しています。
ホストコンピュータにPythonやPoetryをインストールする必要はありません。
Python環境構築
poetry new
Poetryを使う場合、最初にpoetry new
でプロジェクトを初期化する必要があります。ですがPoetryはPythonに依存しており、Python環境構築前にPoetryは使えません。
そのため、Dockerで一時的なコンテナを使ってpoetry new
を実行します。
$ docker run \
--volume $(pwd):/app \
--workdir /app \
python:3.10-slim bash -c \
'pip install poetry && poetry new my_python_project && cd $_ && poetry install'
$ cd my_python_project
以下はお好みで変更してください。
- Dockerイメージ(Pythonのバージョン)
python:3.10-slim
- プロジェクト名
my_python_project
Pythonのバージョンは、2023年10月時点で最新版である3.12がリリースされていますが、どのバージョンを選択するかはいくつかの方針があります。
最新版にすると最新の機能が利用できますが、有名なライブラリ等が対応していない時もあります。そういったトラブルを避ける必要がある場合はひとつ前のバージョンを選ぶのが安定すると思います。
方針 | 現時点のバージョン |
---|---|
最新版にする | 3.12 |
最新版のひとつ前にする | 3.11 |
Google Colabに合わせる | 3.10 |
Gitの設定
$ git init .
$ wget --output-document=.gitignore https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore
お好みでlockファイルをバイナリ扱いにします。
賛否が分かれる設定だと思いますが、最近BunがLockファイルをバイナリとしたのもあって、一定の支持はある考え方のようです。
$ echo "poetry.lock binary" >> .gitattributes # お好みで
Dockerの設定
Docker Composeで起動する設定をします。
# 最初に構築したイメージと合わせる
FROM python:3.10-slim
WORKDIR /app
# お好みで好きなパッケージを追加
RUN apt-get update && apt-get install -y \
build-essential \
git \
curl \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN git config --global --add safe.directory /app
RUN pip install poetry \
&& poetry config virtualenvs.create false
COPY ./pyproject.toml ./poetry.lock* ./
RUN poetry install
services:
app:
build: .
volumes:
- .:/app
command: sleep infinity
ビルドしておきます。
$ docker compose build
パッケージのインストールと起動
次に、パッケージをインストールします。ここでは例としてJupyterLabをインストールし、起動設定をします。
$ docker compose run --rm app poetry add --group dev jupyterlab ipywidgets
compose.yaml
に起動設定をします。JupyterLabしか起動しないコンテナなのであれば、compose.yaml
ではなくDockerfile
にCMD
で指定する方が良いと思います。
services:
app:
build: .
volumes:
- .:/app
- command: sleep infinity
+ ports:
+ - 8888:8888
+ command: poetry run jupyter lab --no-browser --ip=0.0.0.0 --port=8888 --allow-root --NotebookApp.token='' --NotebookApp.password='' --NotebookApp.disable_check_xsrf=True
なおVS CodeからNotebookを使う場合などは、実は8888ポート開放の必要はありません。複数プロジェクトを同時に起動する必要がある場合などにポートの競合が起きなくなり便利です。
$ docker compose up --build
JupyterLabを起動できたら成功です。
JupyterLabを使う必要がないがコンテナを起動したい場合、コマンドをsleep infinity
などのように指定しておくことで起動状態を維持できます。
オプション
以下はオプションの設定です。お好みで必要な設定を取り入れてください。
OpenAI API環境変数の追加
ChatGPTを利用したアプリケーションを利用したい場合のAPIキーなどは、環境変数として配置します。APIキーやChatGPTについての詳細はここでは省略します。
$ echo "OPENAI_API_KEY=XXXXXXXX" >> .env
services:
app:
build: .
volumes:
- .:/app
+ env_file:
+ - .env
command: sleep infinity
.env
はgitignore/Python.gitignoreに含まれているため、手順通り設定している場合はリポジトリに含まれません。
VS CodeのPython設定追加
VS Codeを使っている場合は起動中のコンテナ内にアタッチして使うことで、Pythonランタイムに沿った補完などの恩恵が得られたり、ターミナルでコンテナ内のコマンドを実行できるようになります。
VS Codeを起動したらコマンドパレットを開いて>Dev Containers: Attatch to Running Container
コマンドなどで、Dev Containersで接続します。
コンテナ内でワークスペースを開いたら、/app
(WORKDIRで設定したディレクトリ)を開きます。
コンテナ内でms-python.pythonとms-toolsai.jupyterの拡張機能をインストールします。推奨事項に追加する設定をすると、インストールされていない環境でVS Codeを開くと通知が来るようになります。
{
"recommendations": [
"ms-python.python",
"ms-toolsai.jupyter"
]
}
拡張機能をインストールしたら、>Developer: Reload Window
コマンドでリロードします。
VS Code上のNotebookでPythonを実行などができたら成功です。
なおVS Code内からのみNotebookを使うためWebブラウザからアクセスできる必要が無いという場合、JupyterLabのための8888ポート開放の必要が無くなります。複数プロジェクトを同時に起動する必要がある場合などにポートの競合が起きなくなったりして少し便利です。
services:
app:
build: .
volumes:
- .:/app
- ports:
- - 8888:8888
command: poetry run jupyter lab --no-browser --ip=0.0.0.0 --port=8888 --allow-root --NotebookApp.token='' --NotebookApp.password='' --NotebookApp.disable_check_xsrf=True
Dev Container
記述したDockerfile
やcompose.yaml
を利用して、Development Containers(Dev Container)に沿って定義することもできます。
{
"dockerComposeFile": "../compose.yaml",
"workspaceFolder": "/app",
"service": "app",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-toolsai.jupyter",
"ms-python.flake8",
"ms-python.black-formatter"
]
}
}
}
VS Codeを使う上では、Dev Containerを使うことでワークスペースディレクトリ/app
を指定しなくても良くなったり、拡張機能を自動でインストールできる等のメリットがあります。$ docker
のCLIコマンドを使わずに起動できるという点は、好みが分かれると思います。
GitHub Codespaces
先述のDev Containerの定義を利用して、GitHub Codespacesで開発環境を動作させることもできます。
その際、先述の設定ファイルではenv_file
を用意できなくて環境が立ち上がりません。GitHubのsecretsに設定した上でファイルを作成する必要があります。
"initializeCommand": "if [ ! -e .env ]; then echo OPENAI_API_KEY=`echo $OPENAI_API_KEY` > .env; fi"
また、Codespacesのログは>Codespaces: Export Logs
コマンドを使うとzipで固めた状態で取得できるため、コンテナ内にunzip
をインストールするようDockerfile
に追記すると便利だと思います。
VS CodeによるType Checking
VS CodeのPython拡張機能があれば、Pythonの型チェックを有効にできます。
{
"python.analysis.typeCheckingMode": "basic",
}
Flake8およびBlackの導入
リンターとフォーマッターを導入します。本稿ではリンターにFlake8、フォーマッターにBlackを利用します。
VS Code拡張機能
VS Codeを介してのみFlake8とBlackを利用する場合は、拡張機能をインストールするのみでOKです。$ pip install flake8
などをする必要はありません。
{
"recommendations": [
"ms-python.python",
"ms-toolsai.jupyter",
+ "ms-python.flake8",
+ "ms-python.black-formatter",
]
}
VS Codeで以下のように設定します。
{
"[python]": {
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "modifications",
"editor.defaultFormatter": "ms-python.black-formatter",
},
"black-formatter.args": ["--line-length", "120"],
"flake8.args": ["--max-line-length", "120"],
}
リンターによる指摘が表示され、>Format Document
コマンドでフォーマッターを使えるようになります。
CLI
リンターやフォーマッターをCLIで利用したい場合は、インストールが必要です。
$ docker compose exec app poetry add --group dev black flake8
以下のように設定をします。
[flake8]
max-line-length = 120
+
+[tool.black]
+line-length = 120
以下のようなコマンドで実行します。
$ docker compose exec app poetry run flake8 ./my_python_project/
Skipping virtualenv creation, as specified in config file.
./my_python_project/nicegui_main.py:4:1: E302 expected 2 blank lines, found 1
$ docker compose exec app poetry run black ./my_python_project/
Skipping virtualenv creation, as specified in config file.
reformatted /app/my_python_project/nicegui_main.py
All done! ✨ 🍰 ✨
1 file reformatted, 1 file left unchanged.
実際にはGitHub ActionsなどのCI上で実行するように設定するのが良いと思います。
アプリケーション実行環境の追加
FastAPIの追加
Pythonで開発したものをWeb APIとして実行できる環境も用意したい場合があります。本稿ではFastAPIを起動できる環境を用意します。
$ docker compose exec app poetry add fastapi uvicorn
以下のように記載します。
services:
app:
build: .
volumes:
- .:/app
command: poetry run jupyter lab --no-browser --ip=0.0.0.0 --port=8888 --allow-root --NotebookApp.token='' --NotebookApp.password='' --NotebookApp.disable_check_xsrf=True
+ fastapi:
+ extends:
+ service: app
+ ports:
+ - 8081:80
+ command: uvicorn my_python_project.fastapi_main:app --host 0.0.0.0 --port 80 --reload
FastAPI以外を使う場合もだいたい似たような設定で行けると思います。起動ホストを0.0.0.0
で指定するのがポイントです。
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
コンテナを立ち上げ直し、$ curl localhost:8081
などで{"Hello": "World"}
と表示されたら成功です。
NiceGUIの追加
WebAPIだけではなくUIが欲しい場合もあります。要件や好みによってStreamlitやGradioを選びますが、本稿ではより柔軟にアプリケーションを構築できるNiceGUIの例を記載します。
$ docker compose exec app poetry add nicegui
以下のように記載します。
services:
app:
build: .
volumes:
- .:/app
command: poetry run jupyter lab --no-browser --ip=0.0.0.0 --port=8888 --allow-root --NotebookApp.token='' --NotebookApp.password='' --NotebookApp.disable_check_xsrf=True
+ nicegui:
+ extends:
+ service: app
+ ports:
+ - 8080:8080
+ command: poetry run python my_python_project/nicegui_main.py
from nicegui import ui
ui.label('Hello NiceGUI!')
ui.run()
pytest
開発が進むとテストコードが欲しくなります。ここではpytestを導入します。
$ docker compose exec app poetry add --group dev pytest
tests/test_mymodule.py
のような名前でテストファイルを作成しますが、そのままではテストを実行できません。pyproject.toml
に、pytestの設定を記述する必要があります。
+
+[tool.pytest.ini_options]
+testpaths = ["tests",]
+pythonpath = "my_python_project"
$ poetry run pytest
でテストが実行できます。
補足
本記事は3年前に書いた記事のリメイクです。