[解決!Python]python-dotenvモジュールを使って.envファイルを基に環境変数を設定するには:解決!Python
プログラムで使用する各種設定を.envファイルに記述してあるときに、それらを基に環境変数を設定したり、辞書オブジェクトとして保持したりする方法を紹介する。
# 環境変数FOOが設定されていないことを確認
import os
print(os.getenv('FOO')) # None
# .envファイルの内容を表示
from pathlib import Path
print(Path('.env').read_text())
# 出力結果:
#FOO=foo
#BAR=bar
#EMAIL=kawasaki@example.com
# .envファイルから環境変数の設定を読み込む
from dotenv import load_dotenv
load_dotenv()
if load_dotenv(): # 環境変数が設定されるとTrueを、そうでなければFalseを返す
print('environment variables were set from .env file')
else:
print('environment variables were not set from .env file')
print(os.getenv('FOO')) # foo:環境変数FOOの値が設定された
bar = os.environ['BAR']
print(bar) # bar
baz = os.environ.get('BAZ', 'default') # os.getenv('BAZ', 'default')と同じ
print(baz) # default
print(os.system('echo $EMAIL')) # シェル上で環境変数EMAILの値を表示(macOS)
# 出力結果:
#kawasaki@example.com
#0
# 以降に備えて環境変数を削除しておく
del os.environ['FOO'] # 環境変数FOOを削除
del os.environ['BAR'] # 環境変数BAZを削除
del os.environ['EMAIL'] # 環境変数EMAILを削除
Path('foo/bar/baz').mkdir(parents=True, exist_ok=True) # ディレクトリを作成
os.chdir('foo/bar/baz') # カレントディレクトリを変更
print(os.getcwd()) # ……pytips_0185/test/foo/bar/baz
if Path('.env').exists():
print('.env file exists')
else:
print('.env file does not exist')
load_dotenv() # .envファイルは親ディレクトリ方向に探索される
print(os.getenv('FOO')) # foo
# .envファイルのパスを指定して読み込む
env = Path('../../../.env')
load_dotenv(dotenv_path=env) # dotenv_pathに.envファイルのパスを指定
# デフォルトでは既に設定されている環境変数の値は上書きされない
os.chdir('../../..') # 元のディレクトリに戻る
myenv = Path('.myenv')
print(myenv.read_text())
# 出力結果:
#FOO=foooo
#BAR=barrr
load_dotenv(dotenv_path=myenv)
print(os.getenv('FOO')) # foo
# 既に設定されている環境変数の値を上書きする場合はoverride=Trueを指定する
load_dotenv(dotenv_path=myenv, override=True)
print(os.getenv('FOO')) # foooo
# 環境変数を設定するのではなく、.envファイルの内容を辞書として保持する
from dotenv import dotenv_values
envvars = dotenv_values('.env')
for k, v in envvars.items():
print(f'{k}: {v}')
# 出力結果:
#FOO: foo
#BAR: bar
#EMAIL: kawasaki@example.com
python-dotenvモジュール
プログラムの開発/デバッグ時と本運用時で異なる設定情報を切り分けたい、または接続文字列などの機密情報をプログラムコードに直接記述したくないというときに、環境変数を使ってそれらを管理することがある。こうした情報を「.envファイル」などに記述しておき、必要に応じてプログラムコードから読み出すのに、python-dotenvモジュールを使用できる。
環境変数を記述するファイル(.envファイル)は通常、次のように「環境変数=値」という形式で必要な環境変数とその値を記述していく。
FOO=foo
BAR=bar
EMAIL=kawasaki@example.com
python-dotenvモジュールを使うと、この形式で書かれた.envファイル(または指定した名前のファイル)を読み込んで、環境変数として設定したり、辞書の形でそれらを取得したりできる。
なお、python-dotenvモジュールはPythonには標準で付属しないので、「pip install python-dotenv」「py -m pip install python-dotenv」などのコマンドラインを実行して事前にインストールしておく必要がある。
ここではosモジュールのgetenv関数を使って環境変数FOOなどが設定されていないことを確認した。
import os
print(os.getenv('FOO')) # None
また、以下で使用する.envファイルの内容は次の通り。
from pathlib import Path
print(Path('.env').read_text())
# 出力結果:
#FOO=foo
#BAR=bar
#EMAIL=kawasaki@example.com
先に示した例と同様、3つの環境変数FOO、BAR、EMAILの値を記述してある。
環境変数として設定する
python-dotenvモジュールを使って、.envファイルの内容を読み込み、環境変数を設定するにはload_dotenv関数を使用する。以下に簡単な例を示す。
from dotenv import load_dotenv
load_dotenv()
load_dotenv関数を呼び出すと、デフォルトではカレントディレクトリにある.envファイルの内容を読み込んで、それを基に環境変数を設定してくれる。なお、環境変数が設定されるとTrueを、そうでなければFalseを返送するので、環境変数が設定されたかどうかで処理を切り分けることも可能だ。
if load_dotenv(): # 環境変数が設定されるとTrueを、そうでなければFalseを返す
print('environment variables were set from .env file')
else:
print('environment variables were not set from .env file')
以下はosモジュールのgetenv関数やos.environオブジェクト(マッピングオブジェクト)などを使って、上で見た環境変数が設定されたかどうかを確認するコードだ。
print(os.getenv('FOO')) # foo:環境変数FOOの値が設定された
bar = os.environ['BAR']
print(bar) # bar
baz = os.environ.get('BAZ', 'default') # os.getenv('BAZ', 'default')と同じ
print(baz) # default
環境変数BAZは.envファイルには記述していなかったので、ここではos.environ.getメソッドは環境変数の読み出しに失敗して、'default'を返送している。
また、os.system関数に「echo $EMAIL」として、Pythonコードを実行している環境(の設定を受け継いだシェル)で環境変数が設定されているかどうかも確認してみよう(以下はmacOSの例。Windowsでは「os.system('echo %EMAIL%')」などとする)。
print(os.system('echo $EMAIL')) # echoコマンドで環境変数EMAILの値を表示(macOS)
# 出力結果:
#kawasaki@example.com
#0
環境変数が設定されていることが確認できた。最後の「0」はos.system関数で実行したコマンドが正常に終了したことを表す終了ステータスだ。
以降の説明のために、ここでは上で設定した3つの環境変数を削除しておく。
del os.environ['FOO'] # 環境変数FOOを削除
del os.environ['BAR'] # 環境変数BAZを削除
del os.environ['EMAIL'] # 環境変数EMAILを削除
カレントディレクトリに.envファイルが存在しない場合、load_dotenv関数は親ディレクトリの方向に向かって.envファイルを探索していく。
これを確認するために、サブディレクトリを作成し、そこをカレントディレクトリとした上でload_dotenv関数を呼び出してみよう。
まず、以下のコードではサブディレクトリを作成して、カレントディレクトリを移動し、そこに.envファイルが存在しないことを確認している。
Path('foo/bar/baz').mkdir(parents=True, exist_ok=True) # ディレクトリを作成
os.chdir('foo/bar/baz') # カレントディレクトリを変更
print(os.getcwd()) # ……pytips_0185/test/foo/bar/baz
if Path('.env').exists():
print('.env file exists')
else:
print('.env file does not exist')
# 出力結果:
#.env file does not exist
その上で、load_dotenv関数を呼び出すと、親ディレクトリの方向に.envファイルが探索されて、見つかった.envファイルを基に環境変数が設定される。そのため、以下では環境変数FOOの値を取得できている。
load_dotenv() # .envファイルは親ディレクトリ方向に探索される
print(os.getenv('FOO')) # foo
あるいは、load_dotenv関数のdotenv_pathパラメーターに.envファイルのパスを渡してもよい。以下の例ではpathlibモジュールのPathクラスを使って3つ上の階層にある.envファイルを指定している。
env = Path('../../../.env')
load_dotenv(dotenv_path=env) # dotenv_pathに.envファイルのパスを指定
環境変数の値を上書きする
load_dotenv関数では既に設定されている環境変数の値は上書きされないことに注意が必要だ。例えば、上のコードでは環境変数FOOの値はfooに設定されている。以下のような.myenvファイルがあったとする(カレントディレクトリを元に戻している)。
os.chdir('../../..') # 元のディレクトリに戻る
myenv = Path('.myenv')
print(myenv.read_text())
# 出力結果:
#FOO=foooo
#BAR=barrr
.myenvファイルでは環境変数FOOの値はfooooとなっている。このファイルを上で紹介したdotenv_pathパラメーターに指定して、load_dotenv関数を呼び出した後で環境変数FOOの値を確認してみよう。
load_dotenv(dotenv_path=myenv)
print(os.getenv('FOO')) # foo
環境変数FOOは既に設定されているので上書きされず、その値はfooのままであることが確認できた。
環境変数の値を上書きするには、load_dotenv関数のoverrideパラメーターにTrueを指定する。以下に例を示す。
load_dotenv(dotenv_path=myenv, override=True)
print(os.getenv('FOO')) # foooo
「override=True」を指定すると、このように環境変数の値を上書きできる。
環境変数を設定するのではなく、.envファイルの内容を辞書として保持する
load_dotenv関数は.envファイルの内容を読み込んで、環境変数を設定するものだが、そうではなく、辞書の形で保持することも可能だ。これにはdotenv_values関数を使用する。
以下に例を示す。
from dotenv import dotenv_values
envvars = dotenv_values('.env')
for k, v in envvars.items():
print(f'{k}: {v}')
# 出力結果:
#FOO: foo
#BAR: bar
#EMAIL: kawasaki@example.com
環境変数として取り扱うか、辞書として取り扱うかに応じて、2つの関数を使い分けるようにしよう。
Copyright© Digital Advantage Corp. All Rights Reserved.