[Bugfix] Isolate weekly CPU tests from inherited attention env and hf_api mocks (#7565)
Signed-off-by: wangyu <410167048@qq.com> Signed-off-by: [Your Name] <your.email@example.com> Signed-off-by: [Your Name] [Your Email]
This commit is contained in:
1 parent
2c2cffd2aa
commit
279b1b9687
22 files changed
+236
-221
No files matched your search
@@ -42,6 +42,14 @@ from vllm_omni.diffusion.data import (
|
||||
pytestmark = [pytest.mark.core_model, pytest.mark.diffusion, pytest.mark.cpu]
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clear_inherited_attention_backend(monkeypatch):
|
||||
# Weekly CPU exports DIFFUSION_ATTENTION_BACKEND; OmniDiffusionConfig
|
||||
# treats that as an explicit default so auto-backend cases break.
|
||||
# Tests that setenv the same variable still work: this fixture runs first.
|
||||
monkeypatch.delenv("DIFFUSION_ATTENTION_BACKEND", raising=False)
|
||||
|
||||
|
||||
class TestAttentionSpec:
|
||||
def test_construct_no_skip_softmax(self):
|
||||
spec = AttentionSpec(backend="FLASH_ATTN")
|
||||
@@ -416,13 +424,6 @@ class TestBuildAttentionConfig:
|
||||
class TestOmniDiffusionConfigAttentionParsing:
|
||||
"""Test OmniDiffusionConfig attention shorthand and structured config."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clear_diffusion_attention_backend_env(self, monkeypatch):
|
||||
# OmniDiffusionConfig.__post_init__ applies DIFFUSION_ATTENTION_BACKEND via
|
||||
# build_attention_config(); clear it so these tests assert config defaults,
|
||||
# not whatever the process inherited from CI / sibling tests.
|
||||
monkeypatch.delenv("DIFFUSION_ATTENTION_BACKEND", raising=False)
|
||||
|
||||
def test_diffusion_attention_backend_sets_default(self):
|
||||
config = OmniDiffusionConfig.from_kwargs(diffusion_attention_backend="SAGE_ATTN")
|
||||
assert isinstance(config.diffusion_attention_config, AttentionConfig)
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
|
||||
import contextlib
|
||||
|
||||
import huggingface_hub
|
||||
import pytest
|
||||
|
||||
from tests.helpers.mock import patch_hf_snapshot_download
|
||||
from vllm_omni.diffusion.model_loader import hub_prefetch
|
||||
|
||||
pytestmark = [pytest.mark.core_model, pytest.mark.diffusion, pytest.mark.cpu]
|
||||
|
||||
|
||||
def test_prefetch_subfolders_propagates_revision(monkeypatch):
|
||||
def test_prefetch_subfolders_propagates_revision(monkeypatch, tmp_path):
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, **kwargs):
|
||||
def fake_snapshot_download(**kwargs):
|
||||
calls.append(kwargs)
|
||||
|
||||
monkeypatch.setattr(huggingface_hub.HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
monkeypatch.setattr(hub_prefetch, "_repo_prefetch_lock", lambda _model: contextlib.nullcontext())
|
||||
|
||||
hub_prefetch.prefetch_subfolders(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""Multi-image input regression for HunyuanImage3 IT2I prompt construction.
|
||||
|
||||
The official HunyuanImage-3.0-Instruct supports up to 3 reference images
|
||||
@@ -41,7 +41,7 @@ pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||
|
||||
|
||||
class FakeTokenizer:
|
||||
"""Recording fake tokenizer mirroring the one in test_prompt_utils.
|
||||
"""Recording fake tokenizer mirroring the one in test_hunyuan_image3_prompt_utils.
|
||||
|
||||
Special token ids: `<|startoftext|>`=1, `<img>`=2, `<think>`=3,
|
||||
`<recaption>`=4. encode() returns one id per character starting at
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
@@ -171,7 +171,7 @@ def test_huggingface_url_resolves_pinned_snapshot(tmp_path, monkeypatch):
|
||||
else pytest.fail("unexpected snapshot request")
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"vllm.transformers_utils.repo_utils.hf_api",
|
||||
"vllm_omni.transformers_utils.repo_utils.hf_api",
|
||||
lambda: api,
|
||||
)
|
||||
assert _resolve_checkpoint_root(
|
||||
|
||||
@@ -16,6 +16,7 @@ from tests.diffusion.quantization.test_quantization_quality import (
|
||||
_maybe_save_output,
|
||||
)
|
||||
from tests.helpers.mark import hardware_marks
|
||||
from tests.helpers.mock import patch_hf_snapshot_download
|
||||
|
||||
_MINIMAX_H3_REPO = "MiniMaxAI/MiniMax-H3"
|
||||
_MINIMAX_H3_REVISION = "48d93ede732756e404a3b1b2f3b3a9b5a22f6cfc"
|
||||
@@ -258,13 +259,13 @@ def test_resolve_fl2va_model_ref(tmp_path, monkeypatch):
|
||||
fl2va_root.mkdir()
|
||||
(fl2va_root / "model_index.json").write_text("{}", encoding="utf-8")
|
||||
|
||||
def fake_snapshot_download(self, *, repo_id, revision, allow_patterns):
|
||||
def fake_snapshot_download(*, repo_id, revision, allow_patterns):
|
||||
assert repo_id == _MINIMAX_H3_REPO
|
||||
assert revision == _MINIMAX_H3_REVISION
|
||||
assert allow_patterns == ["FL2VA/**"]
|
||||
return str(tmp_path)
|
||||
|
||||
monkeypatch.setattr("huggingface_hub.HfApi.snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
assert _resolve_fl2va_model_ref() == str(fl2va_root)
|
||||
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ from huggingface_hub import hf_hub_download, snapshot_download
|
||||
from torchmetrics.image import PeakSignalNoiseRatio, StructuralSimilarityIndexMeasure
|
||||
|
||||
from tests.e2e.accuracy.helpers import reset_artifact_dir
|
||||
from tests.helpers import skip_if_gated_repo_inaccessible
|
||||
from tests.helpers.mark import hardware_test
|
||||
|
||||
OFFICIAL_REPOSITORY = "https://github.com/Lightricks/LTX-2.git"
|
||||
@@ -303,32 +302,6 @@ def _resolve_ltx25_image() -> Path:
|
||||
)
|
||||
|
||||
|
||||
def _require_ltx25_model_access() -> None:
|
||||
configured_omni_model = os.environ.get("VLLM_TEST_LTX25_MODEL")
|
||||
if not (configured_omni_model and Path(configured_omni_model).exists()):
|
||||
omni_model = configured_omni_model or LTX25_OMNI_MODEL_ID
|
||||
omni_revision = os.environ.get("VLLM_TEST_LTX25_MODEL_REVISION")
|
||||
if omni_revision is None and omni_model == LTX25_OMNI_MODEL_ID:
|
||||
omni_revision = LTX25_OMNI_MODEL_REVISION
|
||||
skip_if_gated_repo_inaccessible(
|
||||
omni_model,
|
||||
revision=omni_revision,
|
||||
filename="model_index.json",
|
||||
)
|
||||
|
||||
configured_official_model = os.environ.get("VLLM_TEST_LTX25_OFFICIAL_MODEL")
|
||||
if not (configured_official_model and Path(configured_official_model).exists()):
|
||||
official_model = configured_official_model or LTX25_OFFICIAL_MODEL_ID
|
||||
official_revision = os.environ.get("VLLM_TEST_LTX25_OFFICIAL_MODEL_REVISION")
|
||||
if official_revision is None and official_model == LTX25_OFFICIAL_MODEL_ID:
|
||||
official_revision = LTX25_OFFICIAL_MODEL_REVISION
|
||||
skip_if_gated_repo_inaccessible(
|
||||
official_model,
|
||||
revision=official_revision,
|
||||
filename=LTX25_OFFICIAL_COMMON_FILES["text_encoder"],
|
||||
)
|
||||
|
||||
|
||||
def _ltx25_request(image: Path | None = None) -> dict[str, object]:
|
||||
request: dict[str, object] = {
|
||||
"prompt": LTX25_PROMPT,
|
||||
@@ -475,7 +448,6 @@ def _assert_strict_similarity(
|
||||
@pytest.mark.parametrize("task", ["t2v", "i2v"])
|
||||
def test_ltx25_distilled_two_stage_matches_official(accuracy_artifact_root: Path, task: str) -> None:
|
||||
"""Compare Omni with official canonical DiffVAE and matching connector weights."""
|
||||
_require_ltx25_model_access()
|
||||
artifact_parent = accuracy_artifact_root / "ltx_official"
|
||||
output_root = reset_artifact_dir(artifact_parent / f"ltx2_5_distilled_{task}")
|
||||
official_root, official_revision = _ltx25_official_source(artifact_parent)
|
||||
@@ -600,7 +572,6 @@ def test_ltx25_distilled_two_stage_matches_official(accuracy_artifact_root: Path
|
||||
@pytest.mark.parametrize("pipeline_mode", ["full_one_stage", "full_two_stage"])
|
||||
def test_ltx25_full_matches_official(accuracy_artifact_root: Path, task: str, pipeline_mode: str) -> None:
|
||||
"""Compare raw official Full/SFT and DiffVAE weights with Omni."""
|
||||
_require_ltx25_model_access()
|
||||
artifact_parent = accuracy_artifact_root / "ltx_official"
|
||||
output_root = reset_artifact_dir(artifact_parent / f"ltx2_5_{pipeline_mode}_{task}")
|
||||
model_class_name = {
|
||||
|
||||
@@ -558,7 +558,7 @@ def test_shared_script_ar_path_reaches_generation(
|
||||
# safe against MODEL_NAME's base checkpoint missing the Instruct-only
|
||||
# <img_ratio_33>/<img_ratio_36> tokens. Wiring it here exercises the
|
||||
# real production path (get_ar_tokenizer_validator via the registry),
|
||||
# not just the isolated fake-tokenizer coverage in test_prompt_utils.py
|
||||
# not just the isolated fake-tokenizer coverage in test_hunyuan_image3_prompt_utils.py
|
||||
# / test_shared_script_ar_integration.py.
|
||||
validate_tokenizer=get_ar_tokenizer_validator(model_class_name),
|
||||
)
|
||||
|
||||
@@ -7,7 +7,6 @@ import os
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.helpers import skip_if_gated_repo_inaccessible
|
||||
from tests.helpers.mark import hardware_marks
|
||||
from tests.helpers.media import generate_synthetic_image
|
||||
from tests.helpers.runtime import OmniServer, OmniServerParams, OpenAIClientHandler
|
||||
@@ -24,16 +23,6 @@ pytestmark = [pytest.mark.diffusion, pytest.mark.slow]
|
||||
SINGLE_CARD_MARKS = hardware_marks(res={"cuda": "H100"})
|
||||
|
||||
|
||||
@pytest.fixture(scope="module", autouse=True)
|
||||
def require_ltx25_model_access() -> None:
|
||||
if not os.path.isdir(MODEL):
|
||||
skip_if_gated_repo_inaccessible(
|
||||
MODEL,
|
||||
revision=MODEL_REVISION or None,
|
||||
filename="model_index.json",
|
||||
)
|
||||
|
||||
|
||||
def _server(model_class_name: str) -> OmniServerParams:
|
||||
return OmniServerParams(
|
||||
model=MODEL,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""
|
||||
E2E online serving test for Stable Audio Open text-to-audio diffusion.
|
||||
|
||||
@@ -11,7 +11,6 @@ import os
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.helpers import skip_if_gated_repo_inaccessible
|
||||
from tests.helpers.mark import hardware_marks
|
||||
from tests.helpers.runtime import OmniServer, OmniServerParams, OpenAIClientHandler
|
||||
|
||||
@@ -32,17 +31,10 @@ def _stable_audio_server_cases(model: str):
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def _require_stable_audio_access() -> None:
|
||||
"""Skip cleanly (before the server boots) if the gated checkpoint is inaccessible."""
|
||||
skip_if_gated_repo_inaccessible(STABLE_AUDIO_TEST_MODEL)
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
@pytest.mark.diffusion
|
||||
@pytest.mark.parametrize("omni_server", _stable_audio_server_cases(STABLE_AUDIO_TEST_MODEL), indirect=True)
|
||||
def test_stable_audio_t2a_online(
|
||||
_require_stable_audio_access: None,
|
||||
omni_server: OmniServer,
|
||||
openai_client: OpenAIClientHandler,
|
||||
) -> None:
|
||||
|
||||
@@ -22,6 +22,7 @@ from pydantic import ValidationError
|
||||
from transformers import PretrainedConfig, Qwen3OmniMoeConfig
|
||||
from vllm.engine.arg_utils import EngineArgs
|
||||
|
||||
from tests.helpers.mock import patch_hf_snapshot_download
|
||||
from vllm_omni.config.model import OmniModelConfig
|
||||
from vllm_omni.engine.arg_utils import OmniEngineArgs
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
@@ -296,7 +297,7 @@ def test_remote_tokenizer_subfolder_download_does_not_report_failure(tmp_path, m
|
||||
baseline_config = Mock()
|
||||
warning = mocker.patch("vllm_omni.engine.arg_utils.logger.warning")
|
||||
|
||||
monkeypatch.setattr("huggingface_hub.HfApi.snapshot_download", lambda *args, **kwargs: str(tmp_path))
|
||||
patch_hf_snapshot_download(monkeypatch, lambda *args, **kwargs: str(tmp_path), hf_home=tmp_path)
|
||||
monkeypatch.setattr(OmniEngineArgs, "_patch_empty_hf_config", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(EngineArgs, "create_model_config", lambda _self: baseline_config)
|
||||
monkeypatch.setattr(
|
||||
|
||||
@@ -14,6 +14,7 @@ import pytest
|
||||
from omegaconf import OmegaConf
|
||||
from vllm.v1.engine.utils import EngineZmqAddresses
|
||||
|
||||
from tests.helpers.mock import patch_hf_snapshot_download
|
||||
from vllm_omni.config.omni_config import OmniStageRuntimeConfig
|
||||
from vllm_omni.diffusion.data import AttentionConfig
|
||||
from vllm_omni.engine import omni_engine_base as async_omni_engine_module
|
||||
@@ -1566,22 +1567,20 @@ def test_build_engine_args_pulls_stage_subdirs_missing_from_cached_snapshot(monk
|
||||
never materialized. Stage init must fetch exactly those subfolders instead
|
||||
of joining onto a path that exists nowhere.
|
||||
"""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
snapshot = tmp_path / "snapshots" / "deadbeef"
|
||||
_make_snapshot(snapshot, ["tokenizer"])
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
calls.append(kwargs)
|
||||
if kwargs.get("local_files_only"):
|
||||
return str(snapshot)
|
||||
_make_snapshot(snapshot, ["language_model"])
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
@@ -1601,18 +1600,16 @@ def test_build_engine_args_pulls_stage_subdirs_missing_from_cached_snapshot(monk
|
||||
|
||||
def test_build_engine_args_skips_hub_call_when_cached_snapshot_is_complete(monkeypatch, tmp_path):
|
||||
"""A warm cache stays offline-friendly: no outgoing Hub request."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
snapshot = tmp_path / "snapshots" / "deadbeef"
|
||||
_make_snapshot(snapshot, ["language_model", "tokenizer"])
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
assert kwargs.get("local_files_only"), "warm cache must not reach the Hub"
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
@@ -1633,8 +1630,6 @@ def test_build_engine_args_redownloads_a_partial_subdir(monkeypatch, tmp_path):
|
||||
that local path leaves vLLM's loader without any fallback for the missing
|
||||
weights.
|
||||
"""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
snapshot = tmp_path / "snapshots" / "deadbeef"
|
||||
@@ -1644,14 +1639,14 @@ def test_build_engine_args_redownloads_a_partial_subdir(monkeypatch, tmp_path):
|
||||
_make_snapshot(snapshot, ["tokenizer"])
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
calls.append(kwargs)
|
||||
if kwargs.get("local_files_only"):
|
||||
return str(snapshot)
|
||||
_make_snapshot(snapshot, ["language_model"])
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
@@ -1672,8 +1667,6 @@ def test_build_engine_args_redownloads_when_index_lists_missing_shards(monkeypat
|
||||
The index downloads early; accepting it as proof of weights converts the
|
||||
Hub ID into a local path vLLM cannot fetch the remaining shards for.
|
||||
"""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
snapshot = tmp_path / "snapshots" / "deadbeef"
|
||||
@@ -1693,13 +1686,13 @@ def test_build_engine_args_redownloads_when_index_lists_missing_shards(monkeypat
|
||||
_make_snapshot(snapshot, ["tokenizer"])
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
calls.append(kwargs)
|
||||
if not kwargs.get("local_files_only"):
|
||||
(partial / "model-00002-of-00002.safetensors").write_text("x")
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
@@ -1716,8 +1709,6 @@ def test_build_engine_args_redownloads_when_index_lists_missing_shards(monkeypat
|
||||
|
||||
def test_build_engine_args_redownloads_shards_without_their_index(monkeypatch, tmp_path):
|
||||
"""Shard-named weights always ship an index; one without it is partial."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
snapshot = tmp_path / "snapshots" / "deadbeef"
|
||||
@@ -1727,7 +1718,7 @@ def test_build_engine_args_redownloads_shards_without_their_index(monkeypatch, t
|
||||
_make_snapshot(snapshot, ["tokenizer"])
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
calls.append(kwargs)
|
||||
if not kwargs.get("local_files_only"):
|
||||
shards = {f"w{i}.weight": f"model-0000{i}-of-00004.safetensors" for i in range(1, 5)}
|
||||
@@ -1736,7 +1727,7 @@ def test_build_engine_args_redownloads_shards_without_their_index(monkeypatch, t
|
||||
(partial / shard).write_text("x")
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
@@ -1752,8 +1743,6 @@ def test_build_engine_args_redownloads_shards_without_their_index(monkeypatch, t
|
||||
|
||||
def test_build_engine_args_redownloads_a_tokenizer_folder_without_vocabulary(monkeypatch, tmp_path):
|
||||
"""Templates and configs download first; alone they are not a tokenizer."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
snapshot = tmp_path / "snapshots" / "deadbeef"
|
||||
@@ -1763,13 +1752,13 @@ def test_build_engine_args_redownloads_a_tokenizer_folder_without_vocabulary(mon
|
||||
(partial / "chat_template.jinja").write_text("{{ messages }}")
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
calls.append(kwargs)
|
||||
if not kwargs.get("local_files_only"):
|
||||
_make_snapshot(snapshot, ["tokenizer"])
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
@@ -1787,19 +1776,17 @@ def test_build_engine_args_redownloads_a_tokenizer_folder_without_vocabulary(mon
|
||||
def test_build_engine_args_forwards_revision_and_download_dir(monkeypatch, tmp_path):
|
||||
"""revision/download_dir must shape snapshot selection (they cannot be
|
||||
corrected downstream once the repo ID is a local path)."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
snapshot = tmp_path / "snapshots" / "pinned"
|
||||
_make_snapshot(snapshot, ["language_model", "tokenizer"])
|
||||
seen = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
seen.append(kwargs)
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
@@ -1824,8 +1811,6 @@ def test_build_engine_args_forwards_revision_and_download_dir(monkeypatch, tmp_p
|
||||
|
||||
def test_build_engine_args_resolves_tokenizer_revision_separately(monkeypatch, tmp_path):
|
||||
"""A tokenizer pinned to a different revision resolves against its own snapshot."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
model_snapshot = tmp_path / "snapshots" / "model-rev"
|
||||
@@ -1833,12 +1818,12 @@ def test_build_engine_args_resolves_tokenizer_revision_separately(monkeypatch, t
|
||||
tokenizer_snapshot = tmp_path / "snapshots" / "tok-rev"
|
||||
_make_snapshot(tokenizer_snapshot, ["tokenizer"])
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
if kwargs.get("revision") == "tok-rev":
|
||||
return str(tokenizer_snapshot)
|
||||
return str(model_snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
@@ -1861,8 +1846,6 @@ def test_build_engine_args_resolves_tokenizer_revision_separately(monkeypatch, t
|
||||
def test_build_engine_args_resolves_root_tokenizer_revision_separately(monkeypatch, tmp_path):
|
||||
"""An empty tokenizer_subdir targets the snapshot root and still honors
|
||||
its own revision."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
model_snapshot = tmp_path / "snapshots" / "model-rev"
|
||||
@@ -1875,12 +1858,12 @@ def test_build_engine_args_resolves_root_tokenizer_revision_separately(monkeypat
|
||||
tokenizer_snapshot.mkdir(parents=True, exist_ok=True)
|
||||
(tokenizer_snapshot / _SUBDIR_ARTIFACT["tokenizer"]).write_text("x")
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
if kwargs.get("revision") == "tok-rev":
|
||||
return str(tokenizer_snapshot)
|
||||
return str(model_snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
@@ -1902,19 +1885,17 @@ def test_build_engine_args_resolves_root_tokenizer_revision_separately(monkeypat
|
||||
|
||||
def test_build_engine_args_fails_closed_when_subdir_cannot_be_downloaded(monkeypatch, tmp_path):
|
||||
"""An undownloadable subfolder raises here instead of reaching HuggingFace."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
snapshot = tmp_path / "snapshots" / "deadbeef"
|
||||
_make_snapshot(snapshot, ["tokenizer"])
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
if kwargs.get("local_files_only"):
|
||||
return str(snapshot)
|
||||
raise OSError("offline")
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
@@ -1927,16 +1908,14 @@ def test_build_engine_args_fails_closed_when_subdir_cannot_be_downloaded(monkeyp
|
||||
build_engine_args_dict(stage_cfg, "MiniMaxAI/MiniMax-Music3")
|
||||
|
||||
|
||||
def test_build_engine_args_fails_closed_on_cold_cache_instead_of_joining_repo_id(monkeypatch):
|
||||
def test_build_engine_args_fails_closed_on_cold_cache_instead_of_joining_repo_id(monkeypatch, tmp_path):
|
||||
"""With nothing cached, the stage must not join a subdir onto the repo id."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
from vllm_omni.engine.stage_init_utils import build_engine_args_dict
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
raise OSError("offline")
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
stage_cfg = types.SimpleNamespace(
|
||||
stage_id=0,
|
||||
|
||||
@@ -3,49 +3,10 @@
|
||||
|
||||
"""Shared, importable test helper utilities.
|
||||
|
||||
Submodules (``assertions``, ``clean``, ``client``, ``media``, ``runtime``, …) are imported
|
||||
Submodules (``assertions``, ``clean``, ``client``, ``media``, ``mock``, ``runtime``, …) are imported
|
||||
explicitly by callers. Unit tests for these helpers live under ``tests/``.
|
||||
Avoid star-importing everything here: that ran before refactor only inside the
|
||||
old monolithic ``conftest``; a greedy ``__init__`` changes import order and can
|
||||
affect in-process Omni (``OmniRunner`` / offline e2e) vs subprocess-based
|
||||
``OmniServer`` tests.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def skip_if_gated_repo_inaccessible(
|
||||
repo_id: str,
|
||||
*,
|
||||
revision: str | None = None,
|
||||
filename: str = "config.json",
|
||||
) -> None:
|
||||
"""Skip the test if a gated HuggingFace repo is not accessible.
|
||||
|
||||
Tries to download ``filename`` via ``hf_hub_download``, which performs an
|
||||
actual file-access check (unlike ``HfApi().model_info()``
|
||||
that only checks metadata). If the token has metadata access but not
|
||||
file-download access, ``hf_hub_download`` will raise ``GatedRepoError``
|
||||
and we skip cleanly.
|
||||
"""
|
||||
try:
|
||||
from huggingface_hub.errors import GatedRepoError, RepositoryNotFoundError
|
||||
|
||||
from vllm_omni.transformers_utils.repo_utils import hf_api
|
||||
except Exception:
|
||||
return
|
||||
try:
|
||||
hf_api().hf_hub_download(repo_id=repo_id, filename=filename, revision=revision)
|
||||
except GatedRepoError as exc:
|
||||
import pytest
|
||||
|
||||
pytest.skip(
|
||||
f"Skipping: gated HF repo {repo_id!r} inaccessible to the current "
|
||||
f"HF_TOKEN ({exc}). See docs/contributing/ci/hf_credentials.md."
|
||||
)
|
||||
except RepositoryNotFoundError as exc:
|
||||
import pytest
|
||||
|
||||
pytest.skip(f"Skipping: HF repo {repo_id!r} not found ({exc}).")
|
||||
except Exception:
|
||||
return
|
||||
@@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""Shared pytest mocks for unit tests.
|
||||
|
||||
Add reusable ``monkeypatch`` helpers here instead of a new module per target.
|
||||
Callers import explicitly: ``from tests.helpers.mock import ...``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from os import PathLike
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
def patch_hf_snapshot_download(
|
||||
monkeypatch: Any,
|
||||
fake: Callable[..., Any],
|
||||
*,
|
||||
hf_home: str | PathLike[str] | None = None,
|
||||
) -> None:
|
||||
"""Replace ``snapshot_download`` on the cached ``hf_api()`` singleton.
|
||||
|
||||
Production code calls ``hf_api().snapshot_download``. Patching
|
||||
``huggingface_hub.HfApi.snapshot_download`` misses that instance, so
|
||||
weekly CPU jobs talk to the real Hub / ``HF_HOME`` cache.
|
||||
|
||||
``fake`` is installed on the instance, so it is called without ``self``.
|
||||
|
||||
Pass ``hf_home`` (typically pytest ``tmp_path``) to isolate the Hub cache.
|
||||
``repo_utils`` imports ``huggingface_hub`` before tests can ``setenv``, so
|
||||
``constants.HF_HUB_CACHE`` is already frozen from the process environment
|
||||
(weekly: ``/fsx/hf_cache``). Downloads without ``cache_dir`` use that
|
||||
constant, not ``HF_HOME``. Patch both the env and the imported constants
|
||||
so a missed instance mock cannot read the builder cache.
|
||||
"""
|
||||
from huggingface_hub import constants as hub_constants
|
||||
|
||||
from vllm_omni.transformers_utils import repo_utils
|
||||
|
||||
monkeypatch.setattr(repo_utils.hf_api(), "snapshot_download", fake)
|
||||
if hf_home is not None:
|
||||
hf_home_str = str(hf_home)
|
||||
hub_cache = str(Path(hf_home_str) / "hub")
|
||||
monkeypatch.setenv("HF_HOME", hf_home_str)
|
||||
monkeypatch.setenv("HF_HUB_CACHE", hub_cache)
|
||||
monkeypatch.setattr(hub_constants, "HF_HOME", hf_home_str)
|
||||
monkeypatch.setattr(hub_constants, "default_cache_path", hub_cache)
|
||||
monkeypatch.setattr(hub_constants, "HF_HUB_CACHE", hub_cache)
|
||||
monkeypatch.setattr(hub_constants, "HUGGINGFACE_HUB_CACHE", hub_cache)
|
||||
@@ -0,0 +1,93 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.helpers.mock import patch_hf_snapshot_download
|
||||
|
||||
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||
|
||||
|
||||
def test_patch_hf_snapshot_download_binds_instance_without_self(monkeypatch):
|
||||
from vllm_omni.transformers_utils.repo_utils import hf_api
|
||||
|
||||
calls: list[tuple[tuple[object, ...], dict[str, object]]] = []
|
||||
|
||||
def fake(*args, **kwargs):
|
||||
calls.append((args, kwargs))
|
||||
return "ok"
|
||||
|
||||
patch_hf_snapshot_download(monkeypatch, fake)
|
||||
assert hf_api().snapshot_download("org/model", revision="abc") == "ok"
|
||||
assert calls == [(("org/model",), {"revision": "abc"})]
|
||||
|
||||
|
||||
def test_patch_hf_snapshot_download_sets_hf_home(monkeypatch, tmp_path):
|
||||
hf_home = tmp_path / "hf-home"
|
||||
patch_hf_snapshot_download(monkeypatch, lambda *args, **kwargs: "ok", hf_home=hf_home)
|
||||
assert os.environ["HF_HOME"] == str(hf_home)
|
||||
from huggingface_hub import constants
|
||||
|
||||
assert constants.HF_HOME == str(hf_home)
|
||||
assert constants.HF_HUB_CACHE == str(hf_home / "hub")
|
||||
assert constants.HUGGINGFACE_HUB_CACHE == str(hf_home / "hub")
|
||||
assert constants.default_cache_path == str(hf_home / "hub")
|
||||
|
||||
|
||||
def test_patch_hf_snapshot_download_leaves_hf_home_when_omitted(monkeypatch):
|
||||
from huggingface_hub import constants
|
||||
|
||||
monkeypatch.setenv("HF_HOME", "/original-hf-home")
|
||||
original_cache = constants.HF_HUB_CACHE
|
||||
original_default = constants.default_cache_path
|
||||
patch_hf_snapshot_download(monkeypatch, lambda *args, **kwargs: "ok")
|
||||
assert os.environ["HF_HOME"] == "/original-hf-home"
|
||||
assert constants.HF_HUB_CACHE == original_cache
|
||||
assert constants.default_cache_path == original_default
|
||||
|
||||
|
||||
def test_patch_hf_snapshot_download_overrides_preimported_hub_cache(monkeypatch, tmp_path):
|
||||
"""Hub is imported before the helper; ``HF_HOME`` env alone does not move the cache.
|
||||
|
||||
``repo_utils`` / ``huggingface_hub`` compute ``constants.HF_HUB_CACHE`` at
|
||||
import time. Weekly CPU already imported them with ``HF_HOME=/fsx/hf_cache``.
|
||||
A download that bypasses the instance mock uses that constant, not the env.
|
||||
"""
|
||||
from huggingface_hub import constants, snapshot_download
|
||||
from huggingface_hub.errors import LocalEntryNotFoundError
|
||||
|
||||
from vllm_omni.transformers_utils.repo_utils import hf_api
|
||||
|
||||
hf_api()
|
||||
|
||||
poisoned_home = tmp_path / "fsx-hf-cache"
|
||||
poisoned_cache = poisoned_home / "hub"
|
||||
repo_dir = poisoned_cache / "models--org--model"
|
||||
(repo_dir / "refs").mkdir(parents=True)
|
||||
(repo_dir / "refs" / "main").write_text("deadbeef", encoding="utf-8")
|
||||
snapshot = repo_dir / "snapshots" / "deadbeef"
|
||||
snapshot.mkdir(parents=True)
|
||||
(snapshot / "config.json").write_text("{}", encoding="utf-8")
|
||||
|
||||
monkeypatch.setenv("HF_HOME", str(poisoned_home))
|
||||
monkeypatch.setattr(constants, "HF_HOME", str(poisoned_home))
|
||||
monkeypatch.setattr(constants, "HF_HUB_CACHE", str(poisoned_cache))
|
||||
monkeypatch.setattr(constants, "HUGGINGFACE_HUB_CACHE", str(poisoned_cache))
|
||||
|
||||
found = snapshot_download("org/model", local_files_only=True)
|
||||
assert Path(found).resolve() == snapshot.resolve()
|
||||
|
||||
isolated = tmp_path / "isolated-hf-home"
|
||||
patch_hf_snapshot_download(monkeypatch, lambda *args, **kwargs: "mocked", hf_home=isolated)
|
||||
|
||||
assert os.environ["HF_HOME"] == str(isolated)
|
||||
assert os.environ["HF_HUB_CACHE"] == str(isolated / "hub")
|
||||
assert constants.HF_HOME == str(isolated)
|
||||
assert constants.HF_HUB_CACHE == str(isolated / "hub")
|
||||
assert constants.HUGGINGFACE_HUB_CACHE == str(isolated / "hub")
|
||||
assert constants.default_cache_path == str(isolated / "hub")
|
||||
with pytest.raises(LocalEntryNotFoundError):
|
||||
snapshot_download("org/model", local_files_only=True)
|
||||
File renamed without changes.
+1
-1
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
@@ -12,9 +12,9 @@ from __future__ import annotations
|
||||
|
||||
from types import SimpleNamespace
|
||||
|
||||
import huggingface_hub
|
||||
import pytest
|
||||
|
||||
from tests.helpers.mock import patch_hf_snapshot_download
|
||||
from vllm_omni.model_executor.models.minicpmo_4_5.minicpmo_4_5_code2wav import (
|
||||
MiniCPMO45Code2Wav,
|
||||
_resolve_model_dir,
|
||||
@@ -23,28 +23,28 @@ from vllm_omni.model_executor.models.minicpmo_4_5.minicpmo_4_5_code2wav import (
|
||||
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||
|
||||
|
||||
def _no_hub(monkeypatch):
|
||||
def _no_hub(monkeypatch, tmp_path):
|
||||
def _fail(*args, **kwargs): # pragma: no cover - must not be reached
|
||||
raise AssertionError("snapshot_download must not be called here")
|
||||
|
||||
monkeypatch.setattr(huggingface_hub.HfApi, "snapshot_download", _fail)
|
||||
patch_hf_snapshot_download(monkeypatch, _fail, hf_home=tmp_path)
|
||||
|
||||
|
||||
def test_local_directory_is_returned_unchanged(tmp_path, monkeypatch):
|
||||
_no_hub(monkeypatch)
|
||||
_no_hub(monkeypatch, tmp_path)
|
||||
assert _resolve_model_dir(str(tmp_path)) == str(tmp_path)
|
||||
|
||||
|
||||
def test_repo_id_resolves_via_snapshot_download(tmp_path, monkeypatch):
|
||||
calls = {}
|
||||
|
||||
def _fake_snapshot_download(self, model_ref, revision=None, allow_patterns=None):
|
||||
def _fake_snapshot_download(model_ref, revision=None, allow_patterns=None):
|
||||
calls["model_ref"] = model_ref
|
||||
calls["revision"] = revision
|
||||
calls["allow_patterns"] = allow_patterns
|
||||
return str(tmp_path / "snapshot")
|
||||
|
||||
monkeypatch.setattr(huggingface_hub.HfApi, "snapshot_download", _fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, _fake_snapshot_download, hf_home=tmp_path)
|
||||
resolved = _resolve_model_dir("openbmb/MiniCPM-o-4_5", revision="abc123")
|
||||
assert resolved == str(tmp_path / "snapshot")
|
||||
assert calls["model_ref"] == "openbmb/MiniCPM-o-4_5"
|
||||
@@ -52,18 +52,18 @@ def test_repo_id_resolves_via_snapshot_download(tmp_path, monkeypatch):
|
||||
assert calls["allow_patterns"] == ["assets/*"]
|
||||
|
||||
|
||||
def test_snapshot_download_failure_propagates(monkeypatch):
|
||||
def test_snapshot_download_failure_propagates(monkeypatch, tmp_path):
|
||||
def _raise(*args, **kwargs):
|
||||
raise FileNotFoundError("offline and not cached")
|
||||
|
||||
monkeypatch.setattr(huggingface_hub.HfApi, "snapshot_download", _raise)
|
||||
patch_hf_snapshot_download(monkeypatch, _raise, hf_home=tmp_path)
|
||||
with pytest.raises(FileNotFoundError):
|
||||
_resolve_model_dir("openbmb/MiniCPM-o-4_5")
|
||||
|
||||
|
||||
def test_init_with_fake_path_does_not_resolve(monkeypatch):
|
||||
def test_init_with_fake_path_does_not_resolve(monkeypatch, tmp_path):
|
||||
"""Mirrors the CPU-test construction: fake model path, no ``revision``."""
|
||||
_no_hub(monkeypatch)
|
||||
_no_hub(monkeypatch, tmp_path)
|
||||
config = SimpleNamespace(
|
||||
model_config=SimpleNamespace(
|
||||
model="/fake/model",
|
||||
@@ -75,8 +75,8 @@ def test_init_with_fake_path_does_not_resolve(monkeypatch):
|
||||
assert model._default_prompt_wav == "/fake/model/assets/HT_ref_audio.wav"
|
||||
|
||||
|
||||
def test_default_prompt_wav_follows_resolved_model_path(monkeypatch):
|
||||
_no_hub(monkeypatch)
|
||||
def test_default_prompt_wav_follows_resolved_model_path(monkeypatch, tmp_path):
|
||||
_no_hub(monkeypatch, tmp_path)
|
||||
config = SimpleNamespace(
|
||||
model_config=SimpleNamespace(
|
||||
model="openbmb/MiniCPM-o-4_5",
|
||||
|
||||
@@ -12,6 +12,7 @@ from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.helpers.mock import patch_hf_snapshot_download
|
||||
from vllm_omni.model_executor.models.minimax_music3.weights import (
|
||||
_COMPONENT_WEIGHT_NAME,
|
||||
_REQUIRED_COMPONENTS,
|
||||
@@ -47,16 +48,14 @@ def test_resolve_repo_root_walks_up_from_a_model_subdir(tmp_path):
|
||||
|
||||
def test_resolve_repo_root_resolves_a_hub_id_to_a_local_snapshot(monkeypatch, tmp_path):
|
||||
"""A hub id must resolve through the cache, not against the working directory."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
root = _make_root(tmp_path / "snapshots" / "deadbeef")
|
||||
seen = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
seen.append(kwargs)
|
||||
return str(root)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
assert resolve_repo_root("MiniMaxAI/MiniMax-Music3") == root
|
||||
# Cache-first, and only the component folders.
|
||||
@@ -66,18 +65,16 @@ def test_resolve_repo_root_resolves_a_hub_id_to_a_local_snapshot(monkeypatch, tm
|
||||
|
||||
|
||||
def test_resolve_repo_root_falls_back_to_the_hub_when_the_cache_is_incomplete(monkeypatch, tmp_path):
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
root = _make_root(tmp_path / "snapshots" / "deadbeef")
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
calls.append(kwargs)
|
||||
if kwargs.get("local_files_only"):
|
||||
raise OSError("incomplete snapshot")
|
||||
return str(root)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
assert resolve_repo_root("MiniMaxAI/MiniMax-Music3") == root
|
||||
assert len(calls) == 2
|
||||
@@ -89,19 +86,17 @@ def test_resolve_repo_root_retries_online_when_the_local_lookup_returns_a_partia
|
||||
A returned partial root must fall through to the online call all the same,
|
||||
or startup fails without ever consulting the Hub.
|
||||
"""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
snapshot = tmp_path / "models--MiniMaxAI--MiniMax-Music3" / "snapshots" / "deadbeef"
|
||||
(snapshot / "language_model").mkdir(parents=True)
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
calls.append(kwargs)
|
||||
if not kwargs.get("local_files_only"):
|
||||
_make_root(snapshot)
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
assert resolve_repo_root("MiniMaxAI/MiniMax-Music3") == snapshot
|
||||
assert [bool(call.get("local_files_only")) for call in calls] == [True, False]
|
||||
@@ -109,32 +104,28 @@ def test_resolve_repo_root_retries_online_when_the_local_lookup_returns_a_partia
|
||||
|
||||
def test_resolve_repo_root_redownloads_weightless_marker_dirs(monkeypatch, tmp_path):
|
||||
"""Marker folders without their component weights are an interrupted download."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
snapshot = tmp_path / "models--MiniMaxAI--MiniMax-Music3" / "snapshots" / "deadbeef"
|
||||
for marker in _ROOT_MARKERS:
|
||||
(snapshot / marker).mkdir(parents=True)
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
calls.append(kwargs)
|
||||
if not kwargs.get("local_files_only"):
|
||||
_make_root(snapshot)
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
assert resolve_repo_root("MiniMaxAI/MiniMax-Music3") == snapshot
|
||||
assert any(not call.get("local_files_only") for call in calls)
|
||||
|
||||
|
||||
def test_resolve_repo_root_reports_the_original_reference_when_unresolvable(monkeypatch):
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def test_resolve_repo_root_reports_the_original_reference_when_unresolvable(monkeypatch, tmp_path):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
raise OSError("offline")
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
with pytest.raises(FileNotFoundError, match="MiniMaxAI/MiniMax-Music3"):
|
||||
resolve_repo_root("MiniMaxAI/MiniMax-Music3")
|
||||
@@ -147,19 +138,17 @@ def test_resolve_repo_root_downloads_components_for_a_cold_cache_model_subdir(mo
|
||||
the marker walk fails although the repo id is recoverable from the cache
|
||||
layout and one snapshot_download away from working.
|
||||
"""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
snapshot = tmp_path / "models--MiniMaxAI--MiniMax-Music3" / "snapshots" / "deadbeef"
|
||||
(snapshot / "language_model").mkdir(parents=True)
|
||||
(snapshot / "tokenizer").mkdir()
|
||||
seen = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
seen.append(repo_id)
|
||||
_make_root(snapshot)
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
assert resolve_repo_root(str(snapshot / "language_model")) == snapshot
|
||||
assert seen == ["MiniMaxAI/MiniMax-Music3"]
|
||||
@@ -167,12 +156,11 @@ def test_resolve_repo_root_downloads_components_for_a_cold_cache_model_subdir(mo
|
||||
|
||||
def test_resolve_repo_root_does_not_guess_a_repo_id_for_plain_directories(monkeypatch, tmp_path):
|
||||
"""A directory outside the HF cache has no recoverable repo id."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
raise AssertionError("must not reach the Hub for a plain directory")
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
plain = tmp_path / "language_model"
|
||||
plain.mkdir()
|
||||
@@ -187,8 +175,6 @@ def test_resolve_repo_root_rejects_a_snapshot_missing_condition_encoder(monkeypa
|
||||
acoustic stage would still fail, so completeness must cover every required
|
||||
component rather than the identification markers alone.
|
||||
"""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
snapshot = tmp_path / "models--MiniMaxAI--MiniMax-Music3" / "snapshots" / "deadbeef"
|
||||
for marker in _ROOT_MARKERS:
|
||||
folder = snapshot / marker
|
||||
@@ -196,13 +182,13 @@ def test_resolve_repo_root_rejects_a_snapshot_missing_condition_encoder(monkeypa
|
||||
(folder / _COMPONENT_WEIGHT_NAME).write_bytes(b"x")
|
||||
repaired = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
if not kwargs.get("local_files_only"):
|
||||
repaired.append(repo_id)
|
||||
_make_root(snapshot)
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
assert resolve_repo_root(str(snapshot)) == snapshot
|
||||
assert repaired == ["MiniMaxAI/MiniMax-Music3"]
|
||||
@@ -210,8 +196,6 @@ def test_resolve_repo_root_rejects_a_snapshot_missing_condition_encoder(monkeypa
|
||||
|
||||
def test_resolve_repo_root_rejects_a_partial_shard_run(monkeypatch, tmp_path):
|
||||
"""One shard of a multi-shard component satisfies a bare glob but cannot load."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
stem = _COMPONENT_WEIGHT_NAME.removesuffix(".safetensors")
|
||||
snapshot = tmp_path / "models--MiniMaxAI--MiniMax-Music3" / "snapshots" / "deadbeef"
|
||||
for component in _REQUIRED_COMPONENTS:
|
||||
@@ -223,14 +207,14 @@ def test_resolve_repo_root_rejects_a_partial_shard_run(monkeypatch, tmp_path):
|
||||
(partial / f"{stem}-00001-of-00003.safetensors").write_bytes(b"x")
|
||||
repaired = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
if not kwargs.get("local_files_only"):
|
||||
repaired.append(repo_id)
|
||||
for index in (2, 3):
|
||||
(partial / f"{stem}-0000{index}-of-00003.safetensors").write_bytes(b"x")
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
assert resolve_repo_root(str(snapshot)) == snapshot
|
||||
assert repaired == ["MiniMaxAI/MiniMax-Music3"]
|
||||
@@ -242,17 +226,15 @@ def test_resolve_repo_root_threads_revision_and_download_dir(monkeypatch, tmp_pa
|
||||
Resolving components against the default branch while the AR backbone is
|
||||
pinned elsewhere would combine weights from two different commits.
|
||||
"""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
snapshot = tmp_path / "snapshot"
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
calls.append(kwargs)
|
||||
_make_root(snapshot)
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
assert resolve_repo_root("MiniMaxAI/MiniMax-Music3", revision="abc123", download_dir="/tmp/hub-cache") == snapshot
|
||||
assert calls
|
||||
@@ -266,18 +248,16 @@ def test_resolve_repo_root_reuses_the_snapshot_revision_from_the_cache_path(monk
|
||||
Re-resolving the repo id alone would fetch the default branch rather than
|
||||
the snapshot the caller is already sitting in.
|
||||
"""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
snapshot = tmp_path / "models--MiniMaxAI--MiniMax-Music3" / "snapshots" / "cafebabe"
|
||||
(snapshot / "language_model").mkdir(parents=True)
|
||||
calls = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
calls.append(kwargs)
|
||||
_make_root(snapshot)
|
||||
return str(snapshot)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
assert resolve_repo_root(str(snapshot / "language_model")) == snapshot
|
||||
assert calls
|
||||
@@ -292,8 +272,6 @@ def test_resolve_repo_root_accepts_shard_names_the_loader_can_read(monkeypatch,
|
||||
loadable. Judging it incomplete would force a needless re-download and, with
|
||||
no network, fail on weights that are present and readable.
|
||||
"""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
stem = _COMPONENT_WEIGHT_NAME.removesuffix(".safetensors")
|
||||
root = tmp_path / "snapshot"
|
||||
for component in _REQUIRED_COMPONENTS:
|
||||
@@ -303,18 +281,16 @@ def test_resolve_repo_root_accepts_shard_names_the_loader_can_read(monkeypatch,
|
||||
(unsharded / _COMPONENT_WEIGHT_NAME).unlink()
|
||||
(unsharded / f"{stem}-fp16.safetensors").write_bytes(b"x")
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
raise AssertionError("must not reach the Hub for readable weights")
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
assert resolve_repo_root(str(root)) == root
|
||||
|
||||
|
||||
def test_resolve_repo_root_still_rejects_a_partial_run_beside_an_extra_file(monkeypatch, tmp_path):
|
||||
"""An unparsable extra must not mask a genuinely short ``-of-`` run."""
|
||||
from huggingface_hub import HfApi
|
||||
|
||||
stem = _COMPONENT_WEIGHT_NAME.removesuffix(".safetensors")
|
||||
root = tmp_path / "snapshot"
|
||||
for component in _REQUIRED_COMPONENTS:
|
||||
@@ -326,13 +302,13 @@ def test_resolve_repo_root_still_rejects_a_partial_run_beside_an_extra_file(monk
|
||||
(partial / f"{stem}-extra.safetensors").write_bytes(b"x")
|
||||
repaired = []
|
||||
|
||||
def fake_snapshot_download(self, repo_id, **kwargs):
|
||||
def fake_snapshot_download(repo_id, **kwargs):
|
||||
repaired.append(repo_id)
|
||||
for index in (2, 3):
|
||||
(partial / f"{stem}-0000{index}-of-00003.safetensors").write_bytes(b"x")
|
||||
return str(root)
|
||||
|
||||
monkeypatch.setattr(HfApi, "snapshot_download", fake_snapshot_download)
|
||||
patch_hf_snapshot_download(monkeypatch, fake_snapshot_download, hf_home=tmp_path)
|
||||
|
||||
with pytest.raises(FileNotFoundError, match="components are incomplete"):
|
||||
resolve_repo_root(str(root))
|
||||
|
||||
@@ -25,7 +25,6 @@ from vllm.model_executor.model_loader.weight_utils import (
|
||||
pt_weights_iterator,
|
||||
safetensors_weights_iterator,
|
||||
)
|
||||
from vllm.transformers_utils.repo_utils import hf_api
|
||||
from vllm.utils.import_utils import resolve_obj_by_qualname
|
||||
from vllm.utils.torch_utils import set_default_torch_dtype
|
||||
|
||||
@@ -54,6 +53,7 @@ from vllm_omni.diffusion.offloader.module_collector import ModuleDiscovery
|
||||
from vllm_omni.diffusion.offloader.offload_plan import get_offload_plan
|
||||
from vllm_omni.diffusion.registry import initialize_model
|
||||
from vllm_omni.model_executor.model_loader.weight_utils import download_weights_from_hf_specific
|
||||
from vllm_omni.transformers_utils.repo_utils import hf_api
|
||||
|
||||
|
||||
# download_gguf was removed from upstream vLLM (commit 6635279d8).
|
||||
|
||||
@@ -225,7 +225,7 @@ def _resolve_checkpoint_root(model: str, revision: str | None) -> str:
|
||||
"MAGI-2 expects a local checkpoint directory or the official "
|
||||
f"model ID {MAGI2_MODEL_ID!r}; got {model!r}."
|
||||
)
|
||||
from vllm.transformers_utils.repo_utils import hf_api
|
||||
from vllm_omni.transformers_utils.repo_utils import hf_api
|
||||
|
||||
pinned_revision = revision or MAGI2_MODEL_REVISION
|
||||
logger.warning(
|
||||
|
||||
@@ -119,7 +119,7 @@ def _download_component_snapshot(
|
||||
components against the default branch and the default cache while the AR
|
||||
backbone was pinned elsewhere would silently mix weights from two commits.
|
||||
"""
|
||||
from vllm.transformers_utils.repo_utils import hf_api
|
||||
from vllm_omni.transformers_utils.repo_utils import hf_api
|
||||
|
||||
kwargs: dict[str, object] = {"allow_patterns": list(_COMPONENT_PATTERNS)}
|
||||
if revision is not None:
|
||||
|
||||
Reference in new issue
Block a user