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

114 lines
3.4 KiB
Python

# coding: utf-8
"""
Tests that are specific to minimal installations.
"""
import importlib
import itertools
import os
import sys
import unittest.mock as mock
from typing import Dict
import packaging
import pytest
@pytest.mark.skipif(
os.environ.get("RAY_MINIMAL", "0") != "1",
reason="Skip unless running in a minimal install.",
)
def test_correct_python_version():
"""
Validate that Bazel uses the correct Python version in our minimal tests.
"""
expected_python_version = os.environ.get("EXPECTED_PYTHON_VERSION", "").strip()
assert (
expected_python_version
), f"EXPECTED_PYTHON_VERSION is {expected_python_version}"
actual_major, actual_minor = sys.version_info[:2]
actual_version = f"{actual_major}.{actual_minor}"
assert actual_version == expected_python_version, (
f"expected_python_version={expected_python_version}"
f"actual_version={actual_version}"
)
class MockBaseModel:
model_fields = {}
def __init__(self, *args, **kwargs):
pass
def __init_subclass__(self, *args, **kwargs):
pass
def _make_mock_pydantic_modules(pydantic_version: str) -> Dict:
"""Make a mock for the `pydantic` module.
This module requires special handling to:
- Make `BaseModel` a class object so type hints work.
- Set the `__version__` attribute appropriately.
- Also mock `pydantic.dataclasses`.
Returns a dict of mocked modules.
"""
mock_modules = {
"pydantic": mock.MagicMock(),
"pydantic.dataclasses": mock.MagicMock(),
}
mock_modules["pydantic"].BaseModel = MockBaseModel
if packaging.version.parse(pydantic_version) >= packaging.version.parse("1.9.0"):
mock_modules["pydantic"].__version__ = pydantic_version
return mock_modules
@pytest.mark.parametrize("pydantic_version", ["2.0.0"])
@pytest.mark.skipif(
os.environ.get("RAY_MINIMAL", "0") != "1",
reason="Skip unless running in a minimal install.",
)
def test_module_import_with_various_non_minimal_deps(pydantic_version: str):
optional_modules = [
"opencensus",
"prometheus_client",
"aiohttp",
"aiohttp_cors",
"pydantic",
"grpc",
]
for i in range(len(optional_modules)):
for install_modules in itertools.combinations(optional_modules, i):
print(install_modules)
mock_modules = {}
for mod in install_modules:
if mod == "pydantic":
mock_modules.update(**_make_mock_pydantic_modules(pydantic_version))
else:
mock_modules[mod] = mock.MagicMock()
with mock.patch.dict("sys.modules", mock_modules):
from ray.dashboard.utils import DashboardHeadModule, get_all_modules
get_all_modules(DashboardHeadModule)
@pytest.mark.skipif(
os.environ.get("RAY_MINIMAL", "0") != "1",
reason="Skip unless running in a minimal install.",
)
def test_pydantic_v1_is_unsupported():
mock_modules = _make_mock_pydantic_modules("1.9.0")
with mock.patch.dict("sys.modules", mock_modules):
sys.modules.pop("ray._common.pydantic_compat", None)
with pytest.raises(ImportError, match="Pydantic v1 is no longer supported"):
importlib.import_module("ray._common.pydantic_compat")
if __name__ == "__main__":
sys.exit(pytest.main(["-sv", __file__]))