Fix model info cache for package models (#46567)
Signed-off-by: soaringk <k3vin.zhang@gmail.com>
soaringk committed
Jun 29, 2026 at 17:17 UTC
ab132ee98ba14c5d99977b1f83c2d5517c0a1e79
2 files changed
+37
-2
tests/models/test_registry.py
+17
@@ -20,6 +20,7 @@ from vllm.model_executor.models.registry import (
20
_SPECULATIVE_DECODING_MODELS,
21
_TEXT_GENERATION_MODELS,
22
ModelRegistry,
23
+ _LazyRegisteredModel,
24
)
25
from vllm.platforms import current_platform
26
@@ -127,6 +128,22 @@ def test_registry_is_pp(model_arch, is_pp, init_cuda):
128
)
129
130
131
+def test_lazy_modelinfo_package_hash_includes_submodules(tmp_path):
132
+ package_dir = tmp_path / "model_package"
133
+ package_dir.mkdir()
134
+ init_file = package_dir / "__init__.py"
135
+ init_file.write_text("from .model import Model\n", encoding="utf-8")
136
+ model_file = package_dir / "model.py"
137
+ model_file.write_text("class Model: pass\n", encoding="utf-8")
138
+
139
+ first_hash = _LazyRegisteredModel._get_modelinfo_module_hash(init_file)
140
+
141
+ model_file.write_text("class Model:\n supports_pp = True\n", encoding="utf-8")
142
+ second_hash = _LazyRegisteredModel._get_modelinfo_module_hash(init_file)
143
+
144
+ assert first_hash != second_hash
145
+
146
+
147
def test_hf_registry_coverage():
148
untested_archs = (
149
ModelRegistry.get_supported_archs() - HF_EXAMPLE_MODELS.get_supported_archs()
vllm/model_executor/models/registry.py
+20
-2
@@ -849,6 +849,25 @@ class _LazyRegisteredModel(_BaseRegisteredModel):
849
cls_name = f"{self.module_name}-{self.class_name}".replace(".", "-")
850
return f"{cls_name}.json"
851
852
+ @staticmethod
853
+ def _get_modelinfo_module_hash(model_path: Path) -> str:
854
+ if model_path.name == "__init__.py":
855
+ # Package entry points often re-export classes implemented in
856
+ # submodules, so include the package contents in the cache key.
857
+ module_paths = sorted(model_path.parent.rglob("*.py"))
858
+ root_path = model_path.parent
859
+ else:
860
+ module_paths = [model_path]
861
+ root_path = model_path.parent
862
+
863
+ hasher = safe_hash(b"", usedforsecurity=False)
864
+ for path in module_paths:
865
+ hasher.update(path.relative_to(root_path).as_posix().encode("utf-8"))
866
+ hasher.update(b"\0")
867
+ hasher.update(path.read_bytes())
868
+ hasher.update(b"\0")
869
+ return hasher.hexdigest()
870
+
871
def _load_modelinfo_from_cache(self, module_hash: str) -> _ModelInfo | None:
872
try:
873
try:
@@ -915,8 +934,7 @@ class _LazyRegisteredModel(_BaseRegisteredModel):
934
module_hash = None
935
936
if model_path is not None and model_path.exists():
918
- with open(model_path, "rb") as f:
919
- module_hash = safe_hash(f.read(), usedforsecurity=False).hexdigest()
937
+ module_hash = self._get_modelinfo_module_hash(model_path)
938
939
mi = self._load_modelinfo_from_cache(module_hash)
940
if mi is not None: