Skip to content

Commit e0310e5

Browse files
authored
fix: honor --no-override when expanding variables in dotenv run (#698)
Fixes #697.
1 parent a00cb2e commit e0310e5

3 files changed

Lines changed: 40 additions & 2 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1010
### Fixed
1111

1212
- An unquoted empty value followed by an inline comment (e.g. `KEY= # comment`) is now parsed as an empty string instead of the comment text by [@Noethix55555] in [#663]
13+
- `dotenv run --no-override` now expands variable references with the same precedence as `load_dotenv(override=False)`, so a value like `${BASE}/suffix` uses the existing `BASE` from the environment instead of the one from the `.env` file by [@ROTl24] in [#698]
1314

1415
## [1.2.3] - 2026-08-16
1516

@@ -448,6 +449,7 @@ os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]).
448449
[#640]: https://github.com/theskumar/python-dotenv/pull/640
449450
[#663]: https://github.com/theskumar/python-dotenv/pull/663
450451
[#680]: https://github.com/theskumar/python-dotenv/pull/680
452+
[#698]: https://github.com/theskumar/python-dotenv/pull/698
451453
[790c5c0]: https://github.com/theskumar/python-dotenv/commit/790c5c02991100aa1bf41ee5330aca75edc51311
452454

453455
<!-- contributors -->
@@ -459,6 +461,7 @@ os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]).
459461
[@Nougat-Waffle]: https://github.com/Nougat-Waffle
460462
[@Qwerty-133]: https://github.com/Qwerty-133
461463
[@ReinerBRO]: https://github.com/ReinerBRO
464+
[@ROTl24]: https://github.com/ROTl24
462465
[@alanjds]: https://github.com/alanjds
463466
[@altendky]: https://github.com/altendky
464467
[@andrewsmith]: https://github.com/andrewsmith

‎src/dotenv/cli.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
)
1818
sys.exit(1)
1919

20-
from .main import dotenv_values, set_key, unset_key
20+
from .main import DotEnv, dotenv_values, set_key, unset_key
2121
from .version import __version__
2222

2323

@@ -190,7 +190,7 @@ def run(ctx: click.Context, override: bool, commandline: tuple[str, ...]) -> Non
190190
)
191191
dotenv_as_dict = {
192192
k: v
193-
for (k, v) in dotenv_values(file).items()
193+
for (k, v) in DotEnv(file, override=override, encoding="utf-8").dict().items()
194194
if v is not None and (override or k not in os.environ)
195195
}
196196

‎tests/test_cli.py‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import sys
23
from pathlib import Path
34
from typing import Optional
45

@@ -211,6 +212,40 @@ def test_run_with_existing_variable_not_overridden(tmp_path):
211212
check_process(result, exit_code=0, stdout="C\n")
212213

213214

215+
@pytest.mark.parametrize(
216+
"option,existing_value,expected",
217+
[
218+
("--override", "environment", "file\nfile/suffix\n"),
219+
("--no-override", "environment", "environment\nenvironment/suffix\n"),
220+
("--no-override", "", "\n/suffix\n"),
221+
],
222+
)
223+
def test_run_interpolation_respects_override(
224+
tmp_path, option, existing_value, expected
225+
):
226+
(tmp_path / ".env").write_text(
227+
"DOTENV_TEST_BASE=file\nDOTENV_TEST_DERIVED=${DOTENV_TEST_BASE}/suffix\n"
228+
)
229+
env = dict(os.environ)
230+
env.pop("DOTENV_TEST_DERIVED", None)
231+
env["DOTENV_TEST_BASE"] = existing_value
232+
233+
result = run_dotenv(
234+
[
235+
"run",
236+
option,
237+
sys.executable,
238+
"-c",
239+
"import os; print(os.environ['DOTENV_TEST_BASE']); "
240+
"print(os.environ['DOTENV_TEST_DERIVED'])",
241+
],
242+
cwd=tmp_path,
243+
env=env,
244+
)
245+
246+
check_process(result, exit_code=0, stdout=expected)
247+
248+
214249
def test_run_with_none_value(tmp_path):
215250
(tmp_path / ".env").write_text("A=x\nc")
216251

0 commit comments

Comments
 (0)