feat: Add env var to suppress experimental warnings

Checked with local wheel and worked as intended. The harness shows suppression works: 0 warnings for all true-like values.

This CL adds ADK_DISABLE_EXPERIMENTAL_WARNING to let the users to suppress warning messages from features decorated with @experimental.

Previously, using experimental features would always trigger a UserWarning. This change creates a way to disable these warnings, which can be good to stop flooding logs.

The warning is suppressed if ADK_DISABLE_EXPERIMENTAL_WARNING is set to a truthy value such as "true", "1", "yes", or "on" (case-insensitive).

Added unit tests to make sure:
Warning suppression for functions and classes when the env var is set.
Case-insensitivity and various truthy values for the env var.
Loading the env var from a .env file.

PiperOrigin-RevId: 796649404
This commit is contained in:
George Weale
2025-08-18 17:59:13 -07:00
committed by Copybara-Service
parent f8fd6a4f09
commit 4afc9b2f33
2 changed files with 71 additions and 8 deletions
+12 -6
View File
@@ -26,6 +26,13 @@ import warnings
T = TypeVar("T", bound=Union[Callable, type]) T = TypeVar("T", bound=Union[Callable, type])
def _is_truthy_env(var_name: str) -> bool:
value = os.environ.get(var_name)
if value is None:
return False
return value.strip().lower() in ("1", "true", "yes", "on")
def _make_feature_decorator( def _make_feature_decorator(
*, *,
label: str, label: str,
@@ -66,9 +73,8 @@ def _create_decorator(
@functools.wraps(orig_init) @functools.wraps(orig_init)
def new_init(self, *args, **kwargs): def new_init(self, *args, **kwargs):
# Check if usage should be bypassed via environment variable at call time # Check if usage should be bypassed via environment variable at call time
should_bypass = ( should_bypass = bypass_env_var is not None and _is_truthy_env(
bypass_env_var is not None bypass_env_var
and os.environ.get(bypass_env_var, "").lower() == "true"
) )
if should_bypass: if should_bypass:
@@ -88,9 +94,8 @@ def _create_decorator(
@functools.wraps(obj) @functools.wraps(obj)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
# Check if usage should be bypassed via environment variable at call time # Check if usage should be bypassed via environment variable at call time
should_bypass = ( should_bypass = bypass_env_var is not None and _is_truthy_env(
bypass_env_var is not None bypass_env_var
and os.environ.get(bypass_env_var, "").lower() == "true"
) )
if should_bypass: if should_bypass:
@@ -143,6 +148,7 @@ experimental = _make_feature_decorator(
" versions without notice. It may introduce breaking changes at any" " versions without notice. It may introduce breaking changes at any"
" time." " time."
), ),
bypass_env_var="ADK_SUPPRESS_EXPERIMENTAL_FEATURE_WARNINGS",
) )
"""Mark a class or a function as an experimental feature. """Mark a class or a function as an experimental feature.
@@ -206,8 +206,12 @@ def test_working_in_progress_loads_from_dotenv_file():
del os.environ["ADK_ALLOW_WIP_FEATURES"] del os.environ["ADK_ALLOW_WIP_FEATURES"]
def test_experimental_function_warns(): def test_experimental_function_warns(monkeypatch):
"""Test that experimental function shows warnings (unchanged behavior).""" """Test that experimental function shows warnings (unchanged behavior)."""
# Ensure environment variable is not set
monkeypatch.delenv(
"ADK_SUPPRESS_EXPERIMENTAL_FEATURE_WARNINGS", raising=False
)
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always") warnings.simplefilter("always")
@@ -220,8 +224,12 @@ def test_experimental_function_warns():
assert "breaking change in the future" in str(w[0].message) assert "breaking change in the future" in str(w[0].message)
def test_experimental_class_warns(): def test_experimental_class_warns(monkeypatch):
"""Test that experimental class shows warnings (unchanged behavior).""" """Test that experimental class shows warnings (unchanged behavior)."""
# Ensure environment variable is not set
monkeypatch.delenv(
"ADK_SUPPRESS_EXPERIMENTAL_FEATURE_WARNINGS", raising=False
)
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always") warnings.simplefilter("always")
@@ -235,6 +243,55 @@ def test_experimental_class_warns():
assert "class may change" in str(w[0].message) assert "class may change" in str(w[0].message)
def test_experimental_function_bypassed_with_env_var(monkeypatch):
"""Experimental function emits no warning when bypass env var is true."""
true_values = ["true", "True", "TRUE", "1", "yes", "YES", "on", "ON"]
for true_val in true_values:
monkeypatch.setenv("ADK_SUPPRESS_EXPERIMENTAL_FEATURE_WARNINGS", true_val)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
result = experimental_fn()
assert result == "executing"
assert len(w) == 0, f"Bypass failed for env value {true_val}"
def test_experimental_class_bypassed_with_env_var(monkeypatch):
"""Experimental class emits no warning when bypass env var is true."""
true_values = ["true", "True", "TRUE", "1", "yes", "YES", "on", "ON"]
for true_val in true_values:
monkeypatch.setenv("ADK_SUPPRESS_EXPERIMENTAL_FEATURE_WARNINGS", true_val)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
exp_class = ExperimentalClass()
result = exp_class.run()
assert result == "running experimental"
assert len(w) == 0, f"Bypass failed for env value {true_val}"
def test_experimental_function_not_bypassed_for_false_env_var(monkeypatch):
"""Experimental function still warns for non-true bypass env var values."""
false_values = ["false", "False", "FALSE", "0", "", "no", "off"]
for false_val in false_values:
monkeypatch.setenv("ADK_SUPPRESS_EXPERIMENTAL_FEATURE_WARNINGS", false_val)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
experimental_fn()
assert len(w) == 1
assert "[EXPERIMENTAL] experimental_fn:" in str(w[0].message)
def test_experimental_class_not_bypassed_for_false_env_var(monkeypatch):
"""Experimental class still warns for non-true bypass env var values."""
false_values = ["false", "False", "FALSE", "0", "", "no", "off"]
for false_val in false_values:
monkeypatch.setenv("ADK_SUPPRESS_EXPERIMENTAL_FEATURE_WARNINGS", false_val)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
ExperimentalClass()
assert len(w) == 1
assert "[EXPERIMENTAL] ExperimentalClass:" in str(w[0].message)
def test_experimental_class_no_parens_warns(): def test_experimental_class_no_parens_warns():
"""Test that experimental class without parentheses shows default warning.""" """Test that experimental class without parentheses shows default warning."""
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w: