diff --git a/configurations/base.py b/configurations/base.py index 121e80d..a860755 100644 --- a/configurations/base.py +++ b/configurations/base.py @@ -95,6 +95,7 @@ def OTHER(self): """ DOTENV_LOADED = None + DOTENV_RELOAD = False @classmethod def load_dotenv(cls): @@ -109,6 +110,18 @@ def load_dotenv(cls): # check if the class has DOTENV set whether with a path or None dotenv = getattr(cls, 'DOTENV', None) + required = True + overwrite_env = False + # check if the DOTENV is dict, and check all options of it + if isinstance(dotenv, dict): + # whether we want to overwrite previously set envs + overwrite_env = dotenv.get("overwrite", False) + # whether we want to error if the file is not found + required = dotenv.get("required", True) + # whether we want to reload on dotenv, useful if we want to frequently change it + cls.DOTENV_RELOAD = dotenv.get("reload", False) + dotenv = dotenv.get("path", None) + # if DOTENV is falsy we want to disable it if not dotenv: return @@ -118,6 +131,8 @@ def load_dotenv(cls): with open(dotenv, 'r') as f: content = f.read() except OSError as e: + if not required: + return raise ImproperlyConfigured("Couldn't read .env file " "with the path {}. Error: " "{}".format(dotenv, e)) from e @@ -133,13 +148,16 @@ def load_dotenv(cls): m3 = re.match(r'\A"(.*)"\Z', val) if m3: val = re.sub(r'\\(.)', r'\1', m3.group(1)) - os.environ.setdefault(key, val) + if overwrite_env: + os.environ[key] = val + else: + os.environ.setdefault(key, val) cls.DOTENV_LOADED = dotenv @classmethod def pre_setup(cls): - if cls.DOTENV_LOADED is None: + if cls.DOTENV_LOADED is None or cls.DOTENV_RELOAD: cls.load_dotenv() @classmethod diff --git a/docs/cookbook.rst b/docs/cookbook.rst index 0a3d76f..1d8be60 100644 --- a/docs/cookbook.rst +++ b/docs/cookbook.rst @@ -57,6 +57,20 @@ A ``.env`` file is a ``.ini``-style file. It must contain a list of API_KEY1=1234 API_KEY2=5678 +``DOTENV`` can also be a dictionary, and then its behavior can be configured more: +.. code-block:: python + BASE_DIR = os.path.dirname(os.path.dirname(__file__)) + + class Dev(Configuration): + DOTENV = { + "path": str(os.path.join(BASE_DIR, '.env')), + # if True, overwrites previously set environmental variables, if False only sets them if they haven't been set before + "overwrite": True, + # if True errors if the DOTENV is not found at path, if False return + "required": False, + # if True, reloads DOTENV dynamically for example on hot reload + "reload": True, + Envdir ------