diff options
| author | 2018-11-14 13:48:44 +0000 | |
|---|---|---|
| committer | 2018-11-14 13:48:44 +0000 | |
| commit | 572d3585f6fef7d3c9c3f463d66d212261432bdc (patch) | |
| tree | 260a2356f222bfb2d28ad0011b7f7f07d330977b | |
| parent | Merge branch 'about-command-remove-old-syntax' into 'master' (diff) | |
| parent | Replace REQUIRED_ENV config tag (diff) | |
Merge branch 'req_env_var_fix' into 'master'
Allow bot token to be set in config.yml without BOT_TOKEN env var
See merge request python-discord/projects/bot!87
| -rw-r--r-- | bot/constants.py | 71 | ||||
| -rw-r--r-- | config-default.yml | 7 |
2 files changed, 42 insertions, 36 deletions
diff --git a/bot/constants.py b/bot/constants.py index 43f03d7bf..2a9796cc5 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -18,36 +18,10 @@ from pathlib import Path from typing import Dict, List import yaml -from yaml.constructor import ConstructorError log = logging.getLogger(__name__) -def _required_env_var_constructor(loader, node): - """ - Implements a custom YAML tag for loading required environment - variables. If the environment variable is set, this function - will simply return it. Otherwise, a `CRITICAL` log message is - given and the `KeyError` is re-raised. - - Example usage in the YAML configuration: - - bot: - token: !REQUIRED_ENV 'BOT_TOKEN' - """ - - value = loader.construct_scalar(node) - - try: - return os.environ[value] - except KeyError: - log.critical( - f"Environment variable `{value}` is required, but was not set. " - "Set it in your environment or override the option using it in your `config.yml`." - ) - raise - - def _env_var_constructor(loader, node): """ Implements a custom YAML tag for loading optional environment @@ -63,8 +37,12 @@ def _env_var_constructor(loader, node): default = None - try: - # Try to construct a list from this YAML node + # Check if the node is a plain string value + if node.id == 'scalar': + value = loader.construct_scalar(node) + key = str(value) + else: + # The node value is a list value = loader.construct_sequence(node) if len(value) >= 2: @@ -74,11 +52,6 @@ def _env_var_constructor(loader, node): else: # Otherwise, we just have a key key = value[0] - except ConstructorError: - # This YAML node is a plain value rather than a list, so we just have a key - value = loader.construct_scalar(node) - - key = str(value) return os.getenv(key, default) @@ -96,7 +69,9 @@ def _join_var_constructor(loader, node): yaml.SafeLoader.add_constructor("!ENV", _env_var_constructor) yaml.SafeLoader.add_constructor("!JOIN", _join_var_constructor) -yaml.SafeLoader.add_constructor("!REQUIRED_ENV", _required_env_var_constructor) + +# Pointing old tag to !ENV constructor to avoid breaking existing configs +yaml.SafeLoader.add_constructor("!REQUIRED_ENV", _env_var_constructor) with open("config-default.yml", encoding="UTF-8") as f: @@ -129,6 +104,34 @@ if Path("config.yml").exists(): _recursive_update(_CONFIG_YAML, user_config) +def check_required_keys(keys): + """ + Verifies that keys that are set to be required are present in the + loaded configuration. + """ + for key_path in keys: + lookup = _CONFIG_YAML + try: + for key in key_path.split('.'): + lookup = lookup[key] + if lookup is None: + raise KeyError(key) + except KeyError: + log.critical( + f"A configuration for `{key_path}` is required, but was not found. " + "Please set it in `config.yml` or setup an environment variable and try again." + ) + raise + + +try: + required_keys = _CONFIG_YAML['config']['required_keys'] +except KeyError: + pass +else: + check_required_keys(required_keys) + + class YAMLGetter(type): """ Implements a custom metaclass used for accessing diff --git a/config-default.yml b/config-default.yml index 2c814b11e..0019d1688 100644 --- a/config-default.yml +++ b/config-default.yml @@ -1,6 +1,6 @@ bot: - help_prefix: "bot." - token: !REQUIRED_ENV "BOT_TOKEN" + help_prefix: "bot." + token: !ENV "BOT_TOKEN" cooldowns: # Per channel, per tag. @@ -313,3 +313,6 @@ wolfram: user_limit_day: 10 guild_limit_day: 67 key: !ENV "WOLFRAM_API_KEY" + +config: + required_keys: ['bot.token'] |