A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 2, 08:30 UTC
[BugFix] Fix `_has_module` to verify native deps via trial import (#44035)
Signed-off-by: esmeetu <jasonailu87@gmail.com> Signed-off-by: Jeffrey Wang <jeffreywang@anyscale.com> Signed-off-by: Nick Hill <nickhill123@gmail.com> Co-authored-by: esmeetu <jasonailu87@gmail.com> Co-authored-by: Nick Hill <nickhill123@gmail.com>
Jeffrey Wang committed
May 31, 2026 at 22:06 UTC
29d69332aa658a96698a456e044763321f4bbd82
2 files changed
+110
-5
tests/utils_/test_import_utils.py
+94
-1
@@ -1,8 +1,10 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+from unittest.mock import MagicMock, patch
4
+
5
import pytest
6
5
-from vllm.utils.import_utils import PlaceholderModule
7
+from vllm.utils.import_utils import PlaceholderModule, _has_module
8
9
10
def _raises_module_not_found():
@@ -44,3 +46,94 @@ def test_placeholder_module_error_handling():
46
with _raises_module_not_found():
47
# Test conflict with internal __module attribute
48
_ = placeholder_attr.module
49
+
50
+
51
+class TestHasModule:
52
+ """Tests for _has_module with trial import verification."""
53
+
54
+ def setup_method(self):
55
+ # Clear the @cache between tests so each test gets a fresh call
56
+ _has_module.cache_clear()
57
+
58
+ def test_returns_true_for_importable_stdlib_module(self):
59
+ assert _has_module("json") is True
60
+
61
+ def test_returns_false_for_nonexistent_module(self):
62
+ assert _has_module("nonexistent_module_xyz_12345") is False
63
+
64
+ def test_returns_false_when_find_spec_succeeds_but_import_fails(self):
65
+ """Simulate a native extension whose shared library is missing.
66
+
67
+ ``find_spec`` finds the package on disk, but the actual import
68
+ raises ``ImportError`` (e.g. missing ``libcudart.so``).
69
+ """
70
+ fake_spec = MagicMock()
71
+
72
+ with (
73
+ patch(
74
+ "vllm.utils.import_utils.importlib.util.find_spec",
75
+ return_value=fake_spec,
76
+ ),
77
+ patch(
78
+ "vllm.utils.import_utils.importlib.import_module",
79
+ side_effect=ImportError(
80
+ "libcudart.so.12: cannot open shared object file"
81
+ ),
82
+ ),
83
+ ):
84
+ assert _has_module("fake_native_ext") is False
85
+
86
+ def test_returns_false_on_os_error_during_import(self):
87
+ """Some shared-library failures surface as ``OSError``."""
88
+ fake_spec = MagicMock()
89
+
90
+ with (
91
+ patch(
92
+ "vllm.utils.import_utils.importlib.util.find_spec",
93
+ return_value=fake_spec,
94
+ ),
95
+ patch(
96
+ "vllm.utils.import_utils.importlib.import_module",
97
+ side_effect=OSError("cannot load library"),
98
+ ),
99
+ ):
100
+ assert _has_module("fake_native_ext_os") is False
101
+
102
+ def test_returns_false_on_unexpected_error_during_import(self):
103
+ """A broken extension may raise a non-import error (e.g. ``RuntimeError``).
104
+
105
+ Such modules are not usable, so ``_has_module`` should still return
106
+ ``False`` rather than letting the exception propagate.
107
+ """
108
+ fake_spec = MagicMock()
109
+
110
+ with (
111
+ patch(
112
+ "vllm.utils.import_utils.importlib.util.find_spec",
113
+ return_value=fake_spec,
114
+ ),
115
+ patch(
116
+ "vllm.utils.import_utils.importlib.import_module",
117
+ side_effect=RuntimeError("CUDA driver version is insufficient"),
118
+ ),
119
+ ):
120
+ assert _has_module("fake_broken_ext") is False
121
+
122
+ def test_returns_false_when_find_spec_raises(self):
123
+ """``find_spec`` itself can raise for dotted names whose parent package
124
+ fails to import. This should be treated as the module being unavailable.
125
+ """
126
+ with patch(
127
+ "vllm.utils.import_utils.importlib.util.find_spec",
128
+ side_effect=ModuleNotFoundError("No module named 'fake_parent'"),
129
+ ):
130
+ assert _has_module("fake_parent.child") is False
131
+
132
+ def test_result_is_cached(self):
133
+ """Verify the @cache decorator prevents repeated imports."""
134
+ _has_module("json") # prime the cache
135
+
136
+ with patch("vllm.utils.import_utils.importlib.util.find_spec") as mock_spec:
137
+ result = _has_module("json") # should hit cache
138
+ mock_spec.assert_not_called()
139
+ assert result is True
vllm/utils/import_utils.py
+16
-4
@@ -392,12 +392,24 @@ class LazyLoader(ModuleType):
392
# Optional dependency detection utilities
393
@cache
394
def _has_module(module_name: str) -> bool:
395
- """Return True if *module_name* can be found in the current environment.
395
+ """Return True if *module_name* can be imported in the current environment.
396
397
- The result is cached so that subsequent queries for the same module incur
398
- no additional overhead.
397
+ Uses ``importlib.util.find_spec`` as a fast pre-check, then performs a
398
+ trial import to verify that native dependencies (shared libraries, etc.)
399
+ are also satisfied. Any failure during the trial import is treated as the
400
+ module being unavailable. The result is cached so that subsequent queries
401
+ for the same module incur no additional overhead.
402
"""
400
- return importlib.util.find_spec(module_name) is not None
403
+ try:
404
+ if importlib.util.find_spec(module_name) is None:
405
+ return False
406
+ importlib.import_module(module_name)
407
+ except ImportError:
408
+ logger.warning(
409
+ "Module %s was found but failed to import", module_name, exc_info=True
410
+ )
411
+ return False
412
+ return True
413
414
415
def has_deep_ep() -> bool: