diff --git a/litellm/__init__.py b/litellm/__init__.py index 1447e05fdf7..d274a4bfc1b 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -26,7 +26,14 @@ def _dev_env_hot_reload_enabled() -> bool: return os.getenv("LITELLM_DEV_ENV_HOT_RELOAD") == "True" -if os.getenv("LITELLM_MODE", "DEV") == "DEV": +def _should_load_dotenv() -> bool: + """Check if dotenv should be implicitly loaded (skipped in PRODUCTION or when LITELLM_DISABLE_DOTENV is set).""" + if os.getenv("LITELLM_DISABLE_DOTENV", "").lower() in ("1", "true", "t", "yes", "y"): + return False + return os.getenv("LITELLM_MODE", "DEV") == "DEV" + + +if _should_load_dotenv(): _dotenv.load_dotenv(override=_dev_env_hot_reload_enabled()) from collections.abc import Sequence diff --git a/litellm/proxy/proxy_cli.py b/litellm/proxy/proxy_cli.py index 8ac63ba25c9..42b21620068 100644 --- a/litellm/proxy/proxy_cli.py +++ b/litellm/proxy/proxy_cli.py @@ -46,7 +46,8 @@ sys.path.append(os.getcwd()) config_filename: Final = "litellm.secrets" litellm_mode: Final = os.getenv("LITELLM_MODE", "DEV") # "PRODUCTION", "DEV" -if litellm_mode == "DEV": +disable_dotenv: Final = os.getenv("LITELLM_DISABLE_DOTENV", "").lower() in ("1", "true", "t", "yes", "y") +if litellm_mode == "DEV" and not disable_dotenv: load_dotenv() from enum import Enum diff --git a/tests/test_dotenv_opt_out.py b/tests/test_dotenv_opt_out.py new file mode 100644 index 00000000000..3b98947538e --- /dev/null +++ b/tests/test_dotenv_opt_out.py @@ -0,0 +1,30 @@ +import os +from unittest.mock import patch + +from litellm import _should_load_dotenv + + +def test_should_load_dotenv_defaults(): + """By default in DEV mode, dotenv should load.""" + with patch.dict(os.environ, {"LITELLM_MODE": "DEV", "LITELLM_DISABLE_DOTENV": ""}, clear=True): + assert _should_load_dotenv() is True + + +def test_should_load_dotenv_production(): + """In PRODUCTION mode, dotenv should not load.""" + with patch.dict(os.environ, {"LITELLM_MODE": "PRODUCTION", "LITELLM_DISABLE_DOTENV": ""}, clear=True): + assert _should_load_dotenv() is False + + +def test_should_load_dotenv_disabled(): + """When LITELLM_DISABLE_DOTENV is truthy, dotenv should not load even in DEV mode.""" + for truthy_val in ("1", "true", "True", "t", "T", "yes", "YES", "y", "Y"): + with patch.dict(os.environ, {"LITELLM_MODE": "DEV", "LITELLM_DISABLE_DOTENV": truthy_val}, clear=True): + assert _should_load_dotenv() is False, f"Failed for LITELLM_DISABLE_DOTENV={truthy_val}" + + +def test_should_load_dotenv_falsy(): + """When LITELLM_DISABLE_DOTENV is explicitly false, dotenv should load in DEV mode.""" + for falsy_val in ("0", "false", "False", "no", "NO"): + with patch.dict(os.environ, {"LITELLM_MODE": "DEV", "LITELLM_DISABLE_DOTENV": falsy_val}, clear=True): + assert _should_load_dotenv() is True, f"Failed for LITELLM_DISABLE_DOTENV={falsy_val}"