当サイトは、アフィリエイト広告を利用しています

【Docker × VScode × pytest 】pytestの環境別実行方法

作成日:2024月12月25日
更新日:2024年12月25日

VSCodeでpytestを

  • ローカルで実行する
  • コンテナ上で実行する

のテスト実行環境別に実行する方法を調べたのでまとめておく。

当記事では

  • pytestとは?
  • VScode上でのpytestを実行するとは?
  • VScode上でのpytestの方法(ローカル環境で実行)
  • VScode上でのpytestの方法(コンテナ環境で実行)

についてまとめる。

なお、テストの実行方法のみを解説するため
テスト内容等は今回は割愛する

pytestとは?

pytestは CUI(Character User Interface)ツールで、
コマンドライン上で実行するテストフレームワークであり、
対話的なGUIやグラフィカルなユーザーインターフェースを提供していない。

そのため通常テストコードを書いた後、ターミナルから
コマンド実行で実施する。

コマンド実行の場合

コマンドで実行する場合は下記のようになる。

テストコード

サンプルテストコード

test_main.py
from unittest.mock import Mock
import pytest
from main import create_app
def test_1():
mock = Mock()
def test_2():
mock = Mock()
def test_3():
mock = Mock()
def test_4():
mock = Mock()
def test_5():
mock = Mock()
def test_6():
mock = Mock()

コマンド実行

ターミナルからコマンド実行する

コマンド実行
rootdir: C:\develop\01_TechSamples\Python\FastApi\fastApi_pytest
plugins: anyio-4.6.2.post1, cov-5.0.0
collected 6 items
tests/test_main.py::test_1 PASSED [ 16%]
tests/test_main.py::test_2 PASSED [ 33%]
tests/test_main.py::test_3 PASSED [ 50%]
tests/test_main.py::test_4 PASSED [ 66%]
tests/test_main.py::test_5 PASSED [ 83%]
tests/test_main.py::test_6 PASSED [100%]
======================== 6 passed in 0.96s ========================

このようにpytestは通常はテストコードを作成後、ターミナルから
コマンドで実行する。

テストコードを書いた後はコマンド実行で問題ないが
テストコード作成中にデバッグで動作を確認することはできない。

VScode上でpytestを実行するとは?

先にイメージだけ見せると
VScodeからpytest実行する場合は下記のようになる
2024-12-12-18-14-30

VScode上でのpytestをするメリット

コマンドではなくVScode上でのpytestをするメリットをするをまとめる
VSCodeを使うことでグラフィカルなユーザーインターフェースで実行することができる

テストケースを個別で実行できる

2024-12-12-18-40-51

チェックマークを右クリックすることでテストケースを個別で実行できる

クラスやモジュール単位で実行できる

2024-12-12-18-42-03 左のテスト用のエクスプローラーから

  • モジュール
  • クラス
  • テストケース

の任意の単位でテストを実行できる

デバッグできる

2024-12-12-18-44-05

テストケース実行でブレークポイントを打って
デバッグ実行を行えばデバッグできる

VScode上でのpytestの方法

実際にFastApiで作ったサンプルREST APIのテストをVSCodeから実行してみる

テストの実行環境によって行う設定が異なるので
テストの実行環境が

  • ローカルでpytestを実行する
  • dockerコンテナ上でpytestを実行する

の場合別で実行する。

ローカルでpytestを実行する

まずはローカルでpytestを実行する場合の設定方法を解説する。

テスト対象のFastApi製REST API

テスト対象のFastApi製REST APIのプロジェクト構成としては
下記のようにする

FastApi製REST_API
.
|-- .vscode
| |-- .env
| |-- launch.json
| `-- settings.json
|-- app
| |-- __init__.py
| |-- asgi.py
| |-- endpoints.py
| `-- main.py
|-- requirements.txt
`-- tests
|-- test_asgi.py
|-- test_endpoints.py
`-- test_main.py

パッケージインストール

requirements.txt
fastapi
uvicorn[standard]
pytest
pytest-asyncio

必要なパッケージをインストールする

REST API関連モジュール

REST API自体のモジュール
pytestのテスト対象となるモジュール

asgi.py

asgi.py
from main import create_app
app = create_app()

FastApiアプリケーションをASGIサーバーで起動するための エントリーポイントとなるモジュール

endpoints.py

endpoints.py
from fastapi import APIRouter
from fastapi.responses import JSONResponse
router = APIRouter()
# ディクショナリリスト
users = [
{"user_id": "1", "name": "Tujimura", "age": 11},
{"user_id": "2", "name": "mori", "age": 20},
{"user_id": "3", "name": "shimada", "age": 50},
{"user_id": "4", "name": "kyogoku", "age": 70}
]
# ディクショナリの一覧を取得
@router.get("/")
async def get_users():
return JSONResponse(status_code=200, content=users)

エンドポイントを管理するモジュール

main.py

main.py
from fastapi import FastAPI
import endpoints as endpoints
def create_app():
# アプリケーションインスタンスの作成
app = FastAPI()
# ルーティング設定
app.include_router(endpoints.router)
return app

アプリケーションの初期化処理を行うモジュール。

テストモジュール

テスト対象モジュールのテストを行うモジュール
テスト対象モジュールと1:1で作成する

pytestでテストモジュールを作成する場合
「test_」で始まる名前にする必要がある

test_asgi.py

test_asgi.py
from unittest.mock import Mock
import importlib
import asgi
def test_asgi(monkeypatch):
# create_app()が実行された場合にmock_appが返るように置き換え
mock_app = Mock()
monkeypatch.setattr("main.create_app", mock_app)
# asgiモジュールを再インポートして評価させる
importlib.reload(asgi)
# create_app関数(mock)が呼び出されたか確認
mock_app.assert_called_once()

test_endpoints.py

test_endpoints.py
from unittest.mock import Mock
from main import create_app
import endpoints
def test_create_app(monkeypatch):
# Mockの FastAPIインスタンスを作成
mock_app_instance = Mock()
# include_routerメソッドを設定
mock_app_instance.include_router.return_value = True
# FastAPI()が実行された場合にmock_app_instanceが返るように置き換え
mock_app = Mock(return_value=mock_app_instance)
monkeypatch.setattr("main.FastAPI", mock_app)
# create_app 関数を実行
create_app()
# include_router が endpoints.router を引数に呼び出されたか確認
mock_app_instance.include_router.assert_called_with(endpoints.router)

test_main.py

test_main.py
from unittest.mock import Mock
from main import create_app
import endpoints
def test_create_app(monkeypatch):
# Mockの FastAPIインスタンスを作成
mock_app_instance = Mock()
# include_routerメソッドを設定
mock_app_instance.include_router.return_value = True
# FastAPI()が実行された場合にmock_app_instanceが返るように置き換え
mock_app = Mock(return_value=mock_app_instance)
monkeypatch.setattr("main.FastAPI", mock_app)
# create_app 関数を実行
create_app()
# include_router が endpoints.router を引数に呼び出されたか確認
mock_app_instance.include_router.assert_called_with(endpoints.router)

VSCodeの設定ファイル

VScodeでpytestを行うための設定ファイル群

.vscode/.env

.env
PYTHONPATH=./app

PYTHONPATHを指定する。

.envファイルの[.]について

VSCodeは.envの./はそのファイルがどこにあっても ルートディレクトリ、つまり${workspaceFolder}として認識する。

コマンドラインの場合、./はカレントディレクトリが基準になるので注意

なぜPYTHONPATHを指定するのか?

pytestをVSCode上で実行する際、カレントディレクトリは

  • ${workspaceFolder}(vscodeで開いているフォルダ)

になる。

その場合、「PYTHONPATH=./app」の指定がないと
テスト対象モジュールの

main.py
from fastapi import FastAPI
import endpoints as endpoints
def create_app():
# アプリケーションインスタンスの作成
app = FastAPI()
# ルーティング設定
app.include_router(endpoints.router)
return app

やテストモジュールの

py
from unittest.mock import Mock
from main import create_app
import endpoints
def test_create_app(monkeypatch):
# Mockの FastAPIインスタンスを作成
mock_app_instance = Mock()
# include_routerメソッドを設定
mock_app_instance.include_router.return_value = True
print("dddd")
# FastAPI()が実行された場合にmock_app_instanceが返るように置き換え
mock_app = Mock(return_value=mock_app_instance)
monkeypatch.setattr("main.FastAPI", mock_app)
# create_app 関数を実行
create_app()
# include_router が endpoints.router を引数に呼び出されたか確認
mock_app_instance.include_router.assert_called_with(endpoints.router)

でimportしているmainモジュールやendpointsモジュールを
pythonは発見できないため。

pythonがimportするモジュールを

  1. スクリプトを実行しているカレントディレクトリ
  2. 環境変数 PYTHONPATH に設定されたディレクトリ
  3. 標準ライブラリや site-packages ディレクトリ

の順で探すが、カレントディレクトリである${workspaceFolder}には
mainモジュールやendpointsモジュールはないため、見つからない。
※その中のサブディレクトリ(例えば ${workspaceFolder}/app)までは自動で探索してくれない

そこでPYTHONPATHに「PYTHONPATH=./app」を
追加してmainモジュールやendpointsモジュールのある
「${workspaceFolder}/app」を検索パスに入れることで探索可能にしている。

.vscode/settings.json

settings.json
{
// PYTHONPATHの設定
"python.envFile": "${workspaceFolder}/.vscode/.env",
// pytestを実行する際の引数を設定
"python.testing.pytestArgs": [
"${workspaceFolder}", //--rootdir テスト実行のルートディレクトリを指定
"--cov=${workspaceFolder}", //カバレッジ計測を指定
"-v", // 詳細モード有効化
"-s", // printやlogをターミナル表示
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}

VScodeで設定ファイルでテスト実行環境に関する設定をする

python.envFile

ここでVSCodeに「/.vscode/.env」を読み込んで環境変数(PYTHONPATH)を設定している。

python.testing.pytestArgs

pytest実行時のコマンドライン引数を指定する

python.testing.unittestEnabled

unittest フレームワークを無効化

python.testing.pytestEnabled

pytest フレームワークを有効化

.vscode/launch.json

VScodeのデバッグ設定ファイル

launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"purpose": [
"debug-test"
],
"console": "integratedTerminal",
"env": {
"PYTEST_ADDOPTS": "--no-cov"
}
}
]
}

settings.jsonで「--cov=${workspaceFolder}」を指定している場合
このファイルがないとデバッグでブレークポイントが効かなくなる

ローカルでpytest実行

設定ができたらローカルでpytestを実行する

実行方法は

  • VSCode上でpytestを実行
  • VSCodeのターミナルからpytestをコマンド実行

の2つの実行方法がある。

VSCode上でpytestを実行

VScode上でグラフィカルに実行する

拡張機能のインストール

2024-12-12-21-52-24 VScode上でpytestを実行するのに必要な拡張機能をインストールする

F1のコマンドパレットでテストを構成するを選択

2024-12-12-21-50-55

pytestを選択

2024-12-12-21-51-35

ルートディレクトリを選択

2024-12-12-21-54-52

pytestはデフォルトでカレントディレクトリ直下からtestsという名前のディレクトリや
test_ で始まる名前のファイルを探して実行する。

ルート直下のtetsディレクトリあるためルートを選択する

テストが検出される

エラー当がなければテストが検出され下記のようになる 2024-12-12-21-57-05

.vscode/settings.jsonについて

上記手順を行った場合、.vscode/settings.jsonが

