Files
ray-project--ray/python/ray/tune/tests/test_env_callbacks.py
T
2026-07-13 13:17:40 +08:00

109 lines
3.3 KiB
Python

import os
from unittest.mock import MagicMock, patch
import pytest
from ray.tune.constants import RAY_TUNE_CALLBACKS_ENV_VAR
from ray.tune.utils.callback import Callback, _initialize_env_callbacks
class MockCallback(Callback):
pass
@pytest.mark.parametrize(
"env_value,expected_callback_count",
[
("my.module.Callback1", 1),
("module1.Callback1,module2.Callback2", 2),
("", 0),
(" ", 0),
("module.Callback1, ,module.Callback2", 2),
],
)
@patch("importlib.import_module")
def test_env_callbacks_loading(mock_import, env_value, expected_callback_count):
"""Test loading execution callbacks from environment variable with various inputs."""
if env_value:
with patch.dict(os.environ, {RAY_TUNE_CALLBACKS_ENV_VAR: env_value}):
mock_module = MagicMock()
mock_module.Callback1 = MockCallback
mock_module.Callback2 = MockCallback
mock_import.return_value = mock_module
callbacks = _initialize_env_callbacks()
assert len(callbacks) == expected_callback_count
for callback in callbacks:
assert isinstance(callback, MockCallback)
else:
with patch.dict(
os.environ, {RAY_TUNE_CALLBACKS_ENV_VAR: env_value}, clear=True
):
callbacks = _initialize_env_callbacks()
assert len(callbacks) == 0
@pytest.mark.parametrize(
"env_value,original_error_type",
[
("invalid_module", ValueError),
("module.Class", TypeError),
("module.NonExistentClass", AttributeError),
],
)
@patch("importlib.import_module")
def test_callback_loading_errors(mock_import, env_value, original_error_type):
"""Test handling of various error conditions when loading callbacks."""
with patch.dict(os.environ, {RAY_TUNE_CALLBACKS_ENV_VAR: env_value}):
if "invalid_module" in env_value:
pass
elif "NonExistentClass" in env_value:
mock_module = MagicMock()
del mock_module.NonExistentClass
mock_import.return_value = mock_module
else:
mock_module = MagicMock()
class RegularClass:
pass
mock_module.Class = RegularClass
mock_import.return_value = mock_module
with pytest.raises(
ValueError, match=f"Failed to import callback from '{env_value}'"
) as exc_info:
_initialize_env_callbacks()
assert isinstance(exc_info.value.__cause__, original_error_type)
def test_import_error_handling():
"""Test handling of import errors when loading callbacks."""
with patch.dict(
os.environ, {RAY_TUNE_CALLBACKS_ENV_VAR: "nonexistent.module.TestCallback"}
):
with pytest.raises(
ValueError,
match="Failed to import callback from 'nonexistent.module.TestCallback'",
) as exc_info:
_initialize_env_callbacks()
assert isinstance(exc_info.value.__cause__, ImportError)
def test_no_env_variable():
"""Test that no callbacks are loaded when environment variable is not set."""
if RAY_TUNE_CALLBACKS_ENV_VAR in os.environ:
del os.environ[RAY_TUNE_CALLBACKS_ENV_VAR]
callbacks = _initialize_env_callbacks()
assert len(callbacks) == 0
if __name__ == "__main__":
import sys
sys.exit(pytest.main(["-v", __file__]))