diff --git a/CHANGELOG.md b/CHANGELOG.md index 00f08f58..02bad5aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Fixed - 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] +- `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] ## [1.2.3] - 2026-08-16 @@ -448,6 +449,7 @@ os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]). [#640]: https://github.com/theskumar/python-dotenv/pull/640 [#663]: https://github.com/theskumar/python-dotenv/pull/663 [#680]: https://github.com/theskumar/python-dotenv/pull/680 +[#698]: https://github.com/theskumar/python-dotenv/pull/698 [790c5c0]: https://github.com/theskumar/python-dotenv/commit/790c5c02991100aa1bf41ee5330aca75edc51311 @@ -459,6 +461,7 @@ os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]). [@Nougat-Waffle]: https://github.com/Nougat-Waffle [@Qwerty-133]: https://github.com/Qwerty-133 [@ReinerBRO]: https://github.com/ReinerBRO +[@ROTl24]: https://github.com/ROTl24 [@alanjds]: https://github.com/alanjds [@altendky]: https://github.com/altendky [@andrewsmith]: https://github.com/andrewsmith diff --git a/src/dotenv/cli.py b/src/dotenv/cli.py index 79613e28..72c81816 100644 --- a/src/dotenv/cli.py +++ b/src/dotenv/cli.py @@ -17,7 +17,7 @@ ) sys.exit(1) -from .main import dotenv_values, set_key, unset_key +from .main import DotEnv, dotenv_values, set_key, unset_key from .version import __version__ @@ -190,7 +190,7 @@ def run(ctx: click.Context, override: bool, commandline: tuple[str, ...]) -> Non ) dotenv_as_dict = { k: v - for (k, v) in dotenv_values(file).items() + for (k, v) in DotEnv(file, override=override, encoding="utf-8").dict().items() if v is not None and (override or k not in os.environ) } diff --git a/tests/test_cli.py b/tests/test_cli.py index d4e3ad4d..1a71db41 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,4 +1,5 @@ import os +import sys from pathlib import Path from typing import Optional @@ -211,6 +212,40 @@ def test_run_with_existing_variable_not_overridden(tmp_path): check_process(result, exit_code=0, stdout="C\n") +@pytest.mark.parametrize( + "option,existing_value,expected", + [ + ("--override", "environment", "file\nfile/suffix\n"), + ("--no-override", "environment", "environment\nenvironment/suffix\n"), + ("--no-override", "", "\n/suffix\n"), + ], +) +def test_run_interpolation_respects_override( + tmp_path, option, existing_value, expected +): + (tmp_path / ".env").write_text( + "DOTENV_TEST_BASE=file\nDOTENV_TEST_DERIVED=${DOTENV_TEST_BASE}/suffix\n" + ) + env = dict(os.environ) + env.pop("DOTENV_TEST_DERIVED", None) + env["DOTENV_TEST_BASE"] = existing_value + + result = run_dotenv( + [ + "run", + option, + sys.executable, + "-c", + "import os; print(os.environ['DOTENV_TEST_BASE']); " + "print(os.environ['DOTENV_TEST_DERIVED'])", + ], + cwd=tmp_path, + env=env, + ) + + check_process(result, exit_code=0, stdout=expected) + + def test_run_with_none_value(tmp_path): (tmp_path / ".env").write_text("A=x\nc")