settings.json
{
// PYTHONPATHの設定
"python.envFile": "${workspaceFolder}/.vscode/.env",
// pytestを実行する際の引数を設定
"python.testing.pytestArgs": [
"."
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}

のように一部初期化されるので注意

テスト実行

当記事冒頭で説明したようにVScode上でテストを実行できる

VSCodeのターミナルからpytestをコマンド実行

VScodeのターミナルからコマンド実行する

コマンドでpytest実行(失敗)

VScodeのターミナルからコマンド実行すると

コマンド実行
$ pytest -v
C:\Users\lunaj\AppData\Local\Programs\Python\Python311\Lib\site-packages\pytest_asyncio\plugin.py:208: PytestDeprecationWarning: The configuration option "asyncio_default_fixture_loop_scope" is unset.
The event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: "function", "class", "module", "package", "session"
warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))
========================================================================= test session starts =========================================================================
platform win32 -- Python 3.11.1, pytest-8.2.2, pluggy-1.5.0 -- C:\Users\lunaj\AppData\Local\Programs\Python\Python311\python.exe
cachedir: .pytest_cache
rootdir: C:\develop\01_TechSamples\Python\FastApi\fastApi_pytest
plugins: anyio-4.6.2.post1, asyncio-0.24.0, cov-5.0.0
asyncio: mode=Mode.STRICT, default_loop_scope=None
collected 0 items / 3 errors
=============================================================================== ERRORS ================================================================================
_________________________________________________________________ ERROR collecting tests/test_asgi.py _________________________________________________________________
ImportError while importing test module 'C:\develop\01_TechSamples\Python\FastApi\fastApi_pytest\tests\test_asgi.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
C:\Users\lunaj\AppData\Local\Programs\Python\Python311\Lib\importlib\__init__.py:126: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests\test_asgi.py:3: in <module>
import asgi
E ModuleNotFoundError: No module named 'asgi'
______________________________________________________________ ERROR collecting tests/test_endpoints.py _______________________________________________________________
ImportError while importing test module 'C:\develop\01_TechSamples\Python\FastApi\fastApi_pytest\tests\test_endpoints.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
C:\Users\lunaj\AppData\Local\Programs\Python\Python311\Lib\importlib\__init__.py:126: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests\test_endpoints.py:3: in <module>
from endpoints import get_users
E ModuleNotFoundError: No module named 'endpoints'
_________________________________________________________________ ERROR collecting tests/test_main.py _________________________________________________________________
ImportError while importing test module 'C:\develop\01_TechSamples\Python\FastApi\fastApi_pytest\tests\test_main.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
C:\Users\lunaj\AppData\Local\Programs\Python\Python311\Lib\importlib\__init__.py:126: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests\test_main.py:2: in <module>
from main import create_app
E ModuleNotFoundError: No module named 'main'
======================================================================= short test summary info =======================================================================
ERROR tests/test_asgi.py
ERROR tests/test_endpoints.py
ERROR tests/test_main.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 3 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
========================================================================== 3 errors in 0.58s ==========================================================================

のようにエラーになる。

原因としてはでimportしているmainモジュールやendpointsモジュールを
pythonが発見できないため。

.vscode/.envでPYTHONPATH設定し、.vscode/setting.jsonで読み込ませているが
それはVScodeが認識しているのてあって、VSCode内でのエディタとデバッガに影響するが
ターミナルの環境には影響しない。ターミナルでの設定は、ターミナル自体で行う必要がある。

コマンドでpytest実行(成功)

ターミナルでPYTHONPATHを設定してから実行する

コマンド実行
# 環境変数でPYTHONPATHを設定
$ export PYTHONPATH=$(pwd)/app
# 環境変数の確認
$ echo $PYTHONPATH
/c/develop/01_TechSamples/Python/FastApi/fastApi_pytest/app
# pytest実行
$ pytest -v
C:\Users\lunaj\AppData\Local\Programs\Python\Python311\Lib\site-packages\pytest_asyncio\plugin.py:208: PytestDeprecationWarning: The configuration option "asyncio_default_fixture_loop_scope" is unset.
The event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: "function", "class", "module", "package", "session"
warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))
============================== test session starts ==================================
platform win32 -- Python 3.11.1, pytest-8.2.2, pluggy-1.5.0 -- C:\Users\lunaj\AppData\Local\Programs\Python\Python311\python.exe
cachedir: .pytest_cache
rootdir: C:\develop\01_TechSamples\Python\FastApi\fastApi_pytest
plugins: anyio-4.6.2.post1, asyncio-0.24.0, cov-5.0.0
asyncio: mode=Mode.STRICT, default_loop_scope=None
collected 3 items
tests/test_asgi.py::test_asgi PASSED [ 33%]
tests/test_endpoints.py::test_get_users_directly PASSED [ 66%]
tests/test_main.py::test_create_app PASSED [100%]
=============================== 3 passed in 1.68s ===================================

ターミナルでPYTHONPATHを設定してから実行すると成功する

dockerコンテナ上でpytestを実行する

次はpytestをdockerコンテナ上で実行する

コンテナで実行するメリット

pytestをコンテナで実行するメリットとしては下記がある

  • ローカルが汚れない
  • PYTHONPATHの設定をVSCodeとターミナルで同時にできる
  • テスト環境をどこでも再現できる

テスト対象のFastApi製REST API_コンテナ版

テスト対象のFastApi製REST APIのプロジェクト構成としては
下記のようにする

