diff --git a/CHANGELOG.md b/CHANGELOG.md index 00f08f58..734978ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 `` 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 @@ -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 @@ -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 diff --git a/src/dotenv/main.py b/src/dotenv/main.py index 3123690a..251a34da 100644 --- a/src/dotenv/main.py +++ b/src/dotenv/main.py @@ -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() @@ -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) diff --git a/tests/test_main.py b/tests/test_main.py index 6f9d4c5c..00c53342 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -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())", "", "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" )