From 0b1ec79d4b9149cf9d7b546fd377e2829366f13d Mon Sep 17 00:00:00 2001 From: ckarnell <7363269+ckarnell@users.noreply.github.com> Date: Mon, 17 Aug 2026 02:37:34 -0400 Subject: [PATCH] Substitute ${name:-default} when the variable is set but empty (POSIX) The README documents POSIX variable expansion, where ${name:-word} substitutes when name is unset OR null. resolve() used env.get(name, default), which falls back only when the key is absent, so a variable that exists and is empty returned empty. Resolve the name first and fall back when the result is empty. ${name} with no default and ${name:-} on an empty value are unchanged. --- src/dotenv/variables.py | 6 ++++-- tests/test_main.py | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/dotenv/variables.py b/src/dotenv/variables.py index 667f2f26..4e2ff717 100644 --- a/src/dotenv/variables.py +++ b/src/dotenv/variables.py @@ -62,8 +62,10 @@ def __hash__(self) -> int: return hash((self.__class__, self.name, self.default)) def resolve(self, env: Mapping[str, Optional[str]]) -> str: - default = self.default if self.default is not None else "" - result = env.get(self.name, default) + result = env.get(self.name) + if not result and self.default is not None: + # POSIX ${name:-default} substitutes when name is unset OR null. + return self.default return result if result is not None else "" diff --git a/tests/test_main.py b/tests/test_main.py index 48dd7bf4..296d2f20 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -702,6 +702,11 @@ def test_dotenv_values_file(dotenv_path): # Undefined ({}, "a=${b}", True, {"a": ""}), ({}, "a=${b:-d}", True, {"a": "d"}), + # Defined but empty: POSIX ${name:-default} substitutes on null too + ({"b": ""}, "a=${b:-d}", True, {"a": "d"}), + ({}, "b=\na=${b:-d}", True, {"a": "d", "b": ""}), + ({"b": ""}, "a=${b}", True, {"a": ""}), + ({"b": ""}, "a=${b:-}", True, {"a": ""}), # With quotes ({"b": "c"}, 'a="${b}"', True, {"a": "c"}), ({"b": "c"}, "a='${b}'", True, {"a": "c"}),