diff --git a/.gitignore b/.gitignore index 295eb22b..9cbfa3b4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ .coverage reports/ __pycache__/ +config/app-merged.yaml +config/app-custom.yaml diff --git a/Dockerfile b/Dockerfile index 1688264f..a7631c04 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,7 @@ COPY requirements/prod.txt requirements.txt RUN pip install -r requirements.txt COPY slackhealthbot slackhealthbot +COPY config/app-default.yaml config/app-default.yaml COPY templates templates COPY alembic.ini alembic.ini COPY alembic alembic diff --git a/README.md b/README.md index 49c937f6..b64df189 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Pushes messages to a pre-selected Slack channel, when users log new weight data * Create an application in the [Fitbit developer dashboard](https://dev.fitbit.com/apps/). * Create an application [on Slack](https://api.slack.com/apps), with a webhook to post messages to a specific channel. * Copy the `.env.template` file to `.env`, and modify the values. +* [Optional]: Copy the `config/app-custom.yaml.template` file to `app-custom.yaml`, and override any values which are defined in `config/app-default.yaml`. ## Retrieve the docker image @@ -36,7 +37,7 @@ Create a folder on the host where the database will be saved: `/path/to/data/`. Run the docker image. ``` -docker run --detach --publish 8000:8000 -v `pwd`/.env:/app/.env -v /path/to/data/:/tmp/data ghcr.io/caarmen/slack-health-bot +docker run --detach --publish 8000:8000 -v `pwd`/.env:/app/.env -v `pwd`/app-custom.yaml:/app/config/app-custom.yaml -v /path/to/data/:/tmp/data ghcr.io/caarmen/slack-health-bot ``` ## Using the application diff --git a/config/app-custom.yaml.template b/config/app-custom.yaml.template new file mode 100644 index 00000000..f4010e19 --- /dev/null +++ b/config/app-custom.yaml.template @@ -0,0 +1,4 @@ +# Place any overrides of the default values, from app-default.yaml, into this file. +app: + logging: + sql_log_level: "DEBUG" # example override: set sql logging to DEBUG \ No newline at end of file diff --git a/config/app.yaml b/config/app-default.yaml similarity index 100% rename from config/app.yaml rename to config/app-default.yaml diff --git a/slackhealthbot/settings.py b/slackhealthbot/settings.py index c637cc81..affb06fc 100644 --- a/slackhealthbot/settings.py +++ b/slackhealthbot/settings.py @@ -2,7 +2,9 @@ import datetime as dt from pathlib import Path +import yaml from pydantic import AnyHttpUrl, BaseModel, HttpUrl +from pydantic.v1.utils import deep_update from pydantic_settings import ( BaseSettings, PydanticBaseSettingsSource, @@ -73,7 +75,27 @@ class AppSettings(BaseSettings): app: App withings: Withings fitbit: Fitbit - model_config = SettingsConfigDict(yaml_file="config/app.yaml") + model_config = SettingsConfigDict(yaml_file="config/app-merged.yaml") + + @classmethod + def _load_yaml_file( + cls, + path: str, + required: bool, + ) -> dict: + try: + with open(path, "r", encoding="utf-8") as file: + return yaml.safe_load(file) + except OSError as e: + if required: + raise e + return {} + + @classmethod + def _load_merged_config(cls) -> dict: + default_config = cls._load_yaml_file("config/app-default.yaml", required=True) + custom_config = cls._load_yaml_file("config/app-custom.yaml", required=False) + return deep_update(default_config, custom_config) @classmethod def settings_customise_sources( @@ -82,6 +104,9 @@ def settings_customise_sources( *args, **kwargs, ) -> tuple[PydanticBaseSettingsSource, ...]: + merged_config = cls._load_merged_config() + with open("config/app-merged.yaml", "w", encoding="utf-8") as file: + yaml.safe_dump(merged_config, file) yaml_settings_source = YamlConfigSettingsSource(settings_cls) return (yaml_settings_source,)