Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix IS_PYDANTIC_2 logic for pydantic<1.9.0 #42708

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion python/ray/_private/pydantic_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
# In pydantic <1.9.0, __version__ attribute is missing, issue ref:
# https://github.com/pydantic/pydantic/issues/2572, so we need to check
# the existence prior to comparison.
elif hasattr(pydantic, "__version__") and packaging.version.parse(
elif not hasattr(pydantic, "__version__") or packaging.version.parse(
pydantic.__version__
) < packaging.version.parse("2.0"):
IS_PYDANTIC_2 = False
Expand Down
57 changes: 49 additions & 8 deletions python/ray/tests/test_minimal_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
Tests that are specific to minimal installations.
"""

import pytest
import unittest.mock as mock
import itertools
import packaging
import os
import sys
from typing import Dict

import pytest


@pytest.mark.skipif(
Expand All @@ -29,14 +34,45 @@ def test_correct_python_version():
)


class MockBaseModel:
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.v1` for `pydantic >= 2.0`.
- 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

if packaging.version.parse(pydantic_version) >= packaging.version.parse("2.0.0"):
mock_modules["pydantic.v1"] = mock_modules["pydantic"]

return mock_modules


@pytest.mark.parametrize("pydantic_version", ["1.8.0", "1.9.0", "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():
import unittest.mock as mock
import itertools

def test_module_import_with_various_non_minimal_deps(pydantic_version: str):
optional_modules = [
"opencensus",
"prometheus_client",
Expand All @@ -48,9 +84,14 @@ def test_module_import_with_various_non_minimal_deps():
for i in range(len(optional_modules)):
for install_modules in itertools.combinations(optional_modules, i):
print(install_modules)
with mock.patch.dict(
"sys.modules", {mod: mock.Mock() for mod in 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 get_all_modules
from ray.dashboard.utils import DashboardHeadModule

Expand Down
Loading