FastApi製REST_API_コンテナ版
|-- .vscode
# | |-- .env
| |-- launch.json
| `-- settings.json
|-- app
| |-- __init__.py
| |-- asgi.py
| |-- endpoints.py
| `-- main.py
|-- docker-compose.yml
|-- dockerfile
|-- requirements.txt
`-- tests
|-- test_asgi.py
|-- test_endpoints.py
`-- test_main.py
  • .envは不要のため削除、settings.jsonでも読み込みも不要
  • docker-compose.yml、dockerfileをコンテナ作成用に追加

上記以外は変更はないので割愛する

コンテナ作成ファイル

dockerコンテナを作成するためのファイル群

dockerfile

dockerfile
FROM python:3.12
# PYTHONPATHの設定
ENV PYTHONPATH=/workspace/app
# workspaceディレクトリ作成、移動
WORKDIR /workspace
# プロジェクトディレクトリにコピー
COPY requirements.txt /workspace
# 必要パッケージのインストール
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
# uvicorn実行
CMD ["uvicorn", "asgi:app", "--reload", "--host", "0.0.0.0", "--port", "8000"]

ENV PYTHONPATH=/workspace/appについて

コンテナ内では、Dockerfileに

  • ENV PYTHONPATH=...

と設定すると、その環境変数がコンテナ内で実行されるすべてのプロセス(VSCodeのデバッガ、ターミナル、uvicorn サーバーなど)
で認識されるようになる。

つまりVScodeでもターミナルでもPYTHONPATHを認識する

ENV PYTHONPATH=/workspace/appを設定しないと。。。。

同様にimportしているmainモジュールやendpointsモジュールを
pythonが発見できないためエラーとなる。

このDockerfileの場合、カレントディレクトリは/workspaceになるため
/workspace配下にないmainモジュールやendpointsモジュールはimportエラーとなる。

PYTHONPATHに/workspace/appを追加することでapp配下の
mainモジュールやendpointsモジュールをpythonが検索できるようになる

docker-compose.yml

docker-compose.yml
version: "3"
services:
fastapi:
container_name: "fastapi"
build:
context: .
dockerfile: Dockerfile
volumes:
- .:/workspace
tty: true
ports:
- 8000:8000 # ホストマシンのポート8000を、docker内のポート8000に接続する

VSCodeの設定ファイル

VScodeでpytestを行うための設定ファイル群

.vscode/settings.json

settings.json
{
// // PYTHONPATHの設定
// "python.envFile": "${workspaceFolder}/.vscode/.env",
// pytestを実行する際の引数を設定
"python.testing.pytestArgs": [
"${workspaceFolder}", //--rootdir テスト実行のルートディレクトリを指定
"--cov=${workspaceFolder}", //カバレッジ計測を指定
"-v", // 詳細モード有効化
"-s", // printやlogをターミナル表示
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}

VScodeで設定ファイルでテスト実行環境に関する設定をする
PYTHONPATHの設定は不要なので消す

そのほかは同じ

コンテナ作成と接続

コンテナを作成してコンテナに接続する

コンテナ作成

コンテナ作成
# コンテナ作成
$ docker-compose up -d
# 確認
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4a4b4b7d08a7 fastapi_pytest-fastapi "uvicorn asgi:app --…" 3 minutes ago Up 3 minutes 0.0.0.0:8000->8000/tcp fastapi

コンテナ接続

VScodeからコンテナに接続するには VSCodeの拡張機能である。

  • Dev Containers(ms-vscode-remote.remote-containers)
  • Docker(ms-azuretools.vscode-docker)

のどちらかを使用すれば、コンテナ内をVSCodeから操作できるので開発しやすい。
※この拡張機能はホスト側のVSCodeでインストールして使う

ちなみに自分はdocker-composeでコンテナを作った後
Docker(ms-azuretools.vscode-docker)でコンテナにアタッチしている
下記のような感じ 2024-12-13-15-21-14

コンテナ接続後はローカルと同様に拡張機能

  • ms-python.python

をインストールしておく

コンテナでpytest実行

VScodeからコンテナに接続したら

  • VScode(コンテナ)上でpytest実行
  • VScode(コンテナ)のターミナルでpytestをコマンド実行

でそれぞれ実行する

VScode(コンテナ)上でpytest実行

VSCodeでコンテナに接続後にVSCode上でpytestを実行する
VScodeにテストを検出させる方法はローカルと同様に
「F1のコマンドパレットでテストを構成する」から操作していく
※同じ手順

pytest実行

2024-12-13-15-26-51 テストが実行できる

dockerfileでPYTHONPATHを指定しているため
.vscode/setting.jsonでのPYTHONPATHの指定は不要になる

VScode(コンテナ)のターミナルでpytestをコマンド実行

VScodeで接続したコンテナのターミナルでpytestを実行する

コンテナコマンド実行
root@4a4b4b7d08a7:/workspace# pytest -v
/usr/local/lib/python3.12/site-packages/pytest_asyncio/plugin.py:208: PytestDeprecationWarning: The configuration option "asyncio_default_fixture_loop_scope" is unset.
The event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: "function", "class", "module", "package", "session"
warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))
============================= test session starts =======================================
platform linux -- Python 3.12.8, pytest-8.3.4, pluggy-1.5.0 -- /usr/local/bin/python3.12
cachedir: .pytest_cache
rootdir: /workspace
plugins: anyio-4.7.0, asyncio-0.24.0
asyncio: mode=Mode.STRICT, default_loop_scope=None
collected 3 items
tests/test_asgi.py::test_asgi PASSED [ 33%]
tests/test_endpoints.py::test_get_users_directly PASSED [ 66%]
tests/test_main.py::test_create_app PASSED [100%]
============================== 3 passed in 2.36s =========================================
root@4a4b4b7d08a7:/workspace#

ターミナルでPYTHONPATHを設定しなくてもコマンド実行可能。

まとめ

VScodeでのpytestの環境(ローカル、コンテナ)別実行方法の要点として

  • 環境ごとのPYTHONPATHの認識
  • PYTHONPATHのモジュール検索パス
  • pytest

をまとめておく

環境ごとのPYTHONPATHの認識

ローカルの場合

  • ターミナルで 「export PYTHONPATH」を実行しても、VSCodeは認識しない: ターミナルとVSCodeのエディタは別々に動作しているため ターミナルで環境変数を設定しても、VSCodeの設定や開いているファイル、エディタに反映されない。

  • VSCodeに PYTHONPATH を認識させるには以下の設定が必要:

    1. settings.json に設定:
      • VSCodeの設定ファイルである settings.json に環境変数を追加することで、VSCode内で認識させることができる
    2. プロジェクトのルート直下に .env を設定:
      • .env ファイルに「PYTHONPATH」を書くことで、VSCodeがプロジェクトを開いたときにその環境変数を認識する。
  • VSCodeで上記で PYTHONPATH を認識させてもターミナルでは認識しない:

    • settings.json や .env で設定された PYTHONPATH は、VSCode内でのエディタとデバッガに影響するが
      ターミナルの環境には影響しない。ターミナルでの設定は、ターミナル自体で行う必要がある。

コンテナの場合

  • Dockerfile で PYTHONPATH を設定すれば、VSCode、ターミナルともに認識される:
    • コンテナ内では、Dockerfile に ENV PYTHONPATH=... と設定すると、その環境変数がコンテナ内で実行されるすべての
      プロセス(VSCodeのデバッガ、ターミナル、uvicorn サーバーなど)で認識される。
    • VSCodeがコンテナ内で動作する場合や、ターミナルがコンテナ内にいる場合、PYTHONPATH はそのまま有効になる。
      docker-compose などでコンテナ内に入って実行する場合も同様

まとめ

  • ローカルでは、ターミナルとVSCodeの設定は別々に扱われ、VSCode内でのみ PYTHONPATH を認識させるためには settings.json や .env が必要
  • コンテナの場合、Dockerfile で PYTHONPATH を設定すれば、VSCodeやターミナル内の両方で環境変数が有効になる

PYTHONPATHののモジュール検索パス

Python はモジュールをインポートする際に、以下の順序でディレクトリを探索する

  1. スクリプトを実行しているカレントディレクトリ
  2. 環境変数 PYTHONPATH に設定されたディレクトリ
  3. 標準ライブラリや site-packages ディレクトリ

1,2において、その中のサブディレクトリまでは自動で探索しない。

pytestについて

  • pytestはデフォルトでカレントディレクトリ直下からtestsという名前のディレクトリや、test_ で始まる名前のファイルを探して実行する

新着記事

目次
タグ別一覧
top