mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
chore: Raise error when using features decorated by working_in_progress decorator
set environment variable ADK_ALLOW_WIP_FEATURES=true can bypass it. working_in_progress features are not working. ADK users are not supposed to set this environment variable. PiperOrigin-RevId: 771333335
This commit is contained in:
committed by
Copybara-Service
parent
233fd20243
commit
8932106246
@@ -1,3 +1,5 @@
|
||||
import os
|
||||
import tempfile
|
||||
import warnings
|
||||
|
||||
from google.adk.utils.feature_decorator import experimental
|
||||
@@ -11,25 +13,176 @@ class IncompleteFeature:
|
||||
return "running"
|
||||
|
||||
|
||||
@working_in_progress("function not ready")
|
||||
def wip_function():
|
||||
return "executing"
|
||||
|
||||
|
||||
@experimental("api may have breaking change in the future.")
|
||||
def experimental_fn():
|
||||
return "executing"
|
||||
|
||||
|
||||
def test_working_in_progress_class_warns():
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
@experimental("class may change")
|
||||
class ExperimentalClass:
|
||||
|
||||
def run(self):
|
||||
return "running experimental"
|
||||
|
||||
|
||||
def test_working_in_progress_class_raises_error():
|
||||
"""Test that WIP class raises RuntimeError by default."""
|
||||
# Ensure environment variable is not set
|
||||
if "ADK_ALLOW_WIP_FEATURES" in os.environ:
|
||||
del os.environ["ADK_ALLOW_WIP_FEATURES"]
|
||||
|
||||
try:
|
||||
feature = IncompleteFeature()
|
||||
|
||||
assert feature.run() == "running"
|
||||
assert len(w) == 1
|
||||
assert issubclass(w[0].category, UserWarning)
|
||||
assert "[WIP] IncompleteFeature:" in str(w[0].message)
|
||||
assert "don't use yet" in str(w[0].message)
|
||||
assert False, "Expected RuntimeError to be raised"
|
||||
except RuntimeError as e:
|
||||
assert "[WIP] IncompleteFeature:" in str(e)
|
||||
assert "don't use yet" in str(e)
|
||||
|
||||
|
||||
def test_experimental_method_warns():
|
||||
def test_working_in_progress_function_raises_error():
|
||||
"""Test that WIP function raises RuntimeError by default."""
|
||||
# Ensure environment variable is not set
|
||||
if "ADK_ALLOW_WIP_FEATURES" in os.environ:
|
||||
del os.environ["ADK_ALLOW_WIP_FEATURES"]
|
||||
|
||||
try:
|
||||
result = wip_function()
|
||||
assert False, "Expected RuntimeError to be raised"
|
||||
except RuntimeError as e:
|
||||
assert "[WIP] wip_function:" in str(e)
|
||||
assert "function not ready" in str(e)
|
||||
|
||||
|
||||
def test_working_in_progress_class_bypassed_with_env_var():
|
||||
"""Test that WIP class works without warnings when env var is set."""
|
||||
# Set the bypass environment variable
|
||||
os.environ["ADK_ALLOW_WIP_FEATURES"] = "true"
|
||||
|
||||
try:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
|
||||
feature = IncompleteFeature()
|
||||
result = feature.run()
|
||||
|
||||
assert result == "running"
|
||||
# Should have no warnings when bypassed
|
||||
assert len(w) == 0
|
||||
finally:
|
||||
# Clean up environment variable
|
||||
if "ADK_ALLOW_WIP_FEATURES" in os.environ:
|
||||
del os.environ["ADK_ALLOW_WIP_FEATURES"]
|
||||
|
||||
|
||||
def test_working_in_progress_function_bypassed_with_env_var():
|
||||
"""Test that WIP function works without warnings when env var is set."""
|
||||
# Set the bypass environment variable
|
||||
os.environ["ADK_ALLOW_WIP_FEATURES"] = "true"
|
||||
|
||||
try:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
|
||||
result = wip_function()
|
||||
|
||||
assert result == "executing"
|
||||
# Should have no warnings when bypassed
|
||||
assert len(w) == 0
|
||||
finally:
|
||||
# Clean up environment variable
|
||||
if "ADK_ALLOW_WIP_FEATURES" in os.environ:
|
||||
del os.environ["ADK_ALLOW_WIP_FEATURES"]
|
||||
|
||||
|
||||
def test_working_in_progress_env_var_case_insensitive():
|
||||
"""Test that WIP bypass works with different case values."""
|
||||
test_cases = ["true", "True", "TRUE", "tRuE"]
|
||||
|
||||
for case in test_cases:
|
||||
os.environ["ADK_ALLOW_WIP_FEATURES"] = case
|
||||
|
||||
try:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
|
||||
result = wip_function()
|
||||
|
||||
assert result == "executing"
|
||||
assert len(w) == 0
|
||||
finally:
|
||||
if "ADK_ALLOW_WIP_FEATURES" in os.environ:
|
||||
del os.environ["ADK_ALLOW_WIP_FEATURES"]
|
||||
|
||||
|
||||
def test_working_in_progress_env_var_false_values():
|
||||
"""Test that WIP still raises errors with false-like env var values."""
|
||||
false_values = ["false", "False", "FALSE", "0", "", "anything_else"]
|
||||
|
||||
for false_val in false_values:
|
||||
os.environ["ADK_ALLOW_WIP_FEATURES"] = false_val
|
||||
|
||||
try:
|
||||
result = wip_function()
|
||||
assert False, f"Expected RuntimeError with env var '{false_val}'"
|
||||
except RuntimeError as e:
|
||||
assert "[WIP] wip_function:" in str(e)
|
||||
finally:
|
||||
if "ADK_ALLOW_WIP_FEATURES" in os.environ:
|
||||
del os.environ["ADK_ALLOW_WIP_FEATURES"]
|
||||
|
||||
|
||||
def test_working_in_progress_loads_from_dotenv_file():
|
||||
"""Test that WIP decorator can load environment variables from .env file."""
|
||||
# Skip test if dotenv is not available
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
except ImportError:
|
||||
import pytest
|
||||
|
||||
pytest.skip("python-dotenv not available")
|
||||
|
||||
# Ensure environment variable is not set in os.environ
|
||||
if "ADK_ALLOW_WIP_FEATURES" in os.environ:
|
||||
del os.environ["ADK_ALLOW_WIP_FEATURES"]
|
||||
|
||||
# Create a temporary .env file in current directory
|
||||
dotenv_path = ".env.test"
|
||||
|
||||
try:
|
||||
# Write the env file
|
||||
with open(dotenv_path, "w") as f:
|
||||
f.write("ADK_ALLOW_WIP_FEATURES=true\n")
|
||||
|
||||
# Load the environment variables from the file
|
||||
load_dotenv(dotenv_path)
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
|
||||
# This should work because the .env file contains ADK_ALLOW_WIP_FEATURES=true
|
||||
result = wip_function()
|
||||
|
||||
assert result == "executing"
|
||||
# Should have no warnings when bypassed via .env file
|
||||
assert len(w) == 0
|
||||
|
||||
finally:
|
||||
# Clean up
|
||||
try:
|
||||
os.unlink(dotenv_path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
if "ADK_ALLOW_WIP_FEATURES" in os.environ:
|
||||
del os.environ["ADK_ALLOW_WIP_FEATURES"]
|
||||
|
||||
|
||||
def test_experimental_function_warns():
|
||||
"""Test that experimental function shows warnings (unchanged behavior)."""
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
|
||||
@@ -40,3 +193,18 @@ def test_experimental_method_warns():
|
||||
assert issubclass(w[0].category, UserWarning)
|
||||
assert "[EXPERIMENTAL] experimental_fn:" in str(w[0].message)
|
||||
assert "breaking change in the future" in str(w[0].message)
|
||||
|
||||
|
||||
def test_experimental_class_warns():
|
||||
"""Test that experimental class shows warnings (unchanged behavior)."""
|
||||
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) == 1
|
||||
assert issubclass(w[0].category, UserWarning)
|
||||
assert "[EXPERIMENTAL] ExperimentalClass:" in str(w[0].message)
|
||||
assert "class may change" in str(w[0].message)
|
||||
|
||||
Reference in New Issue
Block a user