bazarr/libs/dynaconf/loaders/env_loader.py
2023-10-14 09:56:21 -04:00

108 lines
3.2 KiB
Python

from __future__ import annotations
from os import environ
from dynaconf.utils import missing
from dynaconf.utils import upperfy
from dynaconf.utils.parse_conf import parse_conf_data
DOTENV_IMPORTED = False
try:
from dynaconf.vendor.dotenv import cli as dotenv_cli
DOTENV_IMPORTED = True
except ImportError:
pass
except FileNotFoundError:
pass
IDENTIFIER = "env"
def load(obj, env=None, silent=True, key=None):
"""Loads envvars with prefixes:
`DYNACONF_` (default global) or `$(ENVVAR_PREFIX_FOR_DYNACONF)_`
"""
global_prefix = obj.get("ENVVAR_PREFIX_FOR_DYNACONF")
if global_prefix is False or global_prefix.upper() != "DYNACONF":
load_from_env(obj, "DYNACONF", key, silent, IDENTIFIER + "_global")
# Load the global env if exists and overwrite everything
load_from_env(obj, global_prefix, key, silent, IDENTIFIER + "_global")
def load_from_env(
obj,
prefix=False,
key=None,
silent=False,
identifier=IDENTIFIER,
env=False, # backwards compatibility bc renamed param
):
if prefix is False and env is not False:
prefix = env
env_ = ""
if prefix is not False:
if not isinstance(prefix, str):
raise TypeError("`prefix/env` must be str or False")
prefix = prefix.upper()
env_ = f"{prefix}_"
# Load a single environment variable explicitly.
if key:
key = upperfy(key)
value = environ.get(f"{env_}{key}")
if value:
try: # obj is a Settings
obj.set(key, value, loader_identifier=identifier, tomlfy=True)
except AttributeError: # obj is a dict
obj[key] = parse_conf_data(
value, tomlfy=True, box_settings=obj
)
# Load environment variables in bulk (when matching).
else:
# Only known variables should be loaded from environment?
ignore_unknown = obj.get("IGNORE_UNKNOWN_ENVVARS_FOR_DYNACONF")
trim_len = len(env_)
data = {
key[trim_len:]: parse_conf_data(
data, tomlfy=True, box_settings=obj
)
for key, data in environ.items()
if key.startswith(env_)
and not (
# Ignore environment variables that haven't been
# pre-defined in settings space.
ignore_unknown
and obj.get(key[trim_len:], default=missing) is missing
)
}
# Update the settings space based on gathered data from environment.
if data:
filter_strategy = obj.get("FILTER_STRATEGY")
if filter_strategy:
data = filter_strategy(data)
obj.update(data, loader_identifier=identifier)
def write(settings_path, settings_data, **kwargs):
"""Write data to .env file"""
if not DOTENV_IMPORTED:
return
for key, value in settings_data.items():
quote_mode = (
isinstance(value, str)
and (value.startswith("'") or value.startswith('"'))
) or isinstance(value, (list, dict))
dotenv_cli.set_key(
str(settings_path),
key,
str(value),
quote_mode="always" if quote_mode else "none",
)