main
py 172 lines 5.45 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """Tests for HF_HUB_OFFLINE mode."""
4
5 import importlib
6 import sys
7
8 import pytest
9 import regex as re
10 import urllib3
11
12 MODEL_CONFIGS = [
13 {
14 "model": "facebook/opt-125m",
15 "enforce_eager": True,
16 "gpu_memory_utilization": 0.20,
17 "max_model_len": 64,
18 "max_num_batched_tokens": 64,
19 "max_num_seqs": 64,
20 "tensor_parallel_size": 1,
21 },
22 {
23 "model": "Qwen/Qwen3-0.6B",
24 "enforce_eager": True,
25 "gpu_memory_utilization": 0.50,
26 "max_model_len": 64,
27 "max_num_batched_tokens": 64,
28 "max_num_seqs": 64,
29 "tensor_parallel_size": 1,
30 "tokenizer": "Qwen/Qwen3-4B",
31 },
32 {
33 "model": "mistralai/Mistral-7B-Instruct-v0.1",
34 "enforce_eager": True,
35 "gpu_memory_utilization": 0.95,
36 "max_model_len": 64,
37 "max_num_batched_tokens": 64,
38 "max_num_seqs": 64,
39 "tensor_parallel_size": 1,
40 "tokenizer_mode": "mistral",
41 },
42 # TODO: re-enable once these tests are run with V1
43 # {
44 # "model": "sentence-transformers/all-MiniLM-L12-v2",
45 # "enforce_eager": True,
46 # "gpu_memory_utilization": 0.20,
47 # "max_model_len": 64,
48 # "max_num_batched_tokens": 64,
49 # "max_num_seqs": 64,
50 # "tensor_parallel_size": 1,
51 # },
52 ]
53
54
55 def _create_runner(vllm_runner, model_config):
56 runner_config = model_config.copy()
57 model = runner_config.pop("model")
58 tokenizer_name = runner_config.pop("tokenizer", None)
59 return vllm_runner(model, tokenizer_name=tokenizer_name, **runner_config)
60
61
62 @pytest.fixture(scope="module")
63 def cache_models(vllm_runner):
64 # Cache model files first
65 for model_config in MODEL_CONFIGS:
66 with _create_runner(vllm_runner, model_config):
67 pass
68
69 yield
70
71
72 @pytest.mark.skip_global_cleanup
73 @pytest.mark.usefixtures("cache_models")
74 def test_offline_mode(monkeypatch: pytest.MonkeyPatch, vllm_runner):
75 # Set HF to offline mode and ensure we can still construct an LLM
76 with monkeypatch.context() as m:
77 try:
78 m.setenv("HF_HUB_OFFLINE", "1")
79 m.setenv("VLLM_NO_USAGE_STATS", "1")
80
81 def disable_connect(*args, **kwargs):
82 raise RuntimeError("No http calls allowed")
83
84 m.setattr(
85 urllib3.connection.HTTPConnection,
86 "connect",
87 disable_connect,
88 )
89 m.setattr(
90 urllib3.connection.HTTPSConnection,
91 "connect",
92 disable_connect,
93 )
94
95 # Need to re-import huggingface_hub
96 # and friends to set up offline mode
97 _re_import_modules()
98 # Cached model files should be used in offline mode
99 for model_config in MODEL_CONFIGS:
100 with _create_runner(vllm_runner, model_config):
101 pass
102 finally:
103 # Reset the environment after the test
104 # NB: Assuming tests are run in online mode
105 _re_import_modules()
106
107
108 def _re_import_modules():
109 hf_hub_module_names = [k for k in sys.modules if k.startswith("huggingface_hub")]
110 transformers_module_names = [
111 k
112 for k in sys.modules
113 if k.startswith("transformers") and not k.startswith("transformers_modules")
114 ]
115
116 # These modules are aliased in Transformers v5 and so cannot be reloaded directly
117 aliased_module_patterns = [
118 r".+\.tokenization_utils$",
119 r".+\.tokenization_utils_fast$",
120 r".+\.image_processing_utils_fast$",
121 r".+\.models\..+\.image_processing_.+_fast$",
122 ]
123
124 reload_exception = None
125 for module_name in hf_hub_module_names + transformers_module_names:
126 if any(re.match(pattern, module_name) for pattern in aliased_module_patterns):
127 # Remove from sys.modules so they are re-aliased on next import
128 del sys.modules[module_name]
129 continue
130 try:
131 importlib.reload(sys.modules[module_name])
132 except Exception as e:
133 reload_exception = e
134 # Try to continue clean up so that other tests are less likely to
135 # be affected
136
137 # Error this test if reloading a module failed
138 if reload_exception is not None:
139 raise reload_exception
140
141
142 @pytest.mark.skip_global_cleanup
143 @pytest.mark.usefixtures("cache_models")
144 def test_model_from_huggingface_offline(monkeypatch: pytest.MonkeyPatch, vllm_runner):
145 # Set HF to offline mode and ensure we can still construct an LLM
146 with monkeypatch.context() as m:
147 try:
148 m.setenv("HF_HUB_OFFLINE", "1")
149 m.setenv("VLLM_NO_USAGE_STATS", "1")
150
151 def disable_connect(*args, **kwargs):
152 raise RuntimeError("No http calls allowed")
153
154 m.setattr(
155 urllib3.connection.HTTPConnection,
156 "connect",
157 disable_connect,
158 )
159 m.setattr(
160 urllib3.connection.HTTPSConnection,
161 "connect",
162 disable_connect,
163 )
164 # Need to re-import huggingface_hub
165 # and friends to set up offline mode
166 _re_import_modules()
167 with vllm_runner("facebook/opt-125m"):
168 pass
169 finally:
170 # Reset the environment after the test
171 # NB: Assuming tests are run in online mode
172 _re_import_modules()