From 14a66ff80ccd84a3ca14276a4368e323ab5cf730 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Mon, 23 Nov 2020 12:23:46 +0100 Subject: [PATCH] Fix #1356 -- Allow to override config file settings with env vars --- doc/admin/config.rst | 8 +++++++ src/pretix/helpers/config.py | 43 ++++++++++++++++++++++++++++++++++++ src/pretix/settings.py | 11 +++++---- 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 src/pretix/helpers/config.py diff --git a/doc/admin/config.rst b/doc/admin/config.rst index 53c465ddc..dc1dfab3b 100644 --- a/doc/admin/config.rst +++ b/doc/admin/config.rst @@ -23,6 +23,14 @@ The config file may contain the following sections (all settings are optional an default values). We suggest that you start from the examples given in one of the installation tutorials. +.. note:: + + The configuration file is the recommended way to configure pretix. However, you can + also set them through environment variables. In this case, the syntax is + ``PRETIX_SECTION_CONFIG``. For example, to configure the setting ``password_reset`` + from the ``[pretix]`` section, set ``PRETIX_PRETIX_PASSWORD_RESET=off`` in your + environment. + pretix settings --------------- diff --git a/src/pretix/helpers/config.py b/src/pretix/helpers/config.py new file mode 100644 index 000000000..ad609e050 --- /dev/null +++ b/src/pretix/helpers/config.py @@ -0,0 +1,43 @@ +import os +import re +from configparser import _UNSET + + +class EnvOrParserConfig: + def __init__(self, configparser): + self.cp = configparser + + def _envkey(self, section, option): + section = re.sub('[^a-zA-Z0-9]', '_', section.upper()) + option = re.sub('[^a-zA-Z0-9]', '_', option.upper()) + return f'PRETIX_{section}_{option}' + + def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET): + if self._envkey(section, option) in os.environ: + return os.environ[self._envkey(section, option)] + return self.cp.get(section, option, raw=raw, vars=vars, fallback=fallback) + + def getint(self, section, option, *, raw=False, vars=None, fallback=_UNSET): + if self._envkey(section, option) in os.environ: + return int(os.environ[self._envkey(section, option)]) + return self.cp.getint(section, option, raw=raw, vars=vars, fallback=fallback) + + def getfloat(self, section, option, *, raw=False, vars=None, fallback=_UNSET): + if self._envkey(section, option) in os.environ: + return float(os.environ[self._envkey(section, option)]) + return self.cp.getfloat(section, option, raw=raw, vars=vars, fallback=fallback) + + def getboolean(self, section, option, *, raw=False, vars=None, fallback=_UNSET): + if self._envkey(section, option) in os.environ: + return self.cp._convert_to_boolean(os.environ[self._envkey(section, option)]) + return self.cp.getboolean(section, option, raw=raw, vars=vars, fallback=fallback) + + def has_section(self, section): + if any(k.startswith(self._envkey(section, '')) for k in os.environ): + return True + return self.cp.has_section(section) + + def has_option(self, section, option): + if self._envkey(section, option) in os.environ: + return True + return self.cp.has_option(section, option) diff --git a/src/pretix/settings.py b/src/pretix/settings.py index 484fe7f5d..e49025403 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -11,16 +11,19 @@ from pkg_resources import iter_entry_points from pycountry import currencies from . import __version__ +from .helpers.config import EnvOrParserConfig + from django.contrib.messages import constants as messages # NOQA from django.utils.translation import gettext_lazy as _ # NOQA -config = configparser.RawConfigParser() +_config = configparser.RawConfigParser() if 'PRETIX_CONFIG_FILE' in os.environ: - config.read_file(open(os.environ.get('PRETIX_CONFIG_FILE'), encoding='utf-8')) + _config.read_file(open(os.environ.get('PRETIX_CONFIG_FILE'), encoding='utf-8')) else: - config.read(['/etc/pretix/pretix.cfg', os.path.expanduser('~/.pretix.cfg'), 'pretix.cfg'], - encoding='utf-8') + _config.read(['/etc/pretix/pretix.cfg', os.path.expanduser('~/.pretix.cfg'), 'pretix.cfg'], + encoding='utf-8') +config = EnvOrParserConfig(_config) CONFIG_FILE = config BASE_DIR = os.path.dirname(os.path.dirname(__file__))