Skip to content

Commit 1523b5c

Browse files
author
Richard Cohn
committed
Apply variable expansion to default values
If a default includes a reference to a variable, expand that reference. See test_environs.test_default_expands. Note: type for subs_default is required because of a bug in mypy: python/mypy#5423
1 parent b95960b commit 1523b5c

File tree

2 files changed

+21
-8
lines changed

2 files changed

+21
-8
lines changed

environs/__init__.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,15 @@ def method(
7272
field = field_or_factory(missing=missing, **kwargs)
7373
else:
7474
field = field_or_factory(subcast=subcast, missing=missing, **kwargs)
75-
parsed_key, raw_value, proxied_key = self._get_from_environ(name, ma.missing)
75+
parsed_key, value, proxied_key = self._get_from_environ(name, field.missing)
7676
self._fields[parsed_key] = field
7777
source_key = proxied_key or parsed_key
78-
if raw_value is ma.missing and field.missing is ma.missing:
78+
if value is ma.missing:
7979
if self.eager:
8080
raise EnvError('Environment variable "{}" not set'.format(proxied_key or parsed_key))
8181
else:
8282
self._errors[parsed_key].append("Environment variable not set.")
8383
return None
84-
if raw_value or raw_value == "":
85-
value = raw_value
86-
else:
87-
value = field.missing if field.missing is not ma.missing else None
8884
if preprocess:
8985
value = preprocess(value, subcast=subcast, **kwargs)
9086
try:
@@ -438,10 +434,12 @@ def _get_from_environ(
438434
if hasattr(value, "strip"):
439435
expand_match = self.expand_vars and _EXPANDED_VAR_PATTERN.match(value)
440436
if expand_match: # Full match expand_vars - special case keep default
441-
proxied_key = expand_match.groups()[0]
442-
subs_default = expand_match.groups()[1]
437+
proxied_key: _StrType = expand_match.groups()[0]
438+
subs_default: typing.Optional[_StrType] = expand_match.groups()[1]
443439
if subs_default is not None:
444440
default = subs_default[2:]
441+
elif value == default: # if we have used default, don't use it recursively
442+
default = ma.missing
445443
return (key, self._get_from_environ(proxied_key, default, proxied=True)[1], proxied_key)
446444
expand_search = self.expand_vars and _EXPANDED_VAR_PATTERN.search(value)
447445
if expand_search: # Multiple or in text match expand_vars - General case - default lost

tests/test_environs.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ def test_call(self, set_env, env):
4747
set_env({"STR": "foo", "INT": "42"})
4848
assert env("STR") == "foo"
4949
assert env("NOT_SET", "mydefault") == "mydefault"
50+
with pytest.raises(environs.EnvError, match='Environment variable "NOT_SET" not set'):
51+
assert env("NOT_SET")
5052

5153
def test_call_with_default(self, env):
5254
assert env("NOT_SET", default="mydefault") == "mydefault"
@@ -761,6 +763,19 @@ def test_recursive_expands(self, env, set_env):
761763
)
762764
assert env.str("PGURL") == "postgres://gnarvaja:secret@localhost"
763765

766+
def test_default_expands(self, env, set_env):
767+
set_env(
768+
{
769+
"MAIN": "${SUBSTI}",
770+
"SUBSTI": "substivalue",
771+
}
772+
)
773+
assert env.str("NOT_SET", "${SUBSTI}") == "substivalue"
774+
assert env.str("NOT_SET", "${MAIN}") == "substivalue"
775+
assert env.str("NOT_SET", "${NOT_SET2:-set2}") == "set2"
776+
with pytest.raises(environs.EnvError, match='Environment variable "NOT_SET2" not set'):
777+
assert env.str("NOT_SET", "${NOT_SET2}")
778+
764779
def test_escaped_expand(self, env, set_env):
765780
set_env({"ESCAPED_EXPAND": r"\${ESCAPED}", "ESCAPED": "fail"})
766781
assert env.str("ESCAPED_EXPAND") == r"${ESCAPED}"

0 commit comments

Comments
 (0)