[MyPy][1/N] Fix mypy errors in some tests/ directories and enforce follow-imports=silent (#49570)

Signed-off-by: Martin Hickey <martin.hickey@ie.ibm.com> Co-authored-by: Harry Mellor <19981378+hmellor@users.noreply.github.com>

Martin Hickey committed Jul 30, 2026 at 13:02 UTC 38a267cdd5b30841bb2e2913d67ba18544098c3a
30 files changed +166 -101
tests/compile/correctness_e2e/test_sequence_parallel.py
+6 -2
@@ -348,10 +348,14 @@ def test_tp_sp_generation(
348 if use_inductor_graph_partition and not is_torch_equal_or_newer("2.9.0.dev"):
349 pytest.skip("inductor graph partition is only available in PyTorch 2.9+")
350
351 - # Skip FP8 SP-only test on sm89 (compute capability 8.9)
351 + # Skip FP8 SP-only test on sm89 (compute capability 8.9).
352 + # An unknown capability (None) is left to fail in the test body rather than
353 + # being silently skipped here.
354 + capability = current_platform.get_device_capability()
355 if (
356 "fp8" in model_id.lower()
354 - and current_platform.get_device_capability() < (9, 0)
357 + and capability is not None
358 + and capability < (9, 0)
359 and (not fuse_gemm_comms)
360 ):
361 pytest.skip("FP8 reduction support begins with sm90 capable devices.")
tests/compile/fullgraph/test_full_cudagraph.py
+4 -2
@@ -9,7 +9,7 @@ import pytest
9 from tests.utils import wait_for_gpu_memory_to_clear
10 from tests.v1.attention.utils import full_cg_backend_configs as backend_configs
11 from vllm import LLM, SamplingParams
12 -from vllm.config import CompilationConfig
12 +from vllm.config import CompilationConfig, CUDAGraphMode
13 from vllm.platforms import current_platform
14 from vllm.utils.torch_utils import is_torch_equal_or_newer
15 from vllm.v1.attention.backends.registry import AttentionBackendEnum
@@ -97,7 +97,9 @@ def llm_pair(request):
97 trust_remote_code=True,
98 max_model_len=1024,
99 max_num_seqs=128,
100 - compilation_config=CompilationConfig(cudagraph_mode="PIECEWISE"),
100 + compilation_config=CompilationConfig(
101 + cudagraph_mode=CUDAGraphMode.PIECEWISE
102 + ),
103 generation_config="vllm",
104 seed=42,
105 )
tests/compile/fullgraph/test_full_graph.py
+5 -3
@@ -75,7 +75,7 @@ def test_full_graph(
75 monkeypatch: pytest.MonkeyPatch,
76 model: str,
77 model_kwargs: dict[str, Any],
78 - compilation_mode: int,
78 + compilation_mode: CompilationMode,
79 ):
80 if (
81 "w8a8" in model
@@ -197,7 +197,7 @@ def test_custom_compile_config(
197 ],
198 )
199 def test_fp8_kv_scale_compile(
200 - compilation_mode: int,
200 + compilation_mode: CompilationMode,
201 model: str,
202 backend: AttentionBackendEnum | None,
203 ):
@@ -213,7 +213,9 @@ def test_fp8_kv_scale_compile(
213 run_model(compilation_mode, model, **model_kwargs)
214
215
216 -def run_model(compile_config: int | CompilationConfig, model: str, **model_kwargs):
216 +def run_model(
217 + compile_config: CompilationMode | CompilationConfig, model: str, **model_kwargs
218 +):
219 compilation_config = (
220 compile_config
221 if isinstance(compile_config, CompilationConfig)
tests/compile/fusions_e2e/conftest.py
+4 -2
@@ -12,7 +12,9 @@ from vllm.config import CompilationConfig, CompilationMode, CUDAGraphMode
12 from .common import FUSION_LOG_PATTERNS, AttentionBackendCase, Matches
13
14
15 -def run_model(compile_config: int | CompilationConfig, model: str, **model_kwargs):
15 +def run_model(
16 + compile_config: CompilationMode | CompilationConfig, model: str, **model_kwargs
17 +):
18 """Run a model with the given compilation config for E2E fusion tests."""
19 compilation_config = (
20 compile_config
@@ -54,7 +56,7 @@ def run_model(compile_config: int | CompilationConfig, model: str, **model_kwarg
56 )
57
58 # Fetch match table from each worker via RPC and sum across workers.
57 - worker_tables = llm.llm_engine.engine_core.collective_rpc(
59 + worker_tables: list[dict[str, int]] = llm.llm_engine.engine_core.collective_rpc(
60 "get_compilation_match_table"
61 )
62 combined: defaultdict[str, int] = defaultdict(int)
tests/config/test_bailing_mtp_config.py
+3 -1
@@ -1,6 +1,8 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 +from typing import get_args
5 +
6 from transformers import PretrainedConfig
7
8 from vllm.config.speculative import MTPModelTypes, SpeculativeConfig
@@ -34,7 +36,7 @@ def test_bailing_hybrid_mtp_hf_config_override():
36 assert overridden.model_type == "bailing_hybrid_mtp"
37 assert overridden.architectures == ["BailingMoeV25MTPModel"]
38 assert overridden.n_predict == 1
37 - assert "bailing_hybrid_mtp" in MTPModelTypes.__args__
39 + assert "bailing_hybrid_mtp" in get_args(MTPModelTypes)
40
41
42 def test_bailing_hybrid_mtp_model_arch_config():
tests/config/test_multimodal_config.py
+2 -2
@@ -15,13 +15,13 @@ from vllm.v1.attention.backends.registry import AttentionBackendEnum
15
16
17 def test_mm_encoder_attn_backend_str_conversion():
18 - config = MultiModalConfig(mm_encoder_attn_backend="FLASH_ATTN")
18 + config = MultiModalConfig(mm_encoder_attn_backend="FLASH_ATTN") # type: ignore[arg-type]
19 assert config.mm_encoder_attn_backend == AttentionBackendEnum.FLASH_ATTN
20
21
22 def test_mm_encoder_attn_backend_invalid():
23 with pytest.raises(ValueError):
24 - MultiModalConfig(mm_encoder_attn_backend="not_a_backend")
24 + MultiModalConfig(mm_encoder_attn_backend="not_a_backend") # type: ignore[arg-type]
25
26
27 def test_mm_encoder_attn_backend_hash_updates():
tests/config/test_speculative_draft_max_position_embeddings.py
+2 -1
@@ -14,6 +14,7 @@ methods only.
14 """
15
16 import logging
17 +from typing import Literal
18
19 import pytest
20 from transformers import PretrainedConfig
@@ -77,7 +78,7 @@ def test_override_ignores_missing_attribute(vllm_caplog: pytest.LogCaptureFixtur
78 @pytest.mark.cpu_test
79 @pytest.mark.parametrize("method", ["eagle", "eagle3"])
80 def test_eagle_draft_inherits_target_max_model_len(
80 - method: str, vllm_caplog: pytest.LogCaptureFixture
81 + method: Literal["eagle", "eagle3"], vllm_caplog: pytest.LogCaptureFixture
82 ):
83 target_model_config = ModelConfig(LLAMA3_TARGET)
84 assert target_model_config.max_model_len > 2048
tests/entrypoints/generate/generative_scoring/test_generative_scoring.py
+1 -1
@@ -285,7 +285,7 @@ class TestPromptBuilding:
285 )
286
287 for i, exp in enumerate(expected):
288 - assert engine_inputs[i]["prompt_token_ids"] == exp
288 + assert engine_inputs[i]["prompt_token_ids"] == exp # type: ignore[typeddict-item]
289
290
291 class TestGeneration:
tests/entrypoints/tool_parsers/test_hermes_tool_parser.py
+1 -1
@@ -45,7 +45,7 @@ class ServerConfig(TypedDict, total=False):
45 model: str
46 arguments: list[str]
47 model_arg: str
48 - tool_parser: ToolParser
48 + tool_parser: type[ToolParser]
49
50
51 CONFIGS: dict[str, ServerConfig] = {
tests/entrypoints/weight_transfer/test_weight_transfer_llm.py
+1
@@ -329,4 +329,5 @@ def test_weight_transfer_config_backend():
329 )
330
331 config = llm.llm_engine.vllm_config.weight_transfer_config
332 + assert config is not None
333 assert config.backend == "nccl"
tests/kernels/core/test_fused_qk_norm_rope.py
+2
@@ -35,10 +35,12 @@ def _apply_qk_norm_rope(
35
36 q_by_head = q.view(*q.shape[:-1], q.shape[-1] // head_dim, head_dim)
37 q_by_head = q_norm.forward_native(q_by_head)
38 + assert isinstance(q_by_head, torch.Tensor)
39 q = q_by_head.view(q.shape)
40
41 k_by_head = k.view(*k.shape[:-1], k.shape[-1] // head_dim, head_dim)
42 k_by_head = k_norm.forward_native(k_by_head)
43 + assert isinstance(k_by_head, torch.Tensor)
44 k = k_by_head.view(k.shape)
45
46 q, k = rope.forward_native(positions, q, k)
tests/kernels/core/test_vit_fp8_attn.py
+3 -4
@@ -34,10 +34,9 @@ NUM_HEADS = [16]
34 @pytest.fixture
35 def _fp8_attention():
36 """Create FP8-enabled MMEncoderAttention via config."""
37 - from types import SimpleNamespace
38 - from unittest.mock import patch
37 + from unittest.mock import MagicMock, patch
38
40 - from vllm.config import VllmConfig, set_current_vllm_config
39 + from vllm.config import ModelConfig, VllmConfig, set_current_vllm_config
40 from vllm.config.multimodal import MultiModalConfig
41
42 if not is_flashinfer_cudnn_fp8_prefill_attn_supported():
@@ -45,7 +44,7 @@ def _fp8_attention():
44
45 mm_config = MultiModalConfig(mm_encoder_attn_dtype="fp8")
46 vllm_config = VllmConfig()
48 - vllm_config.model_config = SimpleNamespace(multimodal_config=mm_config)
47 + vllm_config.model_config = MagicMock(spec=ModelConfig, multimodal_config=mm_config)
48
49 # MMEncoderAttention reads torch.get_default_dtype() during init
50 # to determine the output dtype. In real model loading this is bf16.
tests/kernels/core/test_vit_fp8_scaling.py
+5 -6
@@ -4,8 +4,7 @@
4
5 import contextlib
6 import json
7 -from types import SimpleNamespace
8 -from unittest.mock import patch
7 +from unittest.mock import MagicMock, patch
8
9 import pytest
10 import torch
@@ -48,7 +47,7 @@ def _build_attention(mm_config, attn_backend=None):
47 invokes ``process_weights_after_loading`` to simulate the model loader's
48 auto-scan. Yields ``None`` if FlashInfer cuDNN is not available.
49 """
51 - from vllm.config import VllmConfig, set_current_vllm_config
50 + from vllm.config import ModelConfig, VllmConfig, set_current_vllm_config
51 from vllm.model_executor.layers.attention.mm_encoder_attention import (
52 MMEncoderAttention,
53 )
@@ -65,7 +64,7 @@ def _build_attention(mm_config, attn_backend=None):
64 return
65
66 vllm_config = VllmConfig()
68 - vllm_config.model_config = SimpleNamespace(multimodal_config=mm_config)
67 + vllm_config.model_config = MagicMock(spec=ModelConfig, multimodal_config=mm_config)
68
69 with (
70 set_current_vllm_config(vllm_config),
@@ -212,7 +211,7 @@ def test_aiter_static_scales_loaded(tmp_path) -> None:
211
212 def test_static_scales_missing_layer(tmp_path) -> None:
213 """Verify error when requested layer is not in the scale file."""
215 - from vllm.config import VllmConfig, set_current_vllm_config
214 + from vllm.config import ModelConfig, VllmConfig, set_current_vllm_config
215 from vllm.config.multimodal import MultiModalConfig
216 from vllm.v1.attention.backends.registry import AttentionBackendEnum
217
@@ -228,7 +227,7 @@ def test_static_scales_missing_layer(tmp_path) -> None:
227 mm_encoder_fp8_scale_path=str(scale_file),
228 )
229 vllm_config = VllmConfig()
231 - vllm_config.model_config = SimpleNamespace(multimodal_config=mm_config)
230 + vllm_config.model_config = MagicMock(spec=ModelConfig, multimodal_config=mm_config)
231
232 from vllm.model_executor.layers.attention.mm_encoder_attention import (
233 MMEncoderAttention,
tests/kernels/mamba/cpu/test_cpu_gdn_ops.py
+24 -9
@@ -12,6 +12,7 @@ import vllm._custom_ops as ops
12 from vllm.model_executor.layers.mamba.ops.cpu import gdn_attention
13 from vllm.platforms import current_platform
14 from vllm.utils.torch_utils import set_random_seed
15 +from vllm.v1.attention.backends.gdn_attn import GDNAttentionMetadata
16
17 if not current_platform.is_cpu():
18 pytest.skip("skipping CPU-only tests", allow_module_level=True)
@@ -452,12 +453,17 @@ def test_spec_aware_mixed_routing_preserves_token_order(
453
454 spec_indices = torch.tensor([0, 2])
455 nonspec_indices = torch.tensor([1, 3])
455 - metadata = types.SimpleNamespace(
456 + metadata = GDNAttentionMetadata(
457 + num_prefills=1,
458 + num_prefill_tokens=0,
459 + num_decodes=0,
460 + num_decode_tokens=0,
461 + num_spec_decodes=0,
462 + num_spec_decode_tokens=0,
463 + num_actual_tokens=0,
464 spec_sequence_masks=torch.ones(1, dtype=torch.bool),
465 spec_token_indx=spec_indices,
466 non_spec_token_indx=nonspec_indices,
459 - num_prefills=1,
460 - num_decodes=0,
467 )
468 routed = []
469
@@ -501,13 +507,16 @@ def test_spec_aware_nonspec_materializes_state_indices(
507 state_indices = block_table[:, 0]
508 assert not state_indices.is_contiguous()
509
504 - metadata = types.SimpleNamespace(
505 - non_spec_state_indices_tensor=state_indices,
506 - non_spec_query_start_loc=torch.tensor([0, 2, 4], dtype=torch.int32),
507 - num_decodes=0,
508 - num_decode_tokens=0,
510 + metadata = GDNAttentionMetadata(
511 num_prefills=2,
512 num_prefill_tokens=4,
513 + num_decodes=0,
514 + num_decode_tokens=0,
515 + num_spec_decodes=0,
516 + num_spec_decode_tokens=0,
517 + num_actual_tokens=4,
518 + non_spec_state_indices_tensor=state_indices,
519 + non_spec_query_start_loc=torch.tensor([0, 2, 4], dtype=torch.int32),
520 has_initial_state=torch.tensor([False, False]),
521 )
522
@@ -575,8 +584,14 @@ def test_spec_forward_prepares_native_conv_metadata(
584 state_indices = block_table[:, 0]
585 accepted_counts = torch.tensor([1, 4], dtype=torch.int32)
586 assert not state_indices.is_contiguous()
578 - metadata = types.SimpleNamespace(
587 + metadata = GDNAttentionMetadata(
588 + num_prefills=0,
589 + num_prefill_tokens=0,
590 + num_decodes=0,
591 + num_decode_tokens=0,
592 num_spec_decodes=2,
593 + num_spec_decode_tokens=8,
594 + num_actual_tokens=8,
595 spec_state_indices_tensor=block_table,
596 spec_query_start_loc=torch.tensor([0, 4, 8], dtype=torch.int32),
597 num_accepted_tokens=accepted_counts,
tests/kernels/mamba/test_gdn_forward_core_split.py
+5 -1
@@ -174,7 +174,9 @@ def test_forward_core_split_matches_unified(
174 batch = BatchSpec(seq_lens=seq_lens, query_lens=query_lens)
175
176 builder = GDNAttentionMetadataBuilder(
177 - kv_cache_spec=MambaSpec(
177 + # GDNAttentionMetadataBuilder declares kv_cache_spec as AttentionSpec but
178 + # asserts isinstance(kv_cache_spec, MambaSpec). MambaSpec is correct here.
179 + kv_cache_spec=MambaSpec( # type: ignore[arg-type]
180 block_size=BLOCK_SIZE, shapes=((16, 64),), dtypes=(torch.float16,)
181 ),
182 layer_names=[PREFIX],
@@ -198,6 +200,7 @@ def test_forward_core_split_matches_unified(
200 # Full-batch chunk metadata for the unified reference path, built the same
201 # way the builder would for a non-split batch (backend-matched).
202 cu_full = meta_split.non_spec_query_start_loc
203 + assert cu_full is not None
204 if builder.gdn_prefill_backend == "cutedsl":
205 from vllm.model_executor.layers.mamba.ops.gdn_chunk_cutedsl import (
206 prepare_metadata_cutedsl,
@@ -227,6 +230,7 @@ def test_forward_core_split_matches_unified(
230 )
231
232 # Size the state pools from the indices the builder actually produced.
233 + assert meta_split.non_spec_state_indices_tensor is not None
234 pool_size = int(meta_split.non_spec_state_indices_tensor.max().item()) + 1
235 conv_state_shape, temporal_state_shape = (
236 MambaStateShapeCalculator.gated_delta_net_state_shape(
tests/kernels/mamba/test_precopy_mamba_align.py
+14 -7
@@ -21,7 +21,9 @@ The kernel must also no-op when ``src_col < 0`` (fresh request) or
21
22 from __future__ import annotations
23
24 +from collections.abc import Callable
25 from types import SimpleNamespace
26 +from typing import Any
27
28 import numpy as np
29 import torch
@@ -31,6 +33,8 @@ from vllm.platforms import current_platform
33 from vllm.v1.worker import mamba_utils as worker_mamba_utils
34 from vllm.v1.worker.mamba_utils import precopy_mamba_align_fused_kernel
35
36 +_parametrize: Callable[..., Callable[[Any], Any]]
37 +
38 try:
39 import pytest
40
@@ -40,17 +44,18 @@ try:
44 )
45 _parametrize = pytest.mark.parametrize
46 except ModuleNotFoundError: # allow running directly as ``python <thisfile>``
43 - pytest = None
47
48 def _cuda_required(fn):
49 return fn
50
48 - def _parametrize(_name, _values):
51 + def _no_parametrize(_name, _values):
52 def _deco(fn):
53 return fn
54
55 return _deco
56
57 + _parametrize = _no_parametrize
58 +
59
60 NUM_LAYERS = 3
61 CONV_WIDTH = 4 # conv_kernel - 1 + num_spec
@@ -308,8 +313,10 @@ def _make_preprocess_case(token_bias):
313 def test_preprocess_fused_align_matches_scalar_bookkeeping(monkeypatch, token_bias):
314 block_size = 4
315 mamba_spec = SimpleNamespace(block_size=block_size, num_speculative_blocks=1)
311 - cache_config = SimpleNamespace(enable_prefix_caching=True)
312 - kv_cache_config = SimpleNamespace()
316 + # Fakes stand in for real config/context objects. The fused path tests
317 + # below only touch the attributes preprocess_mamba actually reads.
318 + cache_config: Any = SimpleNamespace(enable_prefix_caching=True)
319 + kv_cache_config: Any = SimpleNamespace()
320 scalar_copy_calls = []
321
322 def fake_collect(
@@ -340,7 +347,7 @@ def test_preprocess_fused_align_matches_scalar_bookkeeping(monkeypatch, token_bi
347 scalar_case = _make_preprocess_case(token_bias)
348 fused_case = _make_preprocess_case(token_bias)
349
343 - scalar_copy_bufs = SimpleNamespace(
350 + scalar_copy_bufs: Any = SimpleNamespace(
351 mamba_group_ids=[0],
352 mamba_spec=mamba_spec,
353 offset=0,
@@ -357,8 +364,8 @@ def test_preprocess_fused_align_matches_scalar_bookkeeping(monkeypatch, token_bi
364 copy_bufs=scalar_copy_bufs,
365 )
366
360 - ctx = _FakePrecopyContext(len(fused_case[1].req_ids))
361 - fused_copy_bufs = SimpleNamespace(
367 + ctx: Any = _FakePrecopyContext(len(fused_case[1].req_ids))
368 + fused_copy_bufs: Any = SimpleNamespace(
369 mamba_group_ids=[0],
370 mamba_spec=mamba_spec,
371 offset=0,
tests/models/language/generation/test_mistral.py
+3 -3
@@ -261,7 +261,7 @@ def test_mistral_function_calling(vllm_runner, model: str, dtype: str) -> None:
261
262 model_output = outputs[0].outputs[0].text.strip()
263 assert model_output.startswith(tool_parser.bot_token), model_output
264 - parsed_message = tool_parser.extract_tool_calls(model_output, None)
264 + parsed_message = tool_parser.extract_tool_calls(model_output, None) # type: ignore[arg-type]
265
266 assert parsed_message.tools_called
267
@@ -304,7 +304,7 @@ def test_mistral_function_call_nested_json():
304
305 model_output = f"{parser.bot_token}get_current_weather{json.dumps(args_dict)}"
306
307 - parsed = parser.extract_tool_calls(model_output, None)
307 + parsed = parser.extract_tool_calls(model_output, None) # type: ignore[arg-type]
308
309 # Assertions: the tool call is detected and the full nested JSON is parsed
310 # without truncation.
@@ -337,7 +337,7 @@ def test_mistral_function_call_nested_json():
337 ]
338 )
339
340 - parsed = parser.extract_tool_calls(model_output, None)
340 + parsed = parser.extract_tool_calls(model_output, None) # type: ignore[arg-type]
341
342 # Assertions: the tool call is detected and the full nested JSON is parsed
343 # without truncation.
tests/models/quantization/test_bitsandbytes.py
+1 -1
@@ -323,7 +323,7 @@ def test_bitsandbytes_passes_revision_by_name():
323 return_value=["/folder/model.safetensors"],
324 ),
325 ):
326 - bnb.BitsAndBytesModelLoader._prepare_weights(fake_self, "org/model", "myrev")
326 + bnb.BitsAndBytesModelLoader._prepare_weights(fake_self, "org/model", "myrev") # type: ignore[arg-type]
327
328 mock_idx.assert_called_once()
329 assert mock_idx.call_args.kwargs.get("revision") == "myrev"
tests/plugins/bge_m3_sparse_plugin/bge_m3_sparse_processor/sparse_embeddings_processor.py
+3 -3
@@ -29,7 +29,7 @@ class BgeM3SparseEmbeddingsProcessor(
29 self.online_requests: dict[str, SparseEmbeddingCompletionRequestMixin] = {}
30 self.renderer: BaseRenderer = renderer
31 self.default_pooling_params = {}
32 - pooler_config: PoolerConfig = vllm_config.model_config.pooler_config
32 + pooler_config: PoolerConfig | None = vllm_config.model_config.pooler_config
33 if pooler_config is not None:
34 for param in ["use_activation", "dimensions"]:
35 if getattr(pooler_config, param, None) is None:
@@ -91,11 +91,11 @@ class BgeM3SparseEmbeddingsProcessor(
91 ) -> list[SparseEmbeddingTokenWeight]:
92 token_ids = sparse_embedding.keys()
93 token_weights = sparse_embedding.values()
94 - tokens = [None] * len(token_ids)
94 + tokens: Sequence[str | None] = [None] * len(token_ids)
95
96 if return_tokens and self.renderer is not None:
97 tokens = convert_ids_list_to_tokens(
98 - self.renderer.get_tokenizer(), token_ids
98 + self.renderer.get_tokenizer(), list(token_ids)
99 )
100 sparse_embedding_output: list[SparseEmbeddingTokenWeight] = []
101 for token_id, weight, token in zip(token_ids, token_weights, tokens):
tests/plugins/prithvi_io_processor_plugin/prithvi_io_processor/prithvi_processor.py
+6 -6
@@ -170,7 +170,7 @@ def load_image(
170 list of meta info for each image in *file_paths*
171 """
172
173 - imgs = []
173 + imgs: list[np.ndarray] = []
174 metas = []
175 temporal_coords = []
176 location_coords = []
@@ -209,11 +209,11 @@ def load_image(
209 except Exception:
210 logger.exception("Could not extract timestamp for %s", file)
211
212 - imgs = np.stack(imgs, axis=0) # num_frames, H, W, C
213 - imgs = np.moveaxis(imgs, -1, 0).astype("float32") # C, num_frames, H, W
214 - imgs = np.expand_dims(imgs, axis=0) # add batch di
212 + stacked = np.stack(imgs, axis=0) # num_frames, H, W, C
213 + stacked = np.moveaxis(stacked, -1, 0).astype("float32") # C, num_frames, H, W
214 + stacked = np.expand_dims(stacked, axis=0) # add batch di
215
216 - return imgs, temporal_coords, location_coords, metas
216 + return stacked, temporal_coords, location_coords, metas
217
218
219 class PrithviMultimodalDataProcessor(IOProcessor[ImagePrompt, ImageRequestOutput]):
@@ -327,7 +327,7 @@ class PrithviMultimodalDataProcessor(IOProcessor[ImagePrompt, ImageRequestOutput
327 }
328 )
329
330 - return prompts
330 + return prompts # type: ignore[return-value]
331
332 def post_process(
333 self,
tests/plugins/vllm_add_dummy_platform/vllm_add_dummy_platform/dummy_platform.py
+8 -11
@@ -6,6 +6,8 @@ from vllm.platforms.interface import Platform, PlatformEnum
6
7 if TYPE_CHECKING:
8 from vllm.config import VllmConfig
9 + from vllm.v1.attention.backends.registry import AttentionBackendEnum
10 + from vllm.v1.attention.selector import AttentionSelectorConfig
11 else:
12 VllmConfig = None
13
@@ -20,16 +22,11 @@ class DummyPlatform(Platform):
22 def check_and_update_config(cls, vllm_config: VllmConfig) -> None:
23 vllm_config.compilation_config.custom_ops = ["all"]
24
25 + @classmethod
26 def get_attn_backend_cls(
24 - self,
25 - backend_name,
26 - head_size,
27 - dtype,
28 - kv_cache_dtype,
29 - block_size,
30 - use_mla,
31 - has_sink,
32 - use_sparse,
33 - use_mm_prefix,
34 - ):
27 + cls,
28 + selected_backend: "AttentionBackendEnum",
29 + attn_selector_config: "AttentionSelectorConfig",
30 + num_heads: int | None = None,
31 + ) -> str:
32 return "vllm_add_dummy_platform.dummy_attention_backend.DummyAttentionBackend" # noqa E501
tests/plugins/vllm_add_dummy_stat_logger/dummy_stat_logger/dummy_stat_logger.py
+3 -1
@@ -17,7 +17,9 @@ class DummyStatLogger(StatLoggerBase):
17 self.logged = False
18 self.engine_initialized = False
19
20 - def record(self, scheduler_stats, iteration_stats, mm_cache_stats, engine_idx):
20 + def record(
21 + self, scheduler_stats, iteration_stats, mm_cache_stats=None, engine_idx=0
22 + ):
23 self.recorded.append(
24 (scheduler_stats, iteration_stats, mm_cache_stats, engine_idx)
25 )
tests/plugins_tests/gguf/test_gguf_plugin_multimodal.py
+1 -1
@@ -92,7 +92,7 @@ def run_multimodal_gguf_test(
92 num_logprobs: int,
93 ):
94 # Load images at runtime (inside subprocess) to avoid pickle issues
95 - images = [ImageAsset(name).pil_image for name in model.image_names]
95 + images = [ImageAsset(name).pil_image for name in model.image_names] # type: ignore[arg-type]
96 size_factors = [0.25, 0.5, 1.0]
97 inputs_per_image = [
98 (
tests/plugins_tests/lora_resolvers/test_hf_hub_resolver.py
+1
@@ -31,6 +31,7 @@ async def test_hf_resolver_with_direct_path():
31 assert hf_resolver is not None
32
33 lora_request = await hf_resolver.resolve_lora(LORA_REPO_MODEL_NAME, LORA_REPO)
34 + assert lora_request is not None
35 assert lora_request.lora_name == LORA_REPO
36 assert REPO_DOWNLOAD_DIR in lora_request.lora_path
37 assert "adapter_config.json" in os.listdir(lora_request.lora_path)
tests/spec_decode/test_custom_proposer.py
+1
@@ -30,6 +30,7 @@ class DummyDraftProposer:
30 Args:
31 vllm_config: vLLM configuration containing model and speculative settings.
32 """
33 + assert vllm_config.speculative_config is not None
34 self.num_speculative_tokens = (
35 vllm_config.speculative_config.num_speculative_tokens
36 )
tests/transformers_utils/test_processor.py
+2 -2
@@ -44,7 +44,7 @@ class _ProcWithUnpack:
44
45 def test_get_processor_kwargs_from_processor_unpack_path_returns_full_union():
46 proc = _ProcWithUnpack()
47 - keys = get_processor_kwargs_keys(get_processor_kwargs_type(proc))
47 + keys = get_processor_kwargs_keys(get_processor_kwargs_type(proc)) # type: ignore[arg-type]
48 _assert_has_all_expected(keys)
49
50
@@ -63,5 +63,5 @@ def test_get_processor_kwargs_from_processor_module_scan_returns_full_union():
63 assert hasattr(mod, "_FakeProcessorKwargs")
64
65 proc = _ProcWithoutUnpack()
66 - keys = get_processor_kwargs_keys(get_processor_kwargs_type(proc))
66 + keys = get_processor_kwargs_keys(get_processor_kwargs_type(proc)) # type: ignore[arg-type]
67 _assert_has_all_expected(keys)
tests/v1/distributed/test_async_llm_dp.py
+5 -3
@@ -12,13 +12,14 @@ import pytest
12
13 from vllm import SamplingParams
14 from vllm.config import VllmConfig
15 +from vllm.config.parallel import DataParallelBackend
16 from vllm.engine.arg_utils import AsyncEngineArgs
17 from vllm.inputs import PromptType
18 from vllm.outputs import RequestOutput
19 from vllm.platforms import current_platform
20 from vllm.sampling_params import RequestOutputKind
21 from vllm.v1.engine.async_llm import AsyncLLM
21 -from vllm.v1.engine.core_client import DPAsyncMPClient
22 +from vllm.v1.engine.core_client import DPLBAsyncMPClient
23 from vllm.v1.metrics.loggers import StatLoggerBase
24 from vllm.v1.metrics.stats import IterationStats, MultiModalCacheStats, SchedulerStats
25
@@ -82,7 +83,7 @@ async def generate(
83 async def test_load(
84 model: str,
85 output_kind: RequestOutputKind,
85 - data_parallel_backend: str,
86 + data_parallel_backend: DataParallelBackend,
87 async_scheduling: bool,
88 ):
89 if async_scheduling and data_parallel_backend == "ray":
@@ -162,7 +163,8 @@ async def test_load(
163 assert not engine.output_processor.has_unfinished_requests()
164
165 # testing internals here which may break
165 - core_client: DPAsyncMPClient = engine.engine_core
166 + core_client = engine.engine_core
167 + assert isinstance(core_client, DPLBAsyncMPClient)
168 # the engines only synchronize stopping every N steps so
169 # allow a small amount of time here.
170 for _ in range(10):
tests/v1/distributed/test_eagle_dp.py
+1 -1
@@ -61,7 +61,7 @@ async def test_run_eagle_dp(monkeypatch: pytest.MonkeyPatch, attn_backend: str):
61 data_parallel_backend="mp", # ray takes more time
62 trust_remote_code=True,
63 max_model_len=16384,
64 - attention_config={"backend": attn_backend},
64 + attention_config={"backend": attn_backend}, # type: ignore[arg-type]
65 )
66
67 eagle_engine_args = replace(
tests/v1/shutdown/test_processor_error.py
+8 -3
@@ -9,7 +9,7 @@ import pytest
9 from tests.v1.shutdown.utils import SHUTDOWN_TEST_TIMEOUT_SEC
10 from vllm import SamplingParams
11 from vllm.engine.arg_utils import AsyncEngineArgs
12 -from vllm.inputs import TokensPrompt
12 +from vllm.inputs import ExplicitEncoderDecoderPrompt
13 from vllm.sampling_params import RequestOutputKind
14 from vllm.v1.engine.async_llm import AsyncLLM
15 from vllm.v1.engine.exceptions import EngineGenerateError
@@ -29,9 +29,14 @@ async def test_async_llm_processor_error(model: str) -> None:
29 async_llm = AsyncLLM.from_engine_args(engine_args)
30
31 async def generate(request_id: str):
32 - # [] is not allowed and will raise a ValueError in Processor.
32 + # An encoder/decoder prompt is rejected by the Processor for a
33 + # decoder only model.
34 generator = async_llm.generate(
34 - TokensPrompt([]), request_id=request_id, sampling_params=SamplingParams()
35 + ExplicitEncoderDecoderPrompt(
36 + encoder_prompt="Hello my name is", decoder_prompt=None
37 + ),
38 + request_id=request_id,
39 + sampling_params=SamplingParams(),
40 )
41 try:
42 async for _ in generator:
tools/pre_commit/mypy.py
+41 -24
@@ -21,34 +21,55 @@ import sys
21
22 import regex as re
23
24 +# Paths verified clean under follow_imports="silent". Matched before
25 +# SEPARATE_GROUPS, so these files join the default group and are checked at the
26 +# stricter setting even while a parent directory remains in SEPARATE_GROUPS.
27 +#
28 +# Fixing a directory means moving it from SEPARATE_GROUPS to here. Without that
29 +# move the fixes are not enforced because "tests" claims every file below it.
30 +SILENT_GROUPS = [
31 + "tests/compile/correctness_e2e",
32 + "tests/compile/fullgraph",
33 + "tests/compile/fusions_e2e",
34 + "tests/config",
35 + "tests/entrypoints/generate",
36 + "tests/entrypoints/tool_parsers",
37 + "tests/entrypoints/weight_transfer",
38 + "tests/kernels/core",
39 + "tests/kernels/mamba",
40 + "tests/models/language",
41 + "tests/models/quantization",
42 + "tests/plugins/bge_m3_sparse_plugin",
43 + "tests/plugins/prithvi_io_processor_plugin",
44 + "tests/plugins/vllm_add_dummy_platform",
45 + "tests/plugins/vllm_add_dummy_stat_logger",
46 + "tests/plugins_tests/gguf",
47 + "tests/plugins_tests/lora_resolvers",
48 + "tests/spec_decode",
49 + "tests/transformers_utils",
50 + "tests/v1/distributed",
51 + "tests/v1/shutdown",
52 +]
53 +
54 # After fixing errors resulting from changing follow_imports
25 -# from "skip" to "silent", remove its directory from SEPARATE_GROUPS.
55 +# from "skip" to "silent", move its directory to SILENT_GROUPS.
56 SEPARATE_GROUPS = [
57 "tests",
58 "tests/benchmarks",
29 - "tests/compile/correctness_e2e",
30 - "tests/config",
59 "tests/compile",
32 - "tests/compile/fullgraph",
33 - "tests/compile/fusions_e2e",
60 "tests/compile/passes",
61 "tests/distributed",
62 "tests/entrypoints/anthropic",
37 - "tests/entrypoints/generate",
63 "tests/entrypoints/llm",
64 "tests/entrypoints/multimodal",
65 "tests/entrypoints/openai",
66 "tests/entrypoints/pooling",
67 "tests/entrypoints/serve",
68 "tests/entrypoints/speech_to_text",
44 - "tests/entrypoints/tool_parsers",
69 "tests/entrypoints/unit_tests",
46 - "tests/entrypoints/weight_transfer",
70 "tests/kernels",
71 "tests/kernels/attention",
49 - "tests/kernels/core",
72 "tests/kernels/helion",
51 - "tests/kernels/mamba",
73 "tests/kernels/moe",
74 "tests/kernels/quantization",
75 "tests/lora",
@@ -57,34 +78,23 @@ SEPARATE_GROUPS = [
78 "tests/model_executor/model_loader",
79 "tests/models",
80 "tests/models/test_initialization.py",
60 - "tests/models/language",
81 "tests/models/multimodal",
62 - "tests/models/quantization",
82 "tests/multimodal",
83 "tests/parser",
65 - "tests/plugins_tests/gguf",
66 - "tests/plugins_tests/lora_resolvers",
67 - "tests/plugins/bge_m3_sparse_plugin",
68 - "tests/plugins/prithvi_io_processor_plugin",
69 - "tests/plugins/vllm_add_dummy_platform",
70 - "tests/plugins/vllm_add_dummy_stat_logger",
84 "tests/plugins_tests",
85 "tests/quantization",
86 "tests/reasoning",
87 "tests/renderers",
88 "tests/samplers",
76 - "tests/spec_decode",
89 "tests/tokenizers_",
90 "tests/tool_parsers",
91 "tests/tool_use",
80 - "tests/transformers_utils",
92 "tests/utils_",
93 "tests/v1",
94 "tests/v1/attention",
95 "tests/v1/core",
96 "tests/v1/cudagraph",
97 "tests/v1/determinism",
87 - "tests/v1/distributed",
98 "tests/v1/e2e",
99 "tests/v1/ec_connector",
100 "tests/v1/engine",
@@ -94,7 +104,6 @@ SEPARATE_GROUPS = [
104 "tests/v1/logits_processors",
105 "tests/v1/metrics",
106 "tests/v1/sample",
97 - "tests/v1/shutdown",
107 "tests/v1/simple_kv_offload",
108 "tests/v1/spec_decode",
109 "tests/v1/streaming_input",
@@ -142,14 +151,22 @@ def group_files(changed_files: list[str]) -> dict[str, list[str]]:
151 A dictionary mapping file group names to lists of changed files.
152 """
153 exclude_pattern = re.compile(f"^{'|'.join(EXCLUDE)}.*")
145 - file_groups = {"": []}
154 + silent_pattern = re.compile(f"^({'|'.join(SILENT_GROUPS)}).*")
155 + file_groups: dict[str, list[str]] = {"": []}
156 file_groups.update({k: [] for k in SEPARATE_GROUPS})
157 + # Longest path first so a sub-directory is not shadowed by its parent
158 + separate_groups = sorted(SEPARATE_GROUPS, key=len, reverse=True)
159 for changed_file in changed_files:
160 # Skip files which should be ignored completely
161 if exclude_pattern.match(changed_file):
162 continue
163 + # Already-fixed paths go in the default group, which runs at the
164 + # stricter follow_imports setting from pyproject.toml
165 + if silent_pattern.match(changed_file):
166 + file_groups[""].append(changed_file)
167 + continue
168 # Group files by mypy call
152 - for directory in SEPARATE_GROUPS:
169 + for directory in separate_groups:
170 if re.match(f"^{directory}.*", changed_file):
171 file_groups[directory].append(changed_file)
172 break