diff --git a/src/dotenv/main.py b/src/dotenv/main.py index 3123690a..eae47245 100644 --- a/src/dotenv/main.py +++ b/src/dotenv/main.py @@ -369,10 +369,15 @@ def _is_debugger(): while frame.f_code.co_filename == current_file or not os.path.exists( frame.f_code.co_filename ): - assert frame.f_back is not None + if frame.f_back is None: + # No usable caller frame (e.g. stdin, ``python -c``, runpy). + # Fall back to cwd instead of raising AssertionError (#499). + path = os.getcwd() + break frame = frame.f_back - frame_filename = frame.f_code.co_filename - path = os.path.dirname(os.path.abspath(frame_filename)) + else: + frame_filename = frame.f_code.co_filename + path = 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..a22de65c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,4 +1,5 @@ import io +from pathlib import Path import logging import os import stat @@ -412,6 +413,34 @@ def test_find_dotenv_found(tmp_path): assert result == str(dotenv_path) +def test_find_dotenv_no_assert_when_stack_exhausted(tmp_path): + """Regression for #499: exhausted caller stack must not raise AssertionError. + + ``python -c`` / runpy leaves frames whose ``co_filename`` does not exist on + disk; walking past them used to ``assert frame.f_back is not None``. Fall + back to cwd instead. + """ + dotenv_path = tmp_path / ".env" + dotenv_path.write_text("A=1\n") + env = {**os.environ, "PYTHONPATH": str(Path(__file__).resolve().parents[1] / "src")} + # -c has no real caller file; previously AssertionError. + proc = subprocess.run( + [ + sys.executable, + "-c", + "from dotenv import find_dotenv; print(find_dotenv())", + ], + cwd=str(tmp_path), + env=env, + capture_output=True, + text=True, + check=False, + ) + assert proc.returncode == 0, proc.stderr + assert proc.stdout.strip() == str(dotenv_path) + + + @pytest.mark.skipif( sys.platform == "win32", reason="This test assumes case-sensitive variable names" )