feat: env_prefix create_app variable can select the environment var prefix

This commit is contained in:
Éloi Rivard 2024-04-22 18:10:49 +02:00
parent b8645ce1a3
commit afa0a6ff1e
No known key found for this signature in database
GPG key ID: 7EDA204EA57DD184
4 changed files with 43 additions and 15 deletions

View file

@ -1,9 +1,13 @@
Added
^^^^^
- `env_prefix` create_app variable can select the environment var prefix.
[0.0.52] - 2024-04-22
---------------------
Added
^^^^^
- `ENV_FILE` environment variable can customize/disable the .env file
- `env_file` create_app variable can customize/disable the .env file
Changed
^^^^^^^

View file

@ -124,7 +124,9 @@ def setup_flask_converters(app):
app.url_map.converters[model_name.lower()] = model_converter(model_class)
def create_app(config=None, validate=True, backend=None):
def create_app(
config=None, validate=True, backend=None, env_file=".env", env_prefix=""
):
from .app.configuration import setup_config
from .app.i18n import setup_i18n
from .app.themes import setup_themer
@ -132,7 +134,13 @@ def create_app(config=None, validate=True, backend=None):
app = Flask(__name__)
with app.app_context():
if not setup_config(app, config, validate): # pragma: no cover
if not setup_config(
app=app,
config=config,
test_config=validate,
env_file=env_file,
env_prefix=env_prefix,
): # pragma: no cover
sys.exit(1)
sentry_sdk = setup_sentry(app)

View file

@ -13,7 +13,6 @@ from pydantic_settings import SettingsConfigDict
from canaille.core.configuration import CoreSettings
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DEFAULT_ENV_FILE = ".env"
class RootSettings(BaseSettings):
@ -60,10 +59,10 @@ class RootSettings(BaseSettings):
"""
def settings_factory(config):
"""Overly complicated function that pushes the backend specific
configuration into CoreSettings, in the purpose break dependency against
backends libraries like python-ldap or sqlalchemy."""
def settings_factory(config, env_file=".env", env_prefix=""):
"""Pushes the backend specific configuration into CoreSettings, in the
purpose break dependency against backends libraries like python-ldap or
sqlalchemy."""
attributes = {"CANAILLE": (CoreSettings, CoreSettings())}
if "CANAILLE_SQL" in config or any(
@ -93,11 +92,11 @@ def settings_factory(config):
**attributes,
)
env_file = os.getenv("ENV_FILE", config.get("ENV_FILE", DEFAULT_ENV_FILE))
return Settings(
**config,
_secrets_dir=os.environ.get("SECRETS_DIR"),
_env_file=env_file,
_env_prefix=env_prefix,
)
@ -121,7 +120,7 @@ def toml_content(file_path):
raise Exception("toml library not installed. Cannot load configuration.")
def setup_config(app, config=None, test_config=True):
def setup_config(app, config=None, test_config=True, env_file=".env", env_prefix=""):
from canaille.oidc.installation import install
app.config.from_mapping(
@ -135,7 +134,9 @@ def setup_config(app, config=None, test_config=True):
config = toml_content(os.environ.get("CONFIG"))
try:
config_obj = settings_factory(config or {})
config_obj = settings_factory(
config or {}, env_file=env_file, env_prefix=env_prefix
)
except ValidationError as exc: # pragma: no cover
app.logger.critical(str(exc))
return False

View file

@ -41,6 +41,7 @@ def test_configuration_nestedsecrets_directory(tmp_path, backend, configuration)
def test_configuration_from_environment_vars():
"""Canaille should read configuration from environment vars."""
os.environ["SECRET_KEY"] = "very-very-secret"
os.environ["CANAILLE__SMTP__FROM_ADDR"] = "user@mydomain.tld"
os.environ["CANAILLE_SQL__DATABASE_URI"] = "sqlite:///anything.db"
@ -60,6 +61,22 @@ def test_configuration_from_environment_vars():
del os.environ["CANAILLE_SQL__DATABASE_URI"]
def test_disable_env_var_loading(tmp_path, configuration):
"""Canaille should not read configuration from environment vars when
env_prefix is False."""
del configuration["SERVER_NAME"]
os.environ["SERVER_NAME"] = "example.com"
os.environ["FOOBAR_SERVER_NAME"] = "foobar.example.com"
app = create_app(configuration, env_prefix="")
assert app.config["SERVER_NAME"] == "example.com"
app = create_app(configuration, env_prefix="FOOBAR_")
assert app.config["SERVER_NAME"] == "foobar.example.com"
del os.environ["SERVER_NAME"]
def test_dotenv_file(tmp_path, configuration):
"""Canaille should read configuration from .env files."""
oldcwd = os.getcwd()
@ -81,8 +98,7 @@ def test_custom_dotenv_file(tmp_path, configuration):
with open(dotenv, "w") as fd:
fd.write("FOOBAR=other-custom-value")
configuration["ENV_FILE"] = dotenv
app = create_app(configuration)
app = create_app(configuration, env_file=dotenv)
assert app.config["FOOBAR"] == "other-custom-value"
@ -95,8 +111,7 @@ def test_disable_dotenv_file(tmp_path, configuration):
with open(dotenv, "w") as fd:
fd.write("FOOBAR=custom-value")
configuration["ENV_FILE"] = None
app = create_app(configuration)
app = create_app(configuration, env_file=None)
assert "FOOBAR" not in app.config
os.chdir(oldcwd)