diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 6f311d97..57c4c8dd 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is inspired by `Keep a Changelog `_
and this project adheres to `Semantic Versioning `_.
+`v0.11.2`_ - 1-September-2023
+-------------------------------
+Fixed
++++++
+- Revert "Add variable expansion." feature
+ due to `#490 `_.
+
+
`v0.11.1`_ - 30-August-2023
---------------------------
Fixed
@@ -380,6 +388,7 @@ Added
- Initial release.
+.. _v0.11.2: https://github.com/joke2k/django-environ/compare/v0.11.1...v0.11.2
.. _v0.11.1: https://github.com/joke2k/django-environ/compare/v0.11.0...v0.11.1
.. _v0.11.0: https://github.com/joke2k/django-environ/compare/v0.10.0...v0.11.0
.. _v0.10.0: https://github.com/joke2k/django-environ/compare/v0.9.0...v0.10.0
@@ -396,4 +405,4 @@ Added
.. _v0.4.1: https://github.com/joke2k/django-environ/compare/v0.4...v0.4.1
.. _v0.4: https://github.com/joke2k/django-environ/compare/v0.3.1...v0.4
.. _v0.3.1: https://github.com/joke2k/django-environ/compare/v0.3...v0.3.1
-.. _v0.3: https://github.com/joke2k/django-environ/compare/v0.2.1...v0.3
+.. _v0.3: https://github.com/joke2k/django-environ/compare/v0.2.1...v0.3
\ No newline at end of file
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
index 2ab100fd..62473838 100644
--- a/docs/quickstart.rst
+++ b/docs/quickstart.rst
@@ -23,28 +23,6 @@ And use it with ``settings.py`` as follows:
:start-after: -code-begin-
:end-before: -overview-
-Variables can contain references to another variables: ``$VAR`` or ``${VAR}``.
-Referenced variables are searched in the environment and within all definitions
-in the ``.env`` file. References are checked for recursion (self-reference).
-Exception is thrown if any reference results in infinite loop on any level
-of recursion. Variable values are substituted similar to shell parameter
-expansion. Example:
-
-.. code-block:: shell
-
- # shell
- export POSTGRES_USERNAME='user' POSTGRES_PASSWORD='SECRET'
-
-.. code-block:: shell
-
- # .env
- POSTGRES_HOSTNAME='example.com'
- POSTGRES_DB='database'
- DATABASE_URL="postgres://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@${POSTGRES_HOSTNAME}:5432/${POSTGRES_DB}"
-
-The value of ``DATABASE_URL`` variable will become
-``postgres://user:SECRET@example.com:5432/database``.
-
The ``.env`` file should be specific to the environment and not checked into
version control, it is best practice documenting the ``.env`` file with an example.
For example, you can also add ``.env.dist`` with a template of your variables to
diff --git a/environ/__init__.py b/environ/__init__.py
index 38b5b6dc..28d4a5aa 100644
--- a/environ/__init__.py
+++ b/environ/__init__.py
@@ -18,10 +18,10 @@
from .environ import *
-__copyright__ = 'Copyright (C) 2013-2022 Daniele Faraglia'
+__copyright__ = 'Copyright (C) 2013-2023 Daniele Faraglia'
"""The copyright notice of the package."""
-__version__ = '0.11.1'
+__version__ = '0.11.2'
"""The version of the package."""
__license__ = 'MIT'
diff --git a/environ/environ.py b/environ/environ.py
index 644286e1..f74884be 100644
--- a/environ/environ.py
+++ b/environ/environ.py
@@ -17,9 +17,7 @@
import os
import re
import sys
-import threading
import warnings
-from os.path import expandvars
from urllib.parse import (
parse_qs,
ParseResult,
@@ -42,9 +40,6 @@
Openable = (str, os.PathLike)
logger = logging.getLogger(__name__)
-# Variables which values should not be expanded
-NOT_EXPANDED = 'DJANGO_SECRET_KEY', 'CACHE_URL'
-
def _cast(value):
# Safely evaluate an expression node or a string containing a Python
@@ -194,11 +189,7 @@ class Env:
for s in ('', 's')]
CLOUDSQL = 'cloudsql'
- VAR = re.compile(r'(?[A-Z_][0-9A-Z_]*)}?',
- re.IGNORECASE)
-
def __init__(self, **scheme):
- self._local = threading.local()
self.smart_cast = True
self.escape_proxy = False
self.prefix = ""
@@ -352,13 +343,9 @@ def path(self, var, default=NOTSET, **kwargs):
"""
return Path(self.get_value(var, default=default), **kwargs)
- def get_value(self, var, cast=None, # pylint: disable=R0913
- default=NOTSET, parse_default=False, add_prefix=True):
+ def get_value(self, var, cast=None, default=NOTSET, parse_default=False):
"""Return value for given environment variable.
- - Expand variables referenced as ``$VAR`` or ``${VAR}``.
- - Detect infinite recursion in expansion (self-reference).
-
:param str var:
Name of variable.
:param collections.abc.Callable or None cast:
@@ -367,33 +354,15 @@ def get_value(self, var, cast=None, # pylint: disable=R0913
If var not present in environ, return this instead.
:param bool parse_default:
Force to parse default.
- :param bool add_prefix:
- Whether to add prefix to variable name.
:returns: Value from environment or default (if set).
:rtype: typing.IO[typing.Any]
"""
- var_name = f'{self.prefix}{var}' if add_prefix else var
- if not hasattr(self._local, 'vars'):
- self._local.vars = set()
- if var_name in self._local.vars:
- error_msg = f"Environment variable '{var_name}' recursively "\
- "references itself (eventually)"
- raise ImproperlyConfigured(error_msg)
-
- self._local.vars.add(var_name)
- try:
- return self._get_value(
- var_name, cast=cast, default=default,
- parse_default=parse_default)
- finally:
- self._local.vars.remove(var_name)
-
- def _get_value(self, var_name, cast=None, default=NOTSET,
- parse_default=False):
+
logger.debug(
"get '%s' casted as '%s' with default '%s'",
- var_name, cast, default)
+ var, cast, default)
+ var_name = f'{self.prefix}{var}'
if var_name in self.scheme:
var_info = self.scheme[var_name]
@@ -419,37 +388,26 @@ def _get_value(self, var_name, cast=None, default=NOTSET,
value = self.ENVIRON[var_name]
except KeyError as exc:
if default is self.NOTSET:
- error_msg = f'Set the {var_name} environment variable'
+ error_msg = f'Set the {var} environment variable'
raise ImproperlyConfigured(error_msg) from exc
value = default
- # Expand variables
- if isinstance(value, (bytes, str)) and var_name not in NOT_EXPANDED:
- def repl(match_):
- return self.get_value(
- match_.group('name'), cast=cast, default=default,
- parse_default=parse_default, add_prefix=False)
-
- is_bytes = isinstance(value, bytes)
- if is_bytes:
- value = value.decode('utf-8')
- value = self.VAR.sub(repl, value)
- value = expandvars(value)
- if is_bytes:
- value = value.encode('utf-8')
-
# Resolve any proxied values
prefix = b'$' if isinstance(value, bytes) else '$'
escape = rb'\$' if isinstance(value, bytes) else r'\$'
+ if hasattr(value, 'startswith') and value.startswith(prefix):
+ value = value.lstrip(prefix)
+ value = self.get_value(value, cast=cast, default=default)
if self.escape_proxy and hasattr(value, 'replace'):
value = value.replace(escape, prefix)
# Smart casting
- if self.smart_cast and cast is None and default is not None \
- and not isinstance(default, NoValue):
- cast = type(default)
+ if self.smart_cast:
+ if cast is None and default is not None and \
+ not isinstance(default, NoValue):
+ cast = type(default)
value = None if default is None and value == '' else value
diff --git a/tests/test_expansion.py b/tests/test_expansion.py
deleted file mode 100755
index 757ee9a2..00000000
--- a/tests/test_expansion.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import pytest
-
-from environ import Env, Path
-from environ.compat import ImproperlyConfigured
-
-
-class TestExpansion:
- def setup_method(self, method):
- Env.ENVIRON = {}
- self.env = Env()
- self.env.read_env(Path(__file__, is_file=True)('test_expansion.txt'))
-
- def test_expansion(self):
- assert self.env('HELLO') == 'Hello, world!'
-
- def test_braces(self):
- assert self.env('BRACES') == 'Hello, world!'
-
- def test_recursion(self):
- with pytest.raises(ImproperlyConfigured) as excinfo:
- self.env('RECURSIVE')
- assert str(excinfo.value) == "Environment variable 'RECURSIVE' recursively references itself (eventually)"
-
- def test_transitive(self):
- with pytest.raises(ImproperlyConfigured) as excinfo:
- self.env('R4')
- assert str(excinfo.value) == "Environment variable 'R4' recursively references itself (eventually)"
diff --git a/tests/test_expansion.txt b/tests/test_expansion.txt
deleted file mode 100755
index 8290e45f..00000000
--- a/tests/test_expansion.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-VAR1='Hello'
-VAR2='world'
-HELLO="$VAR1, $VAR2!"
-BRACES="${VAR1}, ${VAR2}!"
-RECURSIVE="This variable is $RECURSIVE"
-R1="$R2"
-R2="$R3"
-R3="$R4"
-R4="$R1"