Make bare `hugging_face` imports forbidden (#49726)
Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com> Co-authored-by: Andreas Karatzas <akaratza@amd.com>
Harry Mellor committed
Jul 25, 2026 at 12:18 UTC
ca0defa3438832bb3fc5826d8bf2d4e572c57e3d
29 files changed
+199
-106
tests/conftest.py
+4
-4
@@ -31,7 +31,7 @@ import pytest
31
import torch
32
import torch.nn as nn
33
import torch.nn.functional as F
34
-from huggingface_hub import snapshot_download
34
+from vllm.transformers_utils.repo_utils import hf_api
35
from PIL import Image
36
from transformers import (
37
AutoConfig,
@@ -1496,7 +1496,7 @@ _dummy_gemma2_embedding_path = os.path.join(temp_dir, "dummy_gemma2_embedding")
1496
def dummy_opt_path():
1497
json_path = os.path.join(_dummy_opt_path, "config.json")
1498
if not os.path.exists(_dummy_opt_path):
1499
- snapshot_download(
1499
+ hf_api().snapshot_download(
1500
repo_id="facebook/opt-125m",
1501
local_dir=_dummy_opt_path,
1502
ignore_patterns=["*.bin", "*.bin.index.json", "*.pt", "*.h5", "*.msgpack"],
@@ -1514,7 +1514,7 @@ def dummy_opt_path():
1514
def dummy_llava_path():
1515
json_path = os.path.join(_dummy_llava_path, "config.json")
1516
if not os.path.exists(_dummy_llava_path):
1517
- snapshot_download(
1517
+ hf_api().snapshot_download(
1518
repo_id="llava-hf/llava-1.5-7b-hf",
1519
local_dir=_dummy_llava_path,
1520
ignore_patterns=[
@@ -1539,7 +1539,7 @@ def dummy_llava_path():
1539
def dummy_gemma2_embedding_path():
1540
json_path = os.path.join(_dummy_gemma2_embedding_path, "config.json")
1541
if not os.path.exists(_dummy_gemma2_embedding_path):
1542
- snapshot_download(
1542
+ hf_api().snapshot_download(
1543
repo_id="BAAI/bge-multilingual-gemma2",
1544
local_dir=_dummy_gemma2_embedding_path,
1545
ignore_patterns=[
tests/distributed/test_rocm_quick_reduce.py
+3
-3
@@ -15,12 +15,12 @@ from unittest.mock import patch
15
import pytest
16
import torch
17
import torch.distributed as dist
18
-from huggingface_hub import snapshot_download
18
19
import vllm.envs as envs
20
from vllm import LLM, SamplingParams
21
from vllm.distributed import cleanup_dist_env_and_memory
22
from vllm.platforms import current_platform
23
+from vllm.transformers_utils.repo_utils import hf_api
24
from vllm.utils.network_utils import get_open_port
25
26
pytestmark = pytest.mark.skipif(
@@ -210,11 +210,11 @@ def _log_prompt_summaries() -> None:
210
@lru_cache(maxsize=1)
211
def _get_model_path() -> str:
212
try:
213
- path = snapshot_download(repo_id=MODEL_NAME, local_files_only=True)
213
+ path = hf_api().snapshot_download(repo_id=MODEL_NAME, local_files_only=True)
214
_log(f"using cached model snapshot: {path}")
215
return path
216
except Exception:
217
- path = snapshot_download(repo_id=MODEL_NAME)
217
+ path = hf_api().snapshot_download(repo_id=MODEL_NAME)
218
_log(f"downloaded model snapshot: {path}")
219
return path
220
tests/entrypoints/conftest.py
+10
-8
@@ -190,30 +190,32 @@ number: "1" | "2"
190
@pytest.fixture(scope="session")
191
def qwen3_lora_files():
192
"""Download Qwen3 LoRA files once per test session."""
193
- from huggingface_hub import snapshot_download
193
+ from vllm.transformers_utils.repo_utils import hf_api
194
195
- return snapshot_download(repo_id="charent/self_cognition_Alice")
195
+ return hf_api().snapshot_download(repo_id="charent/self_cognition_Alice")
196
197
198
@pytest.fixture(scope="session")
199
def qwen3_meowing_lora_files():
200
"""Download Qwen3 LoRA files once per test session."""
201
- from huggingface_hub import snapshot_download
201
+ from vllm.transformers_utils.repo_utils import hf_api
202
203
- return snapshot_download(repo_id="Jackmin108/Qwen3-0.6B-Meow-LoRA")
203
+ return hf_api().snapshot_download(repo_id="Jackmin108/Qwen3-0.6B-Meow-LoRA")
204
205
206
@pytest.fixture(scope="session")
207
def qwen3_woofing_lora_files():
208
"""Download Qwen3 LoRA files once per test session."""
209
- from huggingface_hub import snapshot_download
209
+ from vllm.transformers_utils.repo_utils import hf_api
210
211
- return snapshot_download(repo_id="Jackmin108/Qwen3-0.6B-Woof-LoRA")
211
+ return hf_api().snapshot_download(repo_id="Jackmin108/Qwen3-0.6B-Woof-LoRA")
212
213
214
@pytest.fixture(scope="session")
215
def opt125_lora_files() -> str:
216
"""Download opt-125m LoRA files once per test session."""
217
- from huggingface_hub import snapshot_download
217
+ from vllm.transformers_utils.repo_utils import hf_api
218
219
- return snapshot_download(repo_id="peft-internal-testing/opt-125m-dummy-lora")
219
+ return hf_api().snapshot_download(
220
+ repo_id="peft-internal-testing/opt-125m-dummy-lora"
221
+ )
tests/entrypoints/multimodal/openai/chat_completion/test_chat_completion_with_mixed_audio_embeds.py
+5
-3
@@ -12,10 +12,10 @@ import pytest_asyncio
12
import safetensors
13
import torch
14
import torch.nn as nn
15
-from huggingface_hub import hf_hub_download
15
from transformers import AutoConfig, AutoTokenizer
16
17
from tests.utils import RemoteOpenAIServer
18
+from vllm.transformers_utils.repo_utils import hf_api
19
from vllm.utils.serial_utils import tensor2base64
20
from vllm.utils.torch_utils import is_torch_equal_or_newer
21
@@ -126,11 +126,13 @@ def qwen2audio_aligned_content_and_embeds_b64() -> tuple[str, str]:
126
content = "Describe this audio."
127
tokenizer = AutoTokenizer.from_pretrained(QWEN2AUDIO_MODEL, trust_remote_code=True)
128
129
- index_path = hf_hub_download(QWEN2AUDIO_MODEL, "model.safetensors.index.json")
129
+ index_path = hf_api().hf_hub_download(
130
+ QWEN2AUDIO_MODEL, "model.safetensors.index.json"
131
+ )
132
with open(index_path) as f:
133
weight_map = json.load(f)["weight_map"]
134
embed_key = next(k for k in weight_map if k.endswith("embed_tokens.weight"))
133
- shard_path = hf_hub_download(QWEN2AUDIO_MODEL, weight_map[embed_key])
135
+ shard_path = hf_api().hf_hub_download(QWEN2AUDIO_MODEL, weight_map[embed_key])
136
with safetensors.safe_open(shard_path, framework="pt", device="cpu") as f:
137
embed_weight = f.get_tensor(embed_key)
138
embed_layer = nn.Embedding.from_pretrained(embed_weight.to(QWEN2AUDIO_DTYPE))
tests/entrypoints/multimodal/openai/chat_completion/test_chat_completion_with_mixed_image_embeds.py
+3
-3
@@ -13,12 +13,12 @@ import pytest_asyncio
13
import safetensors
14
import torch
15
import torch.nn as nn
16
-from huggingface_hub import hf_hub_download
16
from transformers import AutoTokenizer
17
18
from tests.utils import RemoteOpenAIServer
19
from vllm.assets.image import ImageAsset
20
from vllm.multimodal.utils import encode_image_url
21
+from vllm.transformers_utils.repo_utils import hf_api
22
from vllm.utils.serial_utils import tensor2base64
23
24
MODEL_NAME = "Qwen/Qwen2-VL-2B-Instruct"
@@ -84,11 +84,11 @@ def aligned_content_and_embeds_b64() -> tuple[str, str]:
84
content = "Describe this image."
85
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
86
87
- index_path = hf_hub_download(MODEL_NAME, "model.safetensors.index.json")
87
+ index_path = hf_api().hf_hub_download(MODEL_NAME, "model.safetensors.index.json")
88
with open(index_path) as f:
89
weight_map = json.load(f)["weight_map"]
90
embed_key = next(k for k in weight_map if k.endswith("embed_tokens.weight"))
91
- shard_path = hf_hub_download(MODEL_NAME, weight_map[embed_key])
91
+ shard_path = hf_api().hf_hub_download(MODEL_NAME, weight_map[embed_key])
92
with safetensors.safe_open(shard_path, framework="pt", device="cpu") as f:
93
embed_weight = f.get_tensor(embed_key)
94
embed_layer = nn.Embedding.from_pretrained(embed_weight.to(MODEL_DTYPE))
tests/entrypoints/multimodal/openai/chat_completion/test_default_mm_loras.py
+4
-2
@@ -6,17 +6,19 @@ import os
6
import openai # use the official client for correctness check
7
import pytest
8
import pytest_asyncio
9
-from huggingface_hub import snapshot_download
9
10
from tests.conftest import AudioTestAssets
11
from tests.utils import RemoteOpenAIServer
12
+from vllm.transformers_utils.repo_utils import hf_api
13
14
# NOTE - the tests in this module are currently analogous to test_chat, but are
15
# separated to avoid OOM killing due to module-scoped servers, since we
16
# need a multimodal model for these tests.
17
18
# Contains a modality specific lora alongside the base model
19
-MULTIMODAL_MODEL_NAME = snapshot_download("microsoft/Phi-4-multimodal-instruct")
19
+MULTIMODAL_MODEL_NAME = hf_api().snapshot_download(
20
+ "microsoft/Phi-4-multimodal-instruct"
21
+)
22
AUDIO_LORA_PATH = os.path.join(MULTIMODAL_MODEL_NAME, "speech-lora")
23
24
ACTIVE_MM_LORA_RESPONSE = "Spoken text: The first words I spoke in the original chronograph, a little piece of practical poetry. Mary had a little lamb, it slept with quite a snow, and everywhere that Mary went, the lamb was sure to go." # noqa: E501
tests/entrypoints/openai/chat_completion/test_chat.py
+2
-2
@@ -27,9 +27,9 @@ MODEL_NAME = "HuggingFaceH4/zephyr-7b-beta"
27
@pytest.fixture(scope="module")
28
def zephyr_lora_files():
29
"""Download zephyr LoRA files once per test session."""
30
- from huggingface_hub import snapshot_download
30
+ from vllm.transformers_utils.repo_utils import hf_api
31
32
- return snapshot_download(repo_id="typeof/zephyr-7b-beta-lora")
32
+ return hf_api().snapshot_download(repo_id="typeof/zephyr-7b-beta-lora")
33
34
35
@pytest.fixture(scope="module")
tests/entrypoints/pooling/scoring/util.py
+2
-2
@@ -6,7 +6,6 @@ from io import BytesIO
6
import pybase64 as base64
7
import torch
8
import torch.nn.functional as F
9
-from huggingface_hub import hf_hub_download
9
from PIL import Image
10
from safetensors.torch import load_file
11
from transformers import AutoModel, AutoTokenizer
@@ -18,6 +17,7 @@ from vllm.entrypoints.chat_utils import (
17
)
18
from vllm.entrypoints.pooling.scoring.typing import ScoreMultiModalParam
19
from vllm.entrypoints.pooling.scoring.utils import compute_maxsim_score
20
+from vllm.transformers_utils.repo_utils import hf_api
21
22
23
class ColBERTScoringHfRunner(torch.nn.Module):
@@ -38,7 +38,7 @@ class ColBERTScoringHfRunner(torch.nn.Module):
38
).to(self.device)
39
self.model.eval()
40
41
- path = hf_hub_download(model_name, filename="model.safetensors")
41
+ path = hf_api().hf_hub_download(model_name, filename="model.safetensors")
42
weights = load_file(path)
43
44
self.linear_weight = weights[linear_weights_key].to(self.device).float()
tests/entrypoints/serve/sagemaker/conftest.py
+2
-2
@@ -21,9 +21,9 @@ HEADER_SAGEMAKER_NEW_SESSION_ID = "X-Amzn-SageMaker-New-Session-Id"
21
@pytest.fixture(scope="session")
22
def smollm2_lora_files():
23
"""Download LoRA files once per test session."""
24
- from huggingface_hub import snapshot_download
24
+ from vllm.transformers_utils.repo_utils import hf_api
25
26
- return snapshot_download(repo_id=LORA_ADAPTER_NAME_SMOLLM)
26
+ return hf_api().snapshot_download(repo_id=LORA_ADAPTER_NAME_SMOLLM)
27
28
29
@pytest.fixture(scope="module")
tests/entrypoints/tool_parsers/test_hermes_tool_parser.py
+2
-2
@@ -6,13 +6,13 @@ import json
6
import openai
7
import pytest
8
import pytest_asyncio
9
-from huggingface_hub import snapshot_download
9
from typing_extensions import TypedDict
10
11
from tests.utils import RemoteOpenAIServer
12
from vllm.tool_parsers.abstract_tool_parser import ToolParser
13
from vllm.tool_parsers.granite4_tool_parser import Granite4ToolParser
14
from vllm.tool_parsers.hermes_tool_parser import Hermes2ProToolParser
15
+from vllm.transformers_utils.repo_utils import hf_api
16
17
LORA_MODEL = "minpeter/LoRA-Llama-3.2-1B-tool-vllm-ci"
18
@@ -91,7 +91,7 @@ def server_config(request):
91
config = CONFIGS[request.param]
92
93
# download model and tokenizer using transformers
94
- snapshot_download(config["model"])
94
+ hf_api().snapshot_download(config["model"])
95
yield CONFIGS[request.param]
96
97
tests/kernels/quantization/test_nvfp4_emulation.py
+2
-2
@@ -2,7 +2,6 @@
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
from typing import cast
4
5
-import huggingface_hub
5
import pytest
6
import torch
7
from safetensors import safe_open
@@ -33,6 +32,7 @@ from vllm.model_executor.layers.quantization.utils.quant_utils import (
32
kNvfp4Static,
33
)
34
from vllm.platforms import current_platform
35
+from vllm.transformers_utils.repo_utils import hf_api
36
from vllm.triton_utils import triton
37
38
if current_platform.is_rocm():
@@ -56,7 +56,7 @@ MOE_MODEL_CONFIGS = {
56
@pytest.fixture(scope="module")
57
def loaded_model_files():
58
return {
59
- model_id: huggingface_hub.snapshot_download(
59
+ model_id: hf_api().snapshot_download(
60
repo_id=model_id, allow_patterns=config["shards"]
61
)
62
for model_id, config in MOE_MODEL_CONFIGS.items()
tests/lora/conftest.py
+47
-29
@@ -9,7 +9,6 @@ from unittest.mock import MagicMock
9
import pytest
10
import torch
11
import torch.nn as nn
12
-from huggingface_hub import snapshot_download
12
13
from vllm.distributed import (
14
cleanup_dist_env_and_memory,
@@ -25,6 +24,7 @@ from vllm.model_executor.layers.logits_processor import LogitsProcessor
24
from vllm.model_executor.layers.vocab_parallel_embedding import ParallelLMHead
25
from vllm.model_executor.models.interfaces import SupportsLoRA
26
from vllm.platforms import current_platform
27
+from vllm.transformers_utils.repo_utils import hf_api
28
29
30
@pytest.fixture()
@@ -170,43 +170,43 @@ def dummy_model_gate_up(default_vllm_config) -> nn.Module:
170
def mixtral_lora_files():
171
# Note: this module has incorrect adapter_config.json to test
172
# https://github.com/vllm-project/vllm/pull/5909/files.
173
- return snapshot_download(repo_id="SangBinCho/mixtral-lora")
173
+ return hf_api().snapshot_download(repo_id="SangBinCho/mixtral-lora")
174
175
176
@pytest.fixture(scope="session")
177
def chatglm3_lora_files():
178
- return snapshot_download(repo_id="jeeejeee/chatglm3-text2sql-spider")
178
+ return hf_api().snapshot_download(repo_id="jeeejeee/chatglm3-text2sql-spider")
179
180
181
@pytest.fixture(scope="session")
182
def baichuan_lora_files():
183
- return snapshot_download(repo_id="jeeejeee/baichuan7b-text2sql-spider")
183
+ return hf_api().snapshot_download(repo_id="jeeejeee/baichuan7b-text2sql-spider")
184
185
186
@pytest.fixture(scope="session")
187
def baichuan_zero_lora_files():
188
# all the lora_B weights are initialized to zero.
189
- return snapshot_download(repo_id="jeeejeee/baichuan7b-zero-init")
189
+ return hf_api().snapshot_download(repo_id="jeeejeee/baichuan7b-zero-init")
190
191
192
@pytest.fixture(scope="session")
193
def baichuan_regex_lora_files():
194
- return snapshot_download(repo_id="jeeejeee/baichuan-7b-lora-zero-regex")
194
+ return hf_api().snapshot_download(repo_id="jeeejeee/baichuan-7b-lora-zero-regex")
195
196
197
@pytest.fixture(scope="session")
198
def ilama_lora_files():
199
- return snapshot_download(repo_id="jeeejeee/ilama-text2sql-spider")
199
+ return hf_api().snapshot_download(repo_id="jeeejeee/ilama-text2sql-spider")
200
201
202
@pytest.fixture(scope="session")
203
def minicpmv_lora_files():
204
- return snapshot_download(repo_id="jeeejeee/minicpmv25-lora-pokemon")
204
+ return hf_api().snapshot_download(repo_id="jeeejeee/minicpmv25-lora-pokemon")
205
206
207
@pytest.fixture(scope="session")
208
def qwen2vl_lora_files():
209
- return snapshot_download(repo_id="jeeejeee/qwen2-vl-lora-pokemon")
209
+ return hf_api().snapshot_download(repo_id="jeeejeee/qwen2-vl-lora-pokemon")
210
211
212
@pytest.fixture(scope="session")
@@ -217,74 +217,84 @@ def qwen25vl_base_huggingface_id():
217
218
@pytest.fixture(scope="session")
219
def qwen25vl_lora_files():
220
- return snapshot_download(repo_id="jeeejeee/qwen25-vl-lora-pokemon")
220
+ return hf_api().snapshot_download(repo_id="jeeejeee/qwen25-vl-lora-pokemon")
221
222
223
@pytest.fixture(scope="session")
224
def qwen2vl_language_lora_files():
225
- return snapshot_download(repo_id="prashanth058/qwen2vl-flickr-lora-language")
225
+ return hf_api().snapshot_download(
226
+ repo_id="prashanth058/qwen2vl-flickr-lora-language"
227
+ )
228
229
230
@pytest.fixture(scope="session")
231
def qwen2vl_vision_tower_connector_lora_files():
230
- return snapshot_download(repo_id="prashanth058/qwen2vl-flickr-lora-tower-connector")
232
+ return hf_api().snapshot_download(
233
+ repo_id="prashanth058/qwen2vl-flickr-lora-tower-connector"
234
+ )
235
236
237
@pytest.fixture(scope="session")
238
def qwen2vl_vision_tower_lora_files():
235
- return snapshot_download(repo_id="prashanth058/qwen2vl-flickr-lora-tower")
239
+ return hf_api().snapshot_download(repo_id="prashanth058/qwen2vl-flickr-lora-tower")
240
241
242
@pytest.fixture(scope="session")
243
def qwen25vl_vision_lora_files():
240
- return snapshot_download(repo_id="EpochEcho/qwen2.5-3b-vl-lora-vision-connector")
244
+ return hf_api().snapshot_download(
245
+ repo_id="EpochEcho/qwen2.5-3b-vl-lora-vision-connector"
246
+ )
247
248
249
@pytest.fixture(scope="session")
250
def qwen3vl_vision_lora_files():
245
- return snapshot_download(repo_id="EpochEcho/qwen3-4b-vl-lora-vision-connector")
251
+ return hf_api().snapshot_download(
252
+ repo_id="EpochEcho/qwen3-4b-vl-lora-vision-connector"
253
+ )
254
255
256
@pytest.fixture(scope="session")
257
def qwen3_meowing_lora_files():
258
"""Download Qwen3 Meow LoRA files once per test session."""
251
- return snapshot_download(repo_id="Jackmin108/Qwen3-0.6B-Meow-LoRA")
259
+ return hf_api().snapshot_download(repo_id="Jackmin108/Qwen3-0.6B-Meow-LoRA")
260
261
262
@pytest.fixture(scope="session")
263
def qwen3_woofing_lora_files():
264
"""Download Qwen3 Woof LoRA files once per test session."""
257
- return snapshot_download(repo_id="Jackmin108/Qwen3-0.6B-Woof-LoRA")
265
+ return hf_api().snapshot_download(repo_id="Jackmin108/Qwen3-0.6B-Woof-LoRA")
266
267
268
@pytest.fixture(scope="session")
269
def tinyllama_lora_files():
262
- return snapshot_download(repo_id="jashing/tinyllama-colorist-lora")
270
+ return hf_api().snapshot_download(repo_id="jashing/tinyllama-colorist-lora")
271
272
273
@pytest.fixture(scope="session")
274
def deepseekv2_lora_files():
267
- return snapshot_download(repo_id="wuchen01/DeepSeek-V2-Lite-Chat-All-LoRA")
275
+ return hf_api().snapshot_download(repo_id="wuchen01/DeepSeek-V2-Lite-Chat-All-LoRA")
276
277
278
@pytest.fixture(scope="session")
279
def gptoss20b_lora_files():
272
- return snapshot_download(repo_id="jeeejeee/gpt-oss-20b-lora-adapter-text2sql")
280
+ return hf_api().snapshot_download(
281
+ repo_id="jeeejeee/gpt-oss-20b-lora-adapter-text2sql"
282
+ )
283
284
285
@pytest.fixture(scope="session")
286
def qwen3moe_lora_files():
277
- return snapshot_download(repo_id="jeeejeee/qwen3-moe-text2sql-spider")
287
+ return hf_api().snapshot_download(repo_id="jeeejeee/qwen3-moe-text2sql-spider")
288
289
290
@pytest.fixture(scope="session")
291
def olmoe_lora_files():
282
- return snapshot_download(repo_id="jeeejeee/olmoe-instruct-text2sql-spider")
292
+ return hf_api().snapshot_download(repo_id="jeeejeee/olmoe-instruct-text2sql-spider")
293
294
295
@pytest.fixture(scope="session")
296
def qwen3_lora_files():
287
- return snapshot_download(repo_id="charent/self_cognition_Alice")
297
+ return hf_api().snapshot_download(repo_id="charent/self_cognition_Alice")
298
299
300
@pytest.fixture(scope="session")
@@ -295,32 +305,40 @@ def llama32_lora_huggingface_id():
305
306
@pytest.fixture(scope="session")
307
def llama32_lora_files(llama32_lora_huggingface_id):
298
- return snapshot_download(repo_id=llama32_lora_huggingface_id)
308
+ return hf_api().snapshot_download(repo_id=llama32_lora_huggingface_id)
309
310
311
@pytest.fixture(scope="session")
312
def whisper_lora_files():
303
- return snapshot_download(repo_id="chengyili2005/whisper-small-mandarin-lora")
313
+ return hf_api().snapshot_download(
314
+ repo_id="chengyili2005/whisper-small-mandarin-lora"
315
+ )
316
317
318
@pytest.fixture(scope="session")
319
def qwen35_text_lora_files():
308
- return snapshot_download(repo_id="jeeejeee/qwen35-4b-text-only-sql-lora")
320
+ return hf_api().snapshot_download(repo_id="jeeejeee/qwen35-4b-text-only-sql-lora")
321
322
323
@pytest.fixture(scope="session")
324
def qwen35_vl_lora_files():
313
- return snapshot_download(repo_id="jeeejeee/qwen35-4b-all-linear-pokemon-lora")
325
+ return hf_api().snapshot_download(
326
+ repo_id="jeeejeee/qwen35-4b-all-linear-pokemon-lora"
327
+ )
328
329
330
@pytest.fixture(scope="session")
331
def qwen36_moe_2d_lora_files():
318
- return snapshot_download(repo_id="jeeejeee/qwen36-35ba3b-2d-weights-poken-lora")
332
+ return hf_api().snapshot_download(
333
+ repo_id="jeeejeee/qwen36-35ba3b-2d-weights-poken-lora"
334
+ )
335
336
337
@pytest.fixture(scope="session")
338
def qwen36_moe_3d_lora_files():
323
- return snapshot_download(repo_id="jeeejeee/qwen36-35ba3b-moe-all-linear-poken-lora")
339
+ return hf_api().snapshot_download(
340
+ repo_id="jeeejeee/qwen36-35ba3b-moe-all-linear-poken-lora"
341
+ )
342
343
344
@pytest.fixture
tests/lora/test_default_mm_loras.py
+2
-2
@@ -8,15 +8,15 @@ import os
8
import unittest.mock as mock
9
10
import pytest
11
-from huggingface_hub import snapshot_download
11
12
from vllm.lora.request import LoRARequest
13
from vllm.platforms import current_platform
14
+from vllm.transformers_utils.repo_utils import hf_api
15
16
from ..conftest import AudioTestAssets, VllmRunner
17
from ..utils import create_new_process_for_each_test
18
19
-MODEL_PATH = snapshot_download("microsoft/Phi-4-multimodal-instruct")
19
+MODEL_PATH = hf_api().snapshot_download("microsoft/Phi-4-multimodal-instruct")
20
AUDIO_LORA_PATH = os.path.join(MODEL_PATH, "speech-lora")
21
IMAGE_LORA_PATH = os.path.join(MODEL_PATH, "vision-lora")
22
tests/model_executor/model_loader/runai_streamer_loader/test_runai_model_streamer_s3.py
+2
-2
@@ -3,10 +3,10 @@
3
4
from pathlib import Path
5
6
-from huggingface_hub import snapshot_download
6
from runai_model_streamer.safetensors_streamer.streamer_mock import StreamerPatcher
7
8
from vllm.engine.arg_utils import EngineArgs
9
+from vllm.transformers_utils.repo_utils import hf_api
10
11
from .conftest import RunaiDummyExecutor
12
@@ -25,7 +25,7 @@ def test_runai_model_loader_download_files_s3_mocked_with_patch(
25
26
# Download model from HF
27
mock_model_dir = f"{tmp_path}/gpt2"
28
- snapshot_download(repo_id=test_model, local_dir=mock_model_dir)
28
+ hf_api().snapshot_download(repo_id=test_model, local_dir=mock_model_dir)
29
30
monkeypatch.setattr(
31
"vllm.transformers_utils.runai_utils.runai_list_safetensors",
tests/model_executor/model_loader/test_sharded_state_loader.py
+2
-2
@@ -9,11 +9,11 @@ from tempfile import TemporaryDirectory
9
10
import pytest
11
import torch
12
-from huggingface_hub import snapshot_download
12
13
from vllm import LLM, SamplingParams
14
from vllm.model_executor.model_loader import ShardedStateLoader
15
from vllm.platforms import current_platform
16
+from vllm.transformers_utils.repo_utils import hf_api
17
18
prompts = [
19
"Hello, my name is",
@@ -52,7 +52,7 @@ def test_filter_subtensors():
52
53
@pytest.fixture(scope="module")
54
def llama_3p2_1b_files():
55
- input_dir = snapshot_download(
55
+ input_dir = hf_api().snapshot_download(
56
"meta-llama/Llama-3.2-1B-Instruct", ignore_patterns=["*.bin*", "original/*"]
57
)
58
tests/models/language/pooling/test_colbert.py
+3
-2
@@ -126,10 +126,11 @@ def _load_hf_model(model_name: str, hf_spec: dict, device: torch.device):
126
127
def _load_projection_weight(model_name: str, hf_spec: dict, device: torch.device):
128
"""Download and return the ColBERT linear projection weight."""
129
- from huggingface_hub import hf_hub_download
129
from safetensors.torch import load_file
130
132
- path = hf_hub_download(model_name, filename=hf_spec["weights_file"])
131
+ from vllm.transformers_utils.repo_utils import hf_api
132
+
133
+ path = hf_api().hf_hub_download(model_name, filename=hf_spec["weights_file"])
134
weights = load_file(path)
135
return weights[hf_spec["weights_key"]].to(device)
136
tests/models/multimodal/generation/test_phi4mm.py
+2
-2
@@ -6,7 +6,6 @@ from collections.abc import Sequence
6
7
import pytest
8
import regex as re
9
-from huggingface_hub import snapshot_download
9
from transformers import AutoTokenizer
10
11
from vllm.assets.image import ImageAsset
@@ -14,6 +13,7 @@ from vllm.logprobs import SampleLogprobs
13
from vllm.lora.request import LoRARequest
14
from vllm.multimodal.image import convert_image_mode, rescale_image_size
15
from vllm.multimodal.media.audio import load_audio
16
+from vllm.transformers_utils.repo_utils import hf_api
17
18
from ....conftest import (
19
IMAGE_ASSETS,
@@ -35,7 +35,7 @@ HF_MULTIIMAGE_IMAGE_PROMPT = (
35
"<|user|>\n<|image_1|>\n<|image_2|>\nDescribe these images.<|end|>\n<|assistant|>\n" # noqa: E501
36
)
37
38
-model_path = snapshot_download("microsoft/Phi-4-multimodal-instruct")
38
+model_path = hf_api().snapshot_download("microsoft/Phi-4-multimodal-instruct")
39
# Since the vision-lora and speech-lora co-exist with the base model,
40
# we have to manually specify the path of the lora weights.
41
vision_lora_path = os.path.join(model_path, "vision-lora")
tests/models/multimodal/pooling/test_intern_vit.py
+2
-2
@@ -3,11 +3,11 @@
3
import pytest
4
import torch
5
import torch.nn as nn
6
-from huggingface_hub import snapshot_download
6
from transformers import AutoConfig, AutoModel, CLIPImageProcessor
7
8
from vllm.distributed import cleanup_dist_env_and_memory
9
from vllm.platforms import current_platform
10
+from vllm.transformers_utils.repo_utils import hf_api
11
from vllm.utils.torch_utils import STR_DTYPE_TO_TORCH_DTYPE
12
13
from ....conftest import ImageTestAssets
@@ -31,7 +31,7 @@ def run_intern_vit_test(
31
*,
32
dtype: str,
33
):
34
- model = snapshot_download(model_id, allow_patterns=DOWNLOAD_PATTERN)
34
+ model = hf_api().snapshot_download(model_id, allow_patterns=DOWNLOAD_PATTERN)
35
torch_dtype = STR_DTYPE_TO_TORCH_DTYPE[dtype]
36
37
img_processor = CLIPImageProcessor.from_pretrained(model)
tests/models/multimodal/pooling/test_radio.py
+2
-2
@@ -3,13 +3,13 @@
3
import pytest
4
import torch
5
import torch.nn as nn
6
-from huggingface_hub import snapshot_download
6
from transformers import AutoConfig, AutoModel, CLIPImageProcessor
7
8
from vllm.distributed import cleanup_dist_env_and_memory
9
from vllm.model_executor.models.radio import RadioModel
10
from vllm.platforms import current_platform
11
from vllm.transformers_utils.configs.radio import RadioConfig
12
+from vllm.transformers_utils.repo_utils import hf_api
13
from vllm.utils.torch_utils import STR_DTYPE_TO_TORCH_DTYPE
14
15
from ....conftest import ImageTestAssets
@@ -28,7 +28,7 @@ def run_radio_test(
28
*,
29
dtype: str,
30
):
31
- model = snapshot_download(model_id, allow_patterns=DOWNLOAD_PATTERN)
31
+ model = hf_api().snapshot_download(model_id, allow_patterns=DOWNLOAD_PATTERN)
32
torch_dtype = STR_DTYPE_TO_TORCH_DTYPE[dtype]
33
34
img_processor = CLIPImageProcessor.from_pretrained(model)
tests/models/quantization/test_gpt_oss.py
+2
-1
@@ -22,6 +22,7 @@ import pytest
22
from packaging import version
23
24
from vllm.platforms import current_platform
25
+from vllm.transformers_utils.repo_utils import hf_api
26
27
if current_platform.is_rocm():
28
from vllm.platforms.rocm import on_gfx950
@@ -47,7 +48,7 @@ QUARK_MXFP4_AVAILABLE = importlib.util.find_spec("quark") is not None and versio
48
49
def has_huggingface_access(repo):
50
try:
50
- huggingface_hub.list_repo_refs(repo)
51
+ hf_api().list_repo_refs(repo)
52
return True
53
except huggingface_hub.errors.RepositoryNotFoundError:
54
return False
tests/plugins_tests/gguf/test_gguf_plugin_multimodal.py
+3
-3
@@ -8,12 +8,12 @@ os.environ["TOKENIZERS_PARALLELISM"] = "true"
8
from typing import Any, NamedTuple
9
10
import pytest
11
-from huggingface_hub import hf_hub_download
11
from pytest import MarkDecorator
12
from transformers import AutoModelForImageTextToText
13
14
from vllm.assets.image import ImageAsset
15
from vllm.multimodal.image import rescale_image_size
16
+from vllm.transformers_utils.repo_utils import hf_api
17
from vllm.utils.torch_utils import set_default_torch_num_threads
18
19
from ...conftest import IMAGE_ASSETS, HfRunner, VllmRunner
@@ -33,8 +33,8 @@ class GGUFMMTestConfig(NamedTuple):
33
34
@property
35
def gguf_model(self):
36
- hf_hub_download(self.gguf_repo, filename=self.gguf_mmproj)
37
- return hf_hub_download(self.gguf_repo, filename=self.gguf_backbone)
36
+ hf_api().hf_hub_download(self.gguf_repo, filename=self.gguf_mmproj)
37
+ return hf_api().hf_hub_download(self.gguf_repo, filename=self.gguf_backbone)
38
39
40
# Common prompts aligned with test_common.py "gemma3" entry format
tests/plugins_tests/lora_resolvers/test_filesystem_resolver.py
+3
-3
@@ -4,9 +4,9 @@ import os
4
import shutil
5
6
import pytest
7
-from huggingface_hub import snapshot_download
7
8
from vllm.plugins.lora_resolvers.filesystem_resolver import FilesystemResolver
9
+from vllm.transformers_utils.repo_utils import hf_api
10
11
MODEL_NAME = "Qwen/Qwen3-0.6B"
12
LORA_NAME = "charent/self_cognition_Alice"
@@ -22,12 +22,12 @@ def adapter_cache(request, tmpdir_factory):
22
23
@pytest.fixture(scope="module")
24
def qwen3_lora_files():
25
- return snapshot_download(repo_id=LORA_NAME)
25
+ return hf_api().snapshot_download(repo_id=LORA_NAME)
26
27
28
@pytest.fixture(scope="module")
29
def pa_files():
30
- return snapshot_download(repo_id=PA_NAME)
30
+ return hf_api().snapshot_download(repo_id=PA_NAME)
31
32
33
@pytest.mark.asyncio
tests/quantization/test_modelopt.py
+2
-2
@@ -42,12 +42,12 @@ def _skip(msg: str) -> NoReturn:
42
43
def _snapshot_download_or_skip(model_id: str) -> str:
44
try:
45
- from huggingface_hub import snapshot_download
45
+ from vllm.transformers_utils.repo_utils import hf_api
46
except Exception as e: # pragma: no cover
47
_skip(f"huggingface_hub is required to download {model_id}: {e}")
48
49
try:
50
- return snapshot_download(
50
+ return hf_api().snapshot_download(
51
repo_id=model_id,
52
repo_type="model",
53
# These checkpoints are already small; download full repo for simplicity.
tests/quantization/test_quark.py
+2
-1
@@ -30,6 +30,7 @@ from vllm.model_executor.layers.quantization.utils.quant_utils import (
30
is_layer_skipped,
31
)
32
from vllm.platforms import current_platform
33
+from vllm.transformers_utils.repo_utils import hf_api
34
35
if current_platform.is_rocm():
36
from vllm.platforms.rocm import on_gfx942, on_gfx950
@@ -59,7 +60,7 @@ if QUARK_MXFP4_AVAILABLE:
60
from quark.torch.quantization.config.config import FP4PerGroupSpec
61
62
try:
62
- huggingface_hub.list_repo_refs(
63
+ hf_api().list_repo_refs(
64
"amd/Llama-3.3-70B-Instruct-WMXFP4-AMXFP4-KVFP8-Scale-UINT8-SQ"
65
)
66
HF_HUB_AMD_ORG_ACCESS = True
tests/tool_use/conftest.py
+2
-2
@@ -3,10 +3,10 @@
3
4
import pytest
5
import pytest_asyncio
6
-from huggingface_hub import snapshot_download
6
7
from tests.utils import RemoteOpenAIServer
8
from vllm.platforms import current_platform
9
+from vllm.transformers_utils.repo_utils import hf_api
10
11
from .utils import ARGS, CONFIGS, ServerConfig
12
@@ -47,7 +47,7 @@ def server_config(request):
47
)
48
49
# download model and tokenizer using transformers
50
- snapshot_download(config["model"])
50
+ hf_api().snapshot_download(config["model"])
51
yield CONFIGS[request.param]
52
53
tests/tool_use/mistral/conftest.py
+2
-2
@@ -3,10 +3,10 @@
3
4
import pytest
5
import pytest_asyncio
6
-from huggingface_hub import snapshot_download
6
7
from tests.utils import RemoteOpenAIServer
8
from vllm.platforms import current_platform
9
+from vllm.transformers_utils.repo_utils import hf_api
10
11
from .utils import ARGS, CONFIGS, ServerConfig
12
@@ -22,7 +22,7 @@ def server_config(request):
22
)
23
24
# download model and tokenizer using transformers
25
- snapshot_download(config["model"])
25
+ hf_api().snapshot_download(config["model"])
26
yield CONFIGS[request.param]
27
28
tests/utils.py
+2
-2
@@ -33,7 +33,6 @@ import pytest
33
import requests
34
import torch
35
import torch.nn.functional as F
36
-from huggingface_hub import hf_hub_download
36
from huggingface_hub.constants import HF_HUB_OFFLINE
37
from openai.types.completion import Completion
38
from typing_extensions import ParamSpec
@@ -57,6 +56,7 @@ from vllm.model_executor.layers.quantization.utils.quant_utils import (
56
from vllm.model_executor.model_loader import get_model_loader
57
from vllm.platforms import current_platform
58
from vllm.tokenizers import get_tokenizer
59
+from vllm.transformers_utils.repo_utils import hf_api
60
from vllm.utils.argparse_utils import FlexibleArgumentParser
61
from vllm.utils.mem_constants import GB_bytes
62
from vllm.utils.network_utils import get_open_port
@@ -77,7 +77,7 @@ def prewarm_hf_cache(assets: list[tuple[str, str]]) -> None:
77
return
78
for repo_id, filename in assets:
79
try:
80
- hf_hub_download(repo_id=repo_id, filename=filename)
80
+ hf_api().hf_hub_download(repo_id=repo_id, filename=filename)
81
except Exception as e:
82
logger.warning(
83
"Failed to prefetch %s/%s: %r. Tests depending on this asset may fail.",
tools/pre_commit/check_forbidden_imports.py
+75
-4
@@ -6,6 +6,13 @@ from dataclasses import dataclass, field
6
7
import regex as re
8
9
+# Hub entry points that must go through the vLLM-tagged repo_utils helpers.
10
+_HF_NAMES = (
11
+ r"HfApi|HfFileSystem|hf_hub_download|snapshot_download"
12
+ r"|list_repo_files|file_exists|try_to_load_from_cache"
13
+ r"|list_repo_refs|repo_exists"
14
+)
15
+
16
17
@dataclass
18
class ForbiddenImport:
@@ -13,6 +20,7 @@ class ForbiddenImport:
20
tip: str
21
allowed_pattern: re.Pattern = re.compile(r"^$") # matches nothing by default
22
allowed_files: set[str] = field(default_factory=set)
23
+ allowed_dirs: set[str] = field(default_factory=set)
24
25
26
CHECK_IMPORTS = {
@@ -83,6 +91,23 @@ CHECK_IMPORTS = {
91
),
92
allowed_files={"vllm/triton_utils/importing.py"},
93
),
94
+ "huggingface_hub repo API": ForbiddenImport(
95
+ # Catch `from huggingface_hub import <fn>`, including parenthesized,
96
+ # multi-line imports.
97
+ pattern=(
98
+ r"^\s*from\s+huggingface_hub\s+import\s*\([^)]*\b(?:" + _HF_NAMES + r")\b"
99
+ r"|"
100
+ r"^\s*from\s+huggingface_hub\s+import\b[^\n]*\b(?:" + _HF_NAMES + r")\b"
101
+ ),
102
+ tip=(
103
+ "Use the shared, vLLM-tagged helpers from "
104
+ "vllm.transformers_utils.repo_utils (e.g. hf_api(), hf_fs(), "
105
+ "list_repo_files, file_exists) instead of calling "
106
+ "huggingface_hub directly."
107
+ ),
108
+ allowed_files={"vllm/transformers_utils/repo_utils.py"},
109
+ allowed_dirs={"examples/"},
110
+ ),
111
}
112
113
@@ -95,11 +120,18 @@ def check_file(path: str) -> int:
120
# Skip files that are allowed for this import
121
if path in forbidden_import.allowed_files:
122
continue
123
+ # Skip directories that are allowed for this import
124
+ if any(path.startswith(prefix) for prefix in forbidden_import.allowed_dirs):
125
+ continue
126
# Search for forbidden imports
127
for match in re.finditer(forbidden_import.pattern, content, re.MULTILINE):
128
# Check if it's allowed
129
if forbidden_import.allowed_pattern.match(match.group()):
130
continue
131
+ # Skip matches inside a comment
132
+ line_start = content.rfind("\n", 0, match.start()) + 1
133
+ if "#" in content[line_start : match.start()]:
134
+ continue
135
# Calculate line number from match position
136
line_num = content[: match.start() + 1].count("\n") + 1
137
print(
@@ -119,7 +151,10 @@ def main():
151
152
153
def test_regex():
122
- test_cases = [
154
+ def matches(rule: str, content: str) -> bool:
155
+ return bool(re.search(CHECK_IMPORTS[rule].pattern, content, re.MULTILINE))
156
+
157
+ pickle_cases = [
158
# Should match
159
("import pickle", True),
160
("import cloudpickle", True),
@@ -139,11 +174,47 @@ def test_regex():
174
("print('import pickle')", False),
175
("import pickleas as asdf", False),
176
]
142
- for i, (line, should_match) in enumerate(test_cases):
143
- result = bool(CHECK_IMPORTS["pickle/cloudpickle"].pattern.match(line))
177
+ for i, (content, should_match) in enumerate(pickle_cases):
178
+ result = matches("pickle/cloudpickle", content)
179
assert result == should_match, (
145
- f"Test case {i} failed: '{line}' (expected {should_match}, got {result})"
180
+ f"pickle case {i} failed: {content!r} "
181
+ f"(expected {should_match}, got {result})"
182
)
183
+
184
+ hf_cases = [
185
+ # Should match
186
+ ("from huggingface_hub import snapshot_download", True),
187
+ ("from huggingface_hub import hf_hub_download", True),
188
+ ("from huggingface_hub import HfApi", True),
189
+ ("from huggingface_hub import HfFileSystem", True),
190
+ ("from huggingface_hub import list_repo_files", True),
191
+ ("from huggingface_hub import try_to_load_from_cache", True),
192
+ (" from huggingface_hub import snapshot_download", True),
193
+ ("from huggingface_hub import PyTorchModelHubMixin, hf_hub_download", True),
194
+ ("from huggingface_hub import (snapshot_download)", True),
195
+ # Parenthesized multi-line import must not bypass the hook
196
+ ("from huggingface_hub import (\n snapshot_download,\n)", True),
197
+ (
198
+ "from huggingface_hub import (\n PyTorchModelHubMixin,\n HfApi,\n)",
199
+ True,
200
+ ),
201
+ # Should not match
202
+ ("import huggingface_hub", False),
203
+ ("import huggingface_hub as hf", False),
204
+ ("from huggingface_hub import PyTorchModelHubMixin", False),
205
+ ("from huggingface_hub.constants import HF_HUB_CACHE", False),
206
+ ("from huggingface_hub.utils import EntryNotFoundError", False),
207
+ ("from vllm.transformers_utils.repo_utils import hf_api", False),
208
+ ("from huggingface_hub import (\n PyTorchModelHubMixin,\n)", False),
209
+ ("# from huggingface_hub import snapshot_download", False),
210
+ ]
211
+ for i, (content, should_match) in enumerate(hf_cases):
212
+ result = matches("huggingface_hub repo API", content)
213
+ assert result == should_match, (
214
+ f"huggingface_hub case {i} failed: {content!r} "
215
+ f"(expected {should_match}, got {result})"
216
+ )
217
+
218
print("All regex tests passed.")
219
220
vllm/model_executor/models/llava_onevision2.py
+5
-10
@@ -24,8 +24,6 @@ from __future__ import annotations
24
25
import hashlib
26
import importlib
27
-import json
28
-import os
27
from collections.abc import Callable, Iterable, Mapping, Sequence
28
from functools import lru_cache
29
from typing import (
@@ -39,7 +37,6 @@ import regex as re
37
import torch
38
import torch.nn as nn
39
import torch.nn.functional as F
42
-from huggingface_hub import hf_hub_download
40
from PIL import Image
41
from transformers import AutoProcessor, AutoTokenizer, BatchFeature
42
from transformers.dynamic_module_utils import get_class_from_dynamic_module
@@ -108,6 +105,7 @@ from vllm.multimodal.video import (
105
)
106
from vllm.sequence import IntermediateTensors
107
from vllm.transformers_utils.processor import _merge_mm_kwargs
108
+from vllm.transformers_utils.repo_utils import get_hf_file_to_dict
109
from vllm.transformers_utils.utils import convert_model_repo_to_path
110
from vllm.utils.tensor_schema import TensorSchema, TensorShape
111
@@ -165,13 +163,10 @@ def _load_ov2_processor(
163
# codec video backend keeps its configured defaults.
164
codec_config: dict = {}
165
try:
168
- config_file = os.path.join(path, "preprocessor_config.json")
169
- if not os.path.isfile(config_file):
170
- config_file = hf_hub_download(
171
- path, "preprocessor_config.json", revision=revision
172
- )
173
- with open(config_file, encoding="utf-8") as f:
174
- codec_config = json.load(f).get("codec", {}) or {}
166
+ preprocessor_config = get_hf_file_to_dict(
167
+ "preprocessor_config.json", path, revision
168
+ )
169
+ codec_config = (preprocessor_config or {}).get("codec", {}) or {}
170
except Exception:
171
logger.debug("OV2: no codec defaults found in preprocessor_config.json")
172