Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Fixed

- Restore current-directory `.env` discovery in interactive consoles that report
pseudo-filenames such as `<input>` by [@cucuwang] in [#596]
- 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]

## [1.2.3] - 2026-08-16
Expand Down Expand Up @@ -436,6 +438,7 @@ os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]).
[#583]: https://github.com/theskumar/python-dotenv/issues/583
[#586]: https://github.com/theskumar/python-dotenv/issues/586
[#590]: https://github.com/theskumar/python-dotenv/issues/590
[#596]: https://github.com/theskumar/python-dotenv/issues/596
[#607]: https://github.com/theskumar/python-dotenv/issues/607
[#588]: https://github.com/theskumar/python-dotenv/issues/588
[#579]: https://github.com/theskumar/python-dotenv/pull/579
Expand Down Expand Up @@ -508,6 +511,7 @@ os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]).
[@JYOuyang]: https://github.com/JYOuyang
[@burnout-projects]: https://github.com/burnout-projects
[@cpackham-atlnz]: https://github.com/cpackham-atlnz
[@cucuwang]: https://github.com/cucuwang
[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.2.3...HEAD
[1.2.3]: https://github.com/theskumar/python-dotenv/compare/v1.2.2...v1.2.3
[1.2.2]: https://github.com/theskumar/python-dotenv/compare/v1.2.1...v1.2.2
Expand Down
14 changes: 11 additions & 3 deletions src/dotenv/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,9 @@ def _is_interactive():
def _is_debugger():
return sys.gettrace() is not None

def _is_pseudo_filename(source_path: str) -> bool:
return source_path.startswith("<") and source_path.endswith(">")

if usecwd or _is_interactive() or _is_debugger() or getattr(sys, "frozen", False):
# Should work without __file__, e.g. in REPL or IPython notebook.
path = os.getcwd()
Expand All @@ -366,13 +369,18 @@ def _is_debugger():
frame = sys._getframe()
current_file = __file__

while frame.f_code.co_filename == current_file or not os.path.exists(
frame.f_code.co_filename
while frame.f_code.co_filename == current_file or (
not _is_pseudo_filename(frame.f_code.co_filename)
and not os.path.exists(frame.f_code.co_filename)
):
assert frame.f_back is not None
frame = frame.f_back
frame_filename = frame.f_code.co_filename
path = os.path.dirname(os.path.abspath(frame_filename))
path = (
os.getcwd()
if _is_pseudo_filename(frame_filename)
else os.path.dirname(os.path.abspath(frame_filename))
)

for dirname in _walk_to_root(path):
check_path = os.path.join(dirname, filename)
Expand Down
29 changes: 29 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,35 @@ def test_find_dotenv_found(tmp_path):
assert result == str(dotenv_path)


def test_find_dotenv_from_pseudo_filename(tmp_path):
project_dir = tmp_path / "project"
project_dir.mkdir()
dotenv_path = project_dir / ".env"
dotenv_path.write_text("TEST=test\n")

console_driver = tmp_path / "console_driver.py"
console_driver.write_text(
textwrap.dedent(
"""
from dotenv import find_dotenv

console_code = compile("print(find_dotenv())", "<input>", "exec")
exec(console_code)
"""
)
)

result = subprocess.run(
[sys.executable, str(console_driver)],
cwd=project_dir,
check=True,
capture_output=True,
text=True,
)

assert result.stdout.strip() == str(dotenv_path)


@pytest.mark.skipif(
sys.platform == "win32", reason="This test assumes case-sensitive variable names"
)
Expand Down