すべてのプロジェクトで、最初にすべての環境変数をロードし、 dotenv-safeアプローチ に従って_.env.example
_ファイルで記述されているように、予想されるすべてのキーが存在することを確認します。
ただし、env変数は文字列であり、Pythonコード内で使用する場合は常に手動でキャストする必要があります。これは迷惑でエラーが発生しやすくなります。以下の情報を使用したいと思います。 _.env.example
_ファイルを使用して環境変数をキャストし、Python入力サポートをmy IDE(VS Code)で取得します。どうすればよいですか?
env.example
_PORT: int
SSL: boolean
_
Pythonの理想的な動作
_# Set the env in some way (doesn't matter)
import os
os.environment["SSL"] = "0"
os.environment["PORT"] = "99999"
env = type_env()
if not env["SSL"]: # <-- I'd like this to be cast to boolean and typed as a boolean
print("Connecting w/o SSL!")
if 65535 < env["PORT"]: # <-- I'd like this to be cast to int and typed as an int
print("Invalid port!")
_
このコード例では、boolean
、int
、float
、およびstr
のみがサポートされていると想定すると、type_env()
関数はどのようになりますか?
例に示すように、キャストを行うことはそれほど難しくありません。 https://stackoverflow.com/a/11781375/1452257 ですが、タイピングサポートで動作させる方法はわかりません。
変数のタイプを明示的に指定するか、_type_env
_関数に実際の値からタイプを推測させる2つのオプションがあります。他のコメンターは、明示的な型を使用する方法の例をすでに提供しています。使用する必要がある変数の数に応じて、個人的にはPORT = int(os.getenv("PORT", 5555))
またはdataclass
アプローチを使用します。
ただし、タイプを明示的に指定すると、多少のオーバーヘッドが発生します。これが私の推論方法です。それはmypy
に正確なタイプを知らせません、それらはすべてAny
になります。
_import os
from distutils.util import strtobool
from typing import Dict, Any
os.environ["SSL"] = "0"
os.environ["PORT"] = "99999"
def type_env() -> Dict[str, Any]:
d: Dict[str, Any] = dict(os.environ)
for key in d:
try:
d[key] = bool(strtobool(d[key]))
continue
except ValueError:
pass
try:
d[key] = int(d[key])
continue
except ValueError:
pass
try:
d[key] = float(d[key])
continue
except ValueError:
pass
return d
env = type_env()
print(type(env["SSL"]))
print(type(env["PORT"]))
if not env["SSL"]: # <-- I'd like this to be cast to boolean and typed as a boolean
print("Connecting w/o SSL!")
if 65535 < env["PORT"]: # <-- I'd like this to be cast to int and typed as an int
print("Invalid port!")
_
yaml
形式であると想定します(少なくとも、あなたが書いたものは有効なyamlです)pip install pyyaml
)...次に、次のコードが機能します。
# do this or anything else to make a dict from your env.example
import yaml
example=yaml.safe_load("""
PORT: int
SSL: bool
""")
# the missing implementation
def type_env():
env={}
for k, v in os.environ.items():
t=example.get(k)
if t == "bool":
env[k] = v.lower() not in ["false", "no", "0", ""] # whatever you want to consider as False
# or env[k] = v.lower() in ["true", "yes", "1"] # whatever you want to consider as True
Elif t == "int":
env[k] = int(v)
Elif t == "float":
env[k] = float(v)
else:
env[k] = v
return env
# From now on your code (exactly your code, except amending os.environment to os.environ)
# Set the env in some way (doesn't matter)
import os
os.environ["SSL"] = "0"
os.environ["PORT"] = "9999"
env = type_env()
if not env["SSL"]: # <-- I'd like this to be cast to boolean and typed as a boolean
print("Connecting w/o SSL!")
if 65535 < env["PORT"]: # <-- I'd like this to be cast to int and typed as an int
print("Invalid port!")