Files
2026-07-13 13:17:40 +08:00

122 lines
2.8 KiB
Python

import sys
from inspect import getmembers, isfunction, ismodule
import pytest
import ray
from ray._common.test_utils import run_string_as_driver
# NOTE: Before adding a new API to Ray (and modifying this test), the new API
# must have Ray Client support.
def test_api_functions():
# These are pulled from the "Python API" of the Ray Docs
# util.queue.Queue & util.ActorPool are removed because they are under
# util.*, not the top-level Ray namespace.
PYTHON_API = [
"init",
"is_initialized",
"remote",
"get",
"wait",
"put",
"kill",
"cancel",
"get_actor",
"get_gpu_ids",
"shutdown",
"method",
"nodes",
"timeline",
"cluster_resources",
"available_resources",
"java_function",
"java_actor_class",
"client",
]
OTHER_ALLOWED_FUNCTIONS = [
# In the RuntimeContext API
"get_runtime_context",
]
IMPL_FUNCTIONS = ["__getattr__"]
functions = getmembers(ray, isfunction)
function_names = [f[0] for f in functions]
assert set(function_names) == set(
PYTHON_API + OTHER_ALLOWED_FUNCTIONS + IMPL_FUNCTIONS
)
def test_non_ray_modules():
modules = getmembers(ray, ismodule)
for name, mod in modules:
assert "ray" in str(mod), f"Module {mod} should not be reachable via ray.{name}"
def test_dynamic_subpackage_import():
# Test that subpackages are dynamically imported and properly cached.
script = """
import sys
import ray
# ray.autoscaler
assert "ray.autoscaler" not in sys.modules
ray.autoscaler
# Check that the package is cached.
assert "ray.autoscaler" in sys.modules
"""
run_string_as_driver(script)
def test_dynamic_subpackage_missing():
# Test nonexistent subpackage dynamic attribute access and imports raise expected
# errors.
script = """
import ray
# Test that nonexistent subpackage attribute access raises an AttributeError.
try:
ray.foo # noqa:F401
except AttributeError:
pass
# Test that nonexistent subpackage import raises an ImportError.
try:
from ray.foo import bar # noqa:F401
except ImportError:
pass
"""
run_string_as_driver(script)
def test_dynamic_subpackage_fallback_only():
# Test that the __getattr__ dynamic
script = """
import ray
import sys
assert "ray._raylet" in sys.modules
assert ray.__getattribute__("_raylet") is ray._raylet
try:
ray.__getattr__("_raylet")
except AttributeError:
pass
"""
run_string_as_driver(script)
def test_for_strings():
strings = getmembers(ray, lambda obj: isinstance(obj, str))
for string, _ in strings:
assert string.startswith("__"), f"Invalid string: {string} found in "
"top level Ray. Please delete at the end of __init__.py."
if __name__ == "__main__":
sys.exit(pytest.main(["-sv", __file__]))