概要
pydantic-settingsのBaseSettingsクラスの初期化における入力変数の優先順位を調べました。
結論としては、CLI引数 > コンストラクタ引数 > 環境変数 > 環境変数ファイル(dotenv) > デフォルト値の優先度でした。
検証コード
import os
import shutil
import sys
from pathlib import Path
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
TMPENV = "tmp/.env"
def setup_tmp_env():
"""一時的な.envファイルを設定する"""
env_file = Path(TMPENV)
tmp_dir = env_file.parent
tmp_dir.mkdir(exist_ok=True)
env_file.write_text("NAME=dotenv")
return env_file
def cleanup_tmp_env():
"""一時的な.envファイルを削除する"""
env_file = Path(TMPENV)
tmp_dir = env_file.parent
if tmp_dir.exists():
shutil.rmtree(tmp_dir)
class SettingsA(BaseSettings):
name: str = Field(default="", description="名前")
model_config = SettingsConfigDict(
env_file=TMPENV, # デフォルトの.envファイルを指定
case_sensitive=False,
cli_parse_args=True,
cli_ignore_unknown_args=True,
extra="ignore",
)
def setup_test():
sys.argv = ["script.py"]
if os.environ.get("NAME"):
del os.environ["NAME"]
cleanup_tmp_env()
def test_settings_with_cli_args():
# デフォルト値
setup_test()
settings = SettingsA()
assert settings.name == ""
# CLI引数を設定
setup_test()
sys.argv = ["script.py", "--name", "cli"]
settings = SettingsA()
assert settings.name == "cli"
# 環境変数を設定
setup_test()
os.environ["NAME"] = "env"
settings = SettingsA()
assert settings.name == "env"
# dotenvを設定
setup_test()
setup_tmp_env()
settings = SettingsA()
assert settings.name == "dotenv"
# コンストラクタ引数
setup_test()
settings = SettingsA(name="constructor")
assert settings.name == "constructor"
# CLI引数とコンストラクタ引数を設定(CLI引数が優先)
setup_test()
sys.argv = ["script.py", "--name", "cli"]
settings = SettingsA(name="constructor")
assert settings.name == "cli"
# コンストラクタ引数と環境変数(コンストラクタ引数が優先)
setup_test()
os.environ["NAME"] = "env"
settings = SettingsA(name="constructor")
assert settings.name == "constructor"
# 環境変数とdotenvを設定(環境変数が優先)
setup_test()
os.environ["NAME"] = "env"
setup_tmp_env()
settings = SettingsA()
assert settings.name == "env"
if __name__ == "__main__":
test_settings_with_cli_args()
おわりに
上記はデフォルトの優先順位の場合です。
優先順位は変更可能です。
基本的にはデフォルトの優先順位で良いと思いますが、CLI引数よりコンストラクタ引数を優先したり、環境変数より環境変数ファイルを優先したくなる可能性もあるかなと思いました。