mirror of
https://github.com/vllm-project/vllm.git
synced 2026-10-28 09:45:26 +08:00
[MyPy][2/N] Fix mypy errors in small tests/ dirs (#51043)
Signed-off-by: Martin Hickey <martin.hickey@ie.ibm.com> Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com> Co-authored-by: Harry Mellor <19981378+hmellor@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
71 files changed
+491
-301
No files matched your search
@@ -285,7 +285,7 @@ def test_async_tp_pass_requires_full_graph_compilation():
|
||||
]
|
||||
|
||||
async_tp_pass = object.__new__(AsyncTPPass)
|
||||
async_tp_pass.compilation_config = vllm_config.compilation_config
|
||||
async_tp_pass.compilation_config = vllm_config.compilation_config # type: ignore[assignment]
|
||||
|
||||
with pytest.raises(
|
||||
AssertionError, match="AsyncTPPass requires full-graph compilation"
|
||||
|
||||
@@ -111,7 +111,7 @@ def test_fused_ar_workspace_hidden_dim(
|
||||
target_hidden: int, draft_hidden: int | None, expected: int
|
||||
):
|
||||
config = _make_workspace_hidden_config(target_hidden, draft_hidden)
|
||||
assert _fused_ar_workspace_hidden_dim(config) == expected
|
||||
assert _fused_ar_workspace_hidden_dim(config) == expected # type: ignore[arg-type]
|
||||
|
||||
|
||||
def test_fused_ar_workspace_hidden_dim_spec_without_draft():
|
||||
@@ -120,7 +120,7 @@ def test_fused_ar_workspace_hidden_dim_spec_without_draft():
|
||||
model_config=SimpleNamespace(get_hidden_size=lambda: 2048),
|
||||
speculative_config=SimpleNamespace(draft_model_config=None),
|
||||
)
|
||||
assert _fused_ar_workspace_hidden_dim(config) == 2048
|
||||
assert _fused_ar_workspace_hidden_dim(config) == 2048 # type: ignore[arg-type]
|
||||
|
||||
|
||||
class TestAllReduceRMSNormModel(torch.nn.Module):
|
||||
|
||||
@@ -222,7 +222,7 @@ def test_sequence_parallelism_pass_requires_full_graph_compilation():
|
||||
]
|
||||
|
||||
sequence_parallelism_pass = object.__new__(SequenceParallelismPass)
|
||||
sequence_parallelism_pass.compilation_config = vllm_config.compilation_config
|
||||
sequence_parallelism_pass.compilation_config = vllm_config.compilation_config # type: ignore[assignment]
|
||||
sequence_parallelism_pass.min_token_num = 1
|
||||
|
||||
with pytest.raises(
|
||||
|
||||
@@ -33,6 +33,7 @@ from vllm.config import (
|
||||
VllmConfig,
|
||||
set_current_vllm_config,
|
||||
)
|
||||
from vllm.config.cache import CacheDType
|
||||
from vllm.forward_context import get_forward_context, set_forward_context
|
||||
from vllm.model_executor.layers.attention import Attention
|
||||
from vllm.model_executor.layers.quantization.utils.quant_utils import (
|
||||
@@ -198,6 +199,7 @@ class TestAttentionAiterFp8StaticQuantPatternModel(
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fp8_linear.kernel.quant_fp8.use_aiter = True
|
||||
assert self.fp8_linear.input_scale is not None
|
||||
self.fp8_linear.input_scale.fill_(0.125)
|
||||
|
||||
|
||||
@@ -307,7 +309,7 @@ def test_attention_quant_pattern(
|
||||
head_size: int,
|
||||
batch_size: int,
|
||||
dtype: torch.dtype,
|
||||
kv_cache_dtype: str,
|
||||
kv_cache_dtype: CacheDType,
|
||||
custom_ops: str,
|
||||
model_name: str,
|
||||
model_class: type[AttentionQuantPatternModel],
|
||||
|
||||
@@ -24,6 +24,7 @@ from vllm.config import (
|
||||
PassConfig,
|
||||
VllmConfig,
|
||||
)
|
||||
from vllm.config.cache import CacheDType
|
||||
from vllm.forward_context import get_forward_context, set_forward_context
|
||||
from vllm.model_executor.layers.attention import MLAAttention
|
||||
from vllm.model_executor.layers.linear import ColumnParallelLinear
|
||||
@@ -254,7 +255,7 @@ def test_mla_rope_kvcache_cat_fusion(
|
||||
block_size: int,
|
||||
is_neox: bool,
|
||||
dtype: torch.dtype,
|
||||
kv_cache_dtype: str,
|
||||
kv_cache_dtype: CacheDType,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
):
|
||||
torch.set_default_device("cuda")
|
||||
|
||||
@@ -39,6 +39,7 @@ from vllm.config import (
|
||||
PassConfig,
|
||||
VllmConfig,
|
||||
)
|
||||
from vllm.config.cache import CacheDType
|
||||
from vllm.forward_context import get_forward_context, set_forward_context
|
||||
from vllm.model_executor.layers.attention import Attention
|
||||
from vllm.model_executor.layers.layernorm import RMSNorm
|
||||
@@ -342,7 +343,7 @@ def _run_qk_norm_rope_kvcache_fusion_test(
|
||||
use_shuffle_kv_layout: str,
|
||||
kv_layout: KVCacheLayout,
|
||||
dtype: torch.dtype,
|
||||
kv_cache_dtype: str,
|
||||
kv_cache_dtype: CacheDType,
|
||||
rms_norm_eps: float,
|
||||
custom_op: str,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
@@ -611,7 +612,7 @@ def test_qk_norm_rope_kvcache_fusion(
|
||||
kv_layout: KVCacheLayout,
|
||||
block_size: int,
|
||||
dtype: torch.dtype,
|
||||
kv_cache_dtype: str,
|
||||
kv_cache_dtype: CacheDType,
|
||||
rms_norm_eps: float,
|
||||
custom_op: str,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
@@ -663,7 +664,7 @@ def test_qk_norm_mrope_kvcache_fusion(
|
||||
mrope_interleaved: bool,
|
||||
is_neox: bool,
|
||||
kv_layout: KVCacheLayout,
|
||||
kv_cache_dtype: str,
|
||||
kv_cache_dtype: CacheDType,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
):
|
||||
_run_qk_norm_rope_kvcache_fusion_test(
|
||||
|
||||
@@ -30,6 +30,7 @@ from vllm.config import (
|
||||
PassConfig,
|
||||
VllmConfig,
|
||||
)
|
||||
from vllm.config.cache import CacheDType
|
||||
from vllm.config.utils import Range
|
||||
from vllm.forward_context import get_forward_context, set_forward_context
|
||||
from vllm.model_executor.layers.attention import Attention
|
||||
@@ -324,7 +325,7 @@ def test_rope_kvcache_fusion(
|
||||
block_size: int,
|
||||
is_neox: bool,
|
||||
dtype: torch.dtype,
|
||||
kv_cache_dtype: str,
|
||||
kv_cache_dtype: CacheDType,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
):
|
||||
torch.set_default_device("cuda")
|
||||
@@ -468,7 +469,7 @@ def test_rope_static_qquant_kvcache_fusion(
|
||||
block_size: int,
|
||||
is_neox: bool,
|
||||
dtype: torch.dtype,
|
||||
kv_cache_dtype: str,
|
||||
kv_cache_dtype: CacheDType,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
):
|
||||
torch.set_default_device("cuda")
|
||||
|
||||
@@ -60,7 +60,7 @@ class TestSiluMulFp8QuantModel(torch.nn.Module):
|
||||
def __init__(
|
||||
self,
|
||||
hidden_size: int,
|
||||
force_kernel: FP8ScaledMMLinearKernel,
|
||||
force_kernel: type[FP8ScaledMMLinearKernel],
|
||||
dtype: torch.dtype,
|
||||
**kwargs,
|
||||
):
|
||||
@@ -282,7 +282,7 @@ def test_fusion_silu_and_mul_quant(
|
||||
],
|
||||
enable_silu_mul_custom_op: bool,
|
||||
enable_quant_fp8_custom_op: bool,
|
||||
force_kernel: FP8ScaledMMLinearKernel | None,
|
||||
force_kernel: type[FP8ScaledMMLinearKernel] | None,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
):
|
||||
if model_class is TestSiluMulNvfp4QuantModel and not is_nvfp4_supported():
|
||||
@@ -330,7 +330,10 @@ def test_fusion_silu_and_mul_quant(
|
||||
passes = [NoOpEliminationPass(config), *fusion_passes, PostCleanupPass(config)]
|
||||
backend = TestBackend(*passes)
|
||||
model = model_class(
|
||||
hidden_size=hidden_size, force_kernel=force_kernel, x=x, dtype=dtype
|
||||
hidden_size=hidden_size,
|
||||
force_kernel=force_kernel, # type: ignore[arg-type]
|
||||
x=x,
|
||||
dtype=dtype,
|
||||
)
|
||||
|
||||
# First dimension dynamic
|
||||
|
||||
@@ -84,7 +84,7 @@ def test_manual_fusion_fp8_static_with_linear(
|
||||
num_tokens: int,
|
||||
hidden_size: int,
|
||||
dtype: torch.dtype,
|
||||
force_kernel: FP8ScaledMMLinearKernel,
|
||||
force_kernel: type[FP8ScaledMMLinearKernel],
|
||||
):
|
||||
"""Test manual fusion with real FP8 linear layer (kFp8StaticTensorSym).
|
||||
|
||||
|
||||
@@ -307,7 +307,8 @@ def test_external_process_monitoring(api_server_args):
|
||||
def run_with_exception_capture():
|
||||
try:
|
||||
wait_for_completion_or_failure(
|
||||
api_server_manager=manager, coordinator=mock_coordinator
|
||||
api_server_manager=manager,
|
||||
coordinator=mock_coordinator, # type: ignore[arg-type]
|
||||
)
|
||||
except Exception as e:
|
||||
result["exception"] = e
|
||||
@@ -376,7 +377,7 @@ def test_gather_actual_addresses_end_to_end():
|
||||
manager = APIServerProcessManager(
|
||||
listen_address=f"tcp://{host}:0",
|
||||
sock=sock,
|
||||
args="test_args",
|
||||
args="test_args", # type: ignore[arg-type]
|
||||
num_servers=num_servers,
|
||||
input_addresses=placeholder_inputs,
|
||||
output_addresses=placeholder_outputs,
|
||||
@@ -423,7 +424,7 @@ def test_gather_actual_addresses_child_crash_before_report():
|
||||
manager = APIServerProcessManager(
|
||||
listen_address=f"tcp://{host}:0",
|
||||
sock=sock,
|
||||
args="test_args",
|
||||
args="test_args", # type: ignore[arg-type]
|
||||
num_servers=num_servers,
|
||||
input_addresses=placeholder_inputs,
|
||||
output_addresses=placeholder_outputs,
|
||||
|
||||
@@ -108,8 +108,8 @@ async def test_unload_lora_adapter_success():
|
||||
response = await serving_models.load_lora_adapter(request)
|
||||
assert len(serving_models.lora_requests) == 1
|
||||
|
||||
request = UnloadLoRAAdapterRequest(lora_name="adapter1")
|
||||
response = await serving_models.unload_lora_adapter(request)
|
||||
unload_request = UnloadLoRAAdapterRequest(lora_name="adapter1")
|
||||
response = await serving_models.unload_lora_adapter(unload_request)
|
||||
assert response == LORA_UNLOADING_SUCCESS_MESSAGE.format(lora_name="adapter1")
|
||||
assert len(serving_models.lora_requests) == 0
|
||||
|
||||
|
||||
@@ -84,7 +84,10 @@ def task_routes(request, monkeypatch) -> tuple[str, list[tuple[str, list[str]]]]
|
||||
|
||||
# Register routers for this specific task (development mode already enabled).
|
||||
register_api_routers(
|
||||
args, app, supported_tasks=(task,), model_config=MockModelConfig()
|
||||
args,
|
||||
app,
|
||||
supported_tasks=(task,),
|
||||
model_config=MockModelConfig(), # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
routes = get_all_http_routes(app)
|
||||
|
||||
@@ -19,6 +19,7 @@ from vllm.entrypoints.serve.tokenize.api_router import attach_router
|
||||
from vllm.entrypoints.serve.tokenize.protocol import (
|
||||
TokenizeChatRequest,
|
||||
TokenizeCompletionRequest,
|
||||
TokenizeResponse,
|
||||
)
|
||||
from vllm.entrypoints.serve.tokenize.serving import ServingTokenization
|
||||
from vllm.exceptions import VLLMNotFoundError, VLLMValidationError
|
||||
@@ -95,7 +96,7 @@ async def test_tokenize_chat_skips_mm_cache_for_renderer_only_path():
|
||||
mock_engine.renderer = MagicMock()
|
||||
|
||||
serving = _build_serving_tokenization(mock_engine)
|
||||
serving.online_renderer.preprocess_chat = AsyncMock(
|
||||
serving.online_renderer.preprocess_chat = AsyncMock( # type: ignore[method-assign]
|
||||
return_value=(
|
||||
[{"role": "user", "content": "Test"}],
|
||||
[{"prompt_token_ids": [1, 2, 3]}],
|
||||
@@ -109,7 +110,7 @@ async def test_tokenize_chat_skips_mm_cache_for_renderer_only_path():
|
||||
|
||||
response = await serving.create_tokenize(request, MagicMock(headers={}))
|
||||
|
||||
assert response.tokens == [1, 2, 3]
|
||||
assert isinstance(response, TokenizeResponse) and response.tokens == [1, 2, 3]
|
||||
assert (
|
||||
serving.online_renderer.preprocess_chat.call_args.kwargs["skip_mm_cache"]
|
||||
is True
|
||||
@@ -125,7 +126,7 @@ async def test_tokenize_completion_skips_mm_cache_for_renderer_only_path():
|
||||
mock_engine.renderer = MagicMock()
|
||||
|
||||
serving = _build_serving_tokenization(mock_engine)
|
||||
serving.online_renderer.preprocess_completion = AsyncMock(
|
||||
serving.online_renderer.preprocess_completion = AsyncMock( # type: ignore[method-assign]
|
||||
return_value=[{"prompt_token_ids": [1, 2, 3]}]
|
||||
)
|
||||
|
||||
@@ -136,7 +137,7 @@ async def test_tokenize_completion_skips_mm_cache_for_renderer_only_path():
|
||||
|
||||
response = await serving.create_tokenize(request, MagicMock(headers={}))
|
||||
|
||||
assert response.tokens == [1, 2, 3]
|
||||
assert isinstance(response, TokenizeResponse) and response.tokens == [1, 2, 3]
|
||||
assert (
|
||||
serving.online_renderer.preprocess_completion.call_args.kwargs["skip_mm_cache"]
|
||||
is True
|
||||
|
||||
@@ -101,13 +101,13 @@ async def test_tokenize_chat(
|
||||
if continue_final:
|
||||
conversation.append({"role": "assistant", "content": "Sure,"})
|
||||
|
||||
prompt = tokenizer.apply_chat_template(
|
||||
prompt = tokenizer.apply_chat_template( # type: ignore[call-arg]
|
||||
add_generation_prompt=add_generation,
|
||||
continue_final_message=continue_final,
|
||||
conversation=conversation,
|
||||
tokenize=False,
|
||||
)
|
||||
tokens = tokenizer.encode(prompt, add_special_tokens=add_special)
|
||||
tokens = tokenizer.encode(prompt, add_special_tokens=add_special) # type: ignore[arg-type]
|
||||
|
||||
response = requests.post(
|
||||
server.url_for("tokenize"),
|
||||
@@ -169,14 +169,14 @@ async def test_tokenize_chat_with_tools(
|
||||
if continue_final:
|
||||
conversation.append({"role": "assistant", "content": "Sure,"})
|
||||
|
||||
prompt = tokenizer.apply_chat_template(
|
||||
prompt = tokenizer.apply_chat_template( # type: ignore[call-arg]
|
||||
add_generation_prompt=add_generation,
|
||||
continue_final_message=continue_final,
|
||||
conversation=conversation,
|
||||
tools=tools,
|
||||
tokenize=False,
|
||||
)
|
||||
tokens = tokenizer.encode(prompt, add_special_tokens=add_special)
|
||||
tokens = tokenizer.encode(prompt, add_special_tokens=add_special) # type: ignore[arg-type]
|
||||
|
||||
response = requests.post(
|
||||
server.url_for("tokenize"),
|
||||
|
||||
@@ -18,7 +18,7 @@ def _cfg(tp=1, pp=1, dp=1, ep=False, digest="a3b21f94deadbeef"):
|
||||
enable_expert_parallel=ep,
|
||||
)
|
||||
)
|
||||
c.compute_hash = lambda: digest # type: ignore[attr-defined]
|
||||
c.compute_hash = lambda: digest
|
||||
return c
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ def test_get_respects_set_default():
|
||||
|
||||
fp.set_default_fingerprint_mode("hash")
|
||||
hashed = fp.get_system_fingerprint(cfg)
|
||||
assert hashed is not None
|
||||
assert hashed != full
|
||||
assert "tp8" not in hashed
|
||||
|
||||
@@ -72,5 +73,7 @@ def test_get_respects_set_default():
|
||||
def test_compute_hash_failure_does_not_raise():
|
||||
cfg = _cfg()
|
||||
cfg.compute_hash = lambda: (_ for _ in ()).throw(RuntimeError("boom"))
|
||||
assert fp.build_system_fingerprint(cfg, "full").endswith("-nohash")
|
||||
assert fp.build_system_fingerprint(cfg, "hash").endswith("-nohash")
|
||||
full_fp = fp.build_system_fingerprint(cfg, "full")
|
||||
assert full_fp is not None and full_fp.endswith("-nohash")
|
||||
hash_fp = fp.build_system_fingerprint(cfg, "hash")
|
||||
assert hash_fp is not None and hash_fp.endswith("-nohash")
|
||||
@@ -17,6 +17,7 @@ from vllm.config import ModelConfig
|
||||
from vllm.entrypoints.chat_utils import (
|
||||
MEDIA_CONNECTOR_REGISTRY,
|
||||
AsyncMultiModalItemTracker,
|
||||
ChatCompletionMessageParam,
|
||||
ConversationMessage,
|
||||
_load_embeds_dict,
|
||||
_parse_metadata_array,
|
||||
@@ -215,7 +216,7 @@ def video_url():
|
||||
@pytest.fixture(scope="module")
|
||||
def audio_url():
|
||||
audio = AudioAsset("mary_had_lamb")
|
||||
return encode_audio_url(*audio.audio_and_sample_rate)
|
||||
return encode_audio_url(*audio.audio_and_sample_rate) # type: ignore[arg-type]
|
||||
|
||||
|
||||
def _assert_mm_data_is_image_input(
|
||||
@@ -769,7 +770,9 @@ async def test_text_only_chat_does_not_initialize_media_connector(
|
||||
):
|
||||
load_connector = MagicMock()
|
||||
monkeypatch.setattr(MEDIA_CONNECTOR_REGISTRY, "load", load_connector)
|
||||
messages = [{"role": "user", "content": "Who are you?"}]
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{"role": "user", "content": "Who are you?"}
|
||||
]
|
||||
|
||||
parse_chat_messages(
|
||||
messages,
|
||||
@@ -2457,7 +2460,7 @@ def test_parse_chat_messages_image_vision_chunk(
|
||||
kimi_k2_5_model_config,
|
||||
image_url,
|
||||
):
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2493,7 +2496,7 @@ def test_parse_chat_messages_video_vision_chunk(
|
||||
kimi_k2_5_model_config,
|
||||
video_url,
|
||||
):
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2530,7 +2533,7 @@ def test_parse_chat_messages_image_vision_chunk_with_uuid(
|
||||
image_url,
|
||||
):
|
||||
image_uuid = "image_123"
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2568,7 +2571,7 @@ def test_parse_chat_messages_video_vision_chunk_with_uuid(
|
||||
video_url,
|
||||
):
|
||||
video_uuid = "video_456"
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2606,7 +2609,7 @@ def test_parse_chat_messages_mixed_vision_chunk(
|
||||
image_url,
|
||||
video_url,
|
||||
):
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2655,7 +2658,7 @@ def test_parse_chat_messages_mixed_vision_chunk_with_uuid(
|
||||
):
|
||||
image_uuid = "image_123"
|
||||
video_uuid = "video_456"
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2707,7 +2710,7 @@ async def test_parse_chat_messages_mixed_vision_chunk_async(
|
||||
image_url,
|
||||
video_url,
|
||||
):
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2757,7 +2760,7 @@ async def test_parse_chat_messages_mixed_vision_chunk_with_uuid_async(
|
||||
):
|
||||
image_uuid = "image_123"
|
||||
video_uuid = "video_456"
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2808,7 +2811,7 @@ async def test_parse_chat_messages_image_vision_chunk_async(
|
||||
kimi_k2_5_model_config,
|
||||
image_url,
|
||||
):
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2845,7 +2848,7 @@ async def test_parse_chat_messages_video_vision_chunk_async(
|
||||
kimi_k2_5_model_config,
|
||||
video_url,
|
||||
):
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2883,7 +2886,7 @@ async def test_parse_chat_messages_image_vision_chunk_with_uuid_async(
|
||||
image_url,
|
||||
):
|
||||
image_uuid = "image_123"
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2922,7 +2925,7 @@ async def test_parse_chat_messages_video_vision_chunk_with_uuid_async(
|
||||
video_url,
|
||||
):
|
||||
video_uuid = "video_456"
|
||||
messages = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
@@ -2997,8 +3000,7 @@ async def test_resolve_items_runs_modalities_concurrently_and_preserves_order():
|
||||
finally:
|
||||
active_fetches -= 1
|
||||
|
||||
tracker = AsyncMultiModalItemTracker(MagicMock())
|
||||
tracker._model_config.is_multimodal_model = True
|
||||
tracker = AsyncMultiModalItemTracker(MagicMock(is_multimodal_model=True))
|
||||
tracker.__dict__["mm_processor"] = MagicMock()
|
||||
tracker._items_by_modality["video"] = [
|
||||
lambda: _fetch("video-0", 0.02),
|
||||
|
||||
@@ -37,7 +37,8 @@ from vllm.utils.flashinfer import (
|
||||
)
|
||||
from vllm.utils.import_utils import has_deep_gemm
|
||||
|
||||
if current_platform.get_device_capability() < (9, 0):
|
||||
capability = current_platform.get_device_capability()
|
||||
if capability is None or capability < (9, 0):
|
||||
pytest.skip("FP8 Triton requires CUDA 9.0 or higher", allow_module_level=True)
|
||||
|
||||
vllm_config = VllmConfig()
|
||||
@@ -258,7 +259,7 @@ def test_w8a8_block_fp8_torch_scaled_mm_matmul():
|
||||
stub = BlockWiseTorchFP8ScaledMMLinearKernel.__new__(
|
||||
BlockWiseTorchFP8ScaledMMLinearKernel
|
||||
)
|
||||
stub.config = types.SimpleNamespace(out_dtype=out_dtype)
|
||||
stub.config = types.SimpleNamespace(out_dtype=out_dtype) # type: ignore[assignment]
|
||||
out = stub.apply_block_scaled_mm(
|
||||
A_fp8_cuda.cuda(), B_fp8.cuda(), As_cuda.cuda(), Bs.cuda()
|
||||
)
|
||||
|
||||
@@ -62,7 +62,8 @@ PER_TOKEN_GROUP_SHAPE = (1, -1)
|
||||
PER_OUT_CH_GROUP_SHAPE = (-1, 1)
|
||||
|
||||
capability = current_platform.get_device_capability()
|
||||
capability = capability[0] * 10 + capability[1]
|
||||
# Fall back to 0 so import doesn't fail on unknown capability
|
||||
capability_int = (capability[0] * 10 + capability[1]) if capability is not None else 0
|
||||
|
||||
|
||||
def rand_int8(shape: tuple, device: str = "cuda"):
|
||||
@@ -639,7 +640,7 @@ def test_cutlass_cuda_graph(per_act_token: bool, per_out_ch: bool):
|
||||
|
||||
|
||||
def test_cutlass_support_opcheck():
|
||||
opcheck(torch.ops._C.cutlass_scaled_mm_supports_fp8, (capability,))
|
||||
opcheck(torch.ops._C.cutlass_scaled_mm_supports_fp8, (capability_int,))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("num_experts", [8, 64])
|
||||
|
||||
@@ -29,7 +29,8 @@ if not current_platform.is_cuda():
|
||||
# `is_quant_method_supported` conflates kernels with quantization methods
|
||||
# an assumption which is breaking down as quantizations methods can have
|
||||
# have kernels and some kernels support multiple quantization methods.
|
||||
IS_SUPPORTED_BY_GPU = current_platform.get_device_capability()[0] >= 9
|
||||
capability = current_platform.get_device_capability()
|
||||
IS_SUPPORTED_BY_GPU = capability is not None and capability[0] >= 9
|
||||
|
||||
MNK_SHAPES = [
|
||||
(1, 128, 128),
|
||||
@@ -207,7 +208,7 @@ def mm_test_helper(
|
||||
a=tensors.a,
|
||||
b_q=tensors.w_q,
|
||||
b_group_scales=tensors.w_g_s,
|
||||
b_group_size=group_size,
|
||||
b_group_size=group_size, # type: ignore[arg-type]
|
||||
b_channel_scales=tensors.w_ch_s,
|
||||
a_token_scales=tensors.w_tok_s,
|
||||
)
|
||||
|
||||
@@ -17,8 +17,9 @@ from vllm.platforms import current_platform
|
||||
from vllm.scalar_type import ScalarType, scalar_types
|
||||
from vllm.utils.torch_utils import set_random_seed
|
||||
|
||||
capability = current_platform.get_device_capability()
|
||||
IS_SUPPORTED_BY_GPU = (
|
||||
current_platform.is_cuda() and current_platform.get_device_capability()[0] >= 9
|
||||
current_platform.is_cuda() and capability is not None and capability[0] >= 9
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from tests.kernels.quant_utils import (
|
||||
)
|
||||
from tests.kernels.utils import opcheck
|
||||
from vllm.model_executor.layers.quantization.utils.quant_utils import (
|
||||
GroupShape,
|
||||
scaled_quantize,
|
||||
)
|
||||
from vllm.platforms import current_platform
|
||||
@@ -208,7 +209,10 @@ def test_static_fp8_quant_group_2d(
|
||||
|
||||
x = torch.rand(num_tokens, hidden_size, dtype=dtype, device="cuda")
|
||||
ref_out, scale = scaled_quantize(
|
||||
x, group_shape, current_platform.fp8_dtype(), compute_dtype=torch.float32
|
||||
x,
|
||||
GroupShape(*group_shape),
|
||||
current_platform.fp8_dtype(),
|
||||
compute_dtype=torch.float32,
|
||||
)
|
||||
ops_out, ops_scale = ops.scaled_fp8_quant(x, scale=scale, group_shape=group_shape)
|
||||
|
||||
@@ -236,7 +240,7 @@ def test_static_fp8_quant_1d_scale(
|
||||
|
||||
x = torch.rand(num_tokens, hidden_size, dtype=dtype, device="cuda")
|
||||
ref_out, scale_2d = scaled_quantize(
|
||||
x, group_shape, FP8_DTYPE, compute_dtype=torch.float32
|
||||
x, GroupShape(*group_shape), FP8_DTYPE, compute_dtype=torch.float32
|
||||
)
|
||||
|
||||
# Flatten scale to 1D for testing 1D scale path
|
||||
|
||||
@@ -38,7 +38,8 @@ CUDA_DEVICES = [
|
||||
# `is_quant_method_supported` conflates kernels with quantization methods
|
||||
# an assumption which is breaking down as quantizations methods can have
|
||||
# have kernels and some kernels support multiple quantization methods.
|
||||
IS_SUPPORTED_BY_GPU = current_platform.get_device_capability()[0] >= 9
|
||||
capability = current_platform.get_device_capability()
|
||||
IS_SUPPORTED_BY_GPU = capability is not None and capability[0] >= 9
|
||||
|
||||
MNK_SHAPES = [
|
||||
(1, 128, 128),
|
||||
@@ -305,7 +306,7 @@ def test_machete_all_schedules(shape, types: TypeConfig):
|
||||
if types.group_scale_type is None:
|
||||
group_sizes = [None]
|
||||
else:
|
||||
group_sizes = query_machete_supported_group_sizes(types.act_type)
|
||||
group_sizes = list(query_machete_supported_group_sizes(types.act_type))
|
||||
|
||||
for group_size in group_sizes:
|
||||
if not group_size_valid(shape, group_size):
|
||||
@@ -334,7 +335,7 @@ def test_machete_heuristic(shape, types: TypeConfig):
|
||||
if types.group_scale_type is None:
|
||||
group_sizes = [None]
|
||||
else:
|
||||
group_sizes = query_machete_supported_group_sizes(types.act_type)
|
||||
group_sizes = list(query_machete_supported_group_sizes(types.act_type))
|
||||
|
||||
for group_size in group_sizes:
|
||||
if not group_size_valid(shape, group_size):
|
||||
|
||||
@@ -342,7 +342,7 @@ def marlin_generate_valid_test_cases():
|
||||
[quant_test_config["b_type"]],
|
||||
quant_test_config.get("c_type", f16_types),
|
||||
quant_test_config["group_blocks"],
|
||||
)
|
||||
) # type: ignore[call-overload]
|
||||
|
||||
for sub_case in inner_combinations:
|
||||
if (
|
||||
|
||||
@@ -11,6 +11,7 @@ import pytest
|
||||
import torch
|
||||
|
||||
from vllm import _custom_ops as ops
|
||||
from vllm.model_executor.layers.linear import LinearBase
|
||||
from vllm.model_executor.layers.quantization.utils.marlin_utils import (
|
||||
GPTQ_MARLIN_TILE,
|
||||
apply_gptq_marlin_linear,
|
||||
@@ -524,13 +525,15 @@ def test_check_marlin_supports_layer_allow_tile_padding():
|
||||
)
|
||||
|
||||
# Tile-misaligned but group-aligned: rejected strictly, allowed w/ padding
|
||||
layer = _FakeLinear(4640, 512, input_size=2048)
|
||||
layer: LinearBase = _FakeLinear( # type: ignore[assignment]
|
||||
4640, 512, input_size=2048
|
||||
)
|
||||
assert not check_marlin_supports_layer(layer, 128)
|
||||
assert check_marlin_supports_layer(layer, 128, allow_tile_padding=True)
|
||||
assert check_marlin_supports_layer(layer, -1, allow_tile_padding=True)
|
||||
|
||||
# A group straddling the TP shard cannot be fixed by padding
|
||||
layer = _FakeLinear(4608, 4672, input_size=18688)
|
||||
layer = _FakeLinear(4608, 4672, input_size=18688) # type: ignore[assignment]
|
||||
assert not check_marlin_supports_layer(layer, 128, allow_tile_padding=True)
|
||||
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ def test_nvfp4_emulation_support_check_rejects_bias_and_lora(
|
||||
in_dtype=torch.bfloat16,
|
||||
device="cuda",
|
||||
routing_method=RoutingMethodType.TopK,
|
||||
**config_kwargs,
|
||||
**config_kwargs, # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
supported, reason = Nvfp4QuantizationEmulationTritonExperts.is_supported_config(
|
||||
|
||||
@@ -35,7 +35,7 @@ pytestmark = pytest.mark.cpu_test
|
||||
|
||||
|
||||
def test_auto_linear_backend_is_unchanged_without_overrides():
|
||||
kernels = [object]
|
||||
kernels: list[type] = [object]
|
||||
quantizations = (
|
||||
"fp8_block_w8a8",
|
||||
"fp8_w8a8",
|
||||
|
||||
@@ -17,6 +17,7 @@ import vllm.config as vllm_config_module
|
||||
from vllm.config import VllmConfig, set_current_vllm_config
|
||||
from vllm.model_executor.layers.fused_moe import utils as fused_moe_utils
|
||||
from vllm.model_executor.layers.fused_moe.layer import determine_expert_counts
|
||||
from vllm.model_executor.layers.quantization.base_config import QuantizationConfig
|
||||
from vllm.model_executor.layers.quantization.fp8 import Fp8Config
|
||||
from vllm.model_executor.layers.quantization.quark.quark import QuarkConfig
|
||||
from vllm.model_executor.layers.quantization.utils.config_utils import (
|
||||
@@ -140,10 +141,15 @@ def get_deepseek_v4_quark_config(exclude: list[str]) -> dict[str, Any]:
|
||||
return quantization_config
|
||||
|
||||
|
||||
def _stub_quant_config() -> QuantizationConfig:
|
||||
return cast(QuantizationConfig, object())
|
||||
|
||||
|
||||
def get_fse_test_model_config(
|
||||
model_type: str,
|
||||
quantization_config: dict[str, Any],
|
||||
) -> tuple[object, type[nn.Module]]:
|
||||
config: object
|
||||
if model_type == "minimax_m3":
|
||||
config = MiniMaxM3TextConfig(
|
||||
hidden_size=128,
|
||||
@@ -301,7 +307,7 @@ def test_resolve_layer_fused_shared_expert_skips_compatibility_when_disabled(
|
||||
)
|
||||
|
||||
assert not fused_moe_utils.resolve_layer_fused_shared_expert(
|
||||
object(), "model.layers.0.mlp"
|
||||
_stub_quant_config(), "model.layers.0.mlp"
|
||||
)
|
||||
|
||||
|
||||
@@ -316,7 +322,7 @@ def test_resolve_layer_fused_shared_expert_normalizes_unavailable_aiter(
|
||||
|
||||
assert (
|
||||
fused_moe_utils.resolve_layer_fused_shared_expert(
|
||||
object(), "model.layers.0.mlp"
|
||||
_stub_quant_config(), "model.layers.0.mlp"
|
||||
)
|
||||
is False
|
||||
)
|
||||
@@ -325,7 +331,7 @@ def test_resolve_layer_fused_shared_expert_normalizes_unavailable_aiter(
|
||||
def test_resolve_layer_fused_shared_expert_passes_module_prefixes(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
quant_config = object()
|
||||
quant_config = _stub_quant_config()
|
||||
monkeypatch.setattr(
|
||||
fused_moe_utils.rocm_aiter_ops,
|
||||
"is_fusion_moe_shared_experts_enabled",
|
||||
@@ -374,7 +380,7 @@ def test_resolve_layer_fused_shared_expert_rejects_incompatible_quantization(
|
||||
)
|
||||
|
||||
assert not fused_moe_utils.resolve_layer_fused_shared_expert(
|
||||
object(), "model.layers.0.mlp"
|
||||
_stub_quant_config(), "model.layers.0.mlp"
|
||||
)
|
||||
assert "shared experts are excluded" in caplog.text
|
||||
|
||||
@@ -407,7 +413,7 @@ def test_deepseek_v4_shared_expert_fse_uses_mtp_quantization_config_prefix(
|
||||
)
|
||||
|
||||
compatible, reason = is_shared_expert_quant_fse_compatible(
|
||||
DeepseekV4Config(),
|
||||
DeepseekV4Config(), # type: ignore[arg-type]
|
||||
"model.layers.2.ffn.experts",
|
||||
"model.layers.2.ffn.shared_experts",
|
||||
)
|
||||
@@ -818,7 +824,7 @@ def test_models_fse_init(
|
||||
model_type, quantization_config
|
||||
)
|
||||
vllm_config = VllmConfig()
|
||||
vllm_config.model_config = SimpleNamespace(
|
||||
vllm_config.model_config = SimpleNamespace( # type: ignore[assignment]
|
||||
hf_config=config,
|
||||
hf_text_config=config,
|
||||
dtype=torch.bfloat16,
|
||||
@@ -887,7 +893,7 @@ def test_models_fse_init(
|
||||
DeepSeekV4MTP,
|
||||
)
|
||||
|
||||
vllm_config.speculative_config = SimpleNamespace(
|
||||
vllm_config.speculative_config = SimpleNamespace( # type: ignore[assignment]
|
||||
draft_model_config=SimpleNamespace(hf_config=config),
|
||||
method="mtp",
|
||||
parallel_drafting=False,
|
||||
@@ -1214,7 +1220,7 @@ def test_quark_packed_layer_config_must_match_global_config() -> None:
|
||||
|
||||
def test_non_quark_shared_expert_fse_is_incompatible() -> None:
|
||||
compatible, reason = is_shared_expert_quant_fse_compatible(
|
||||
object(),
|
||||
_stub_quant_config(),
|
||||
"model.layers.0.mlp.experts",
|
||||
"model.layers.0.mlp.shared_experts",
|
||||
)
|
||||
|
||||
@@ -46,7 +46,7 @@ def test_sparse_attention_refreshes_batch_state_inside_eager_segment(
|
||||
|
||||
with pytest.raises(BatchStateRefreshed):
|
||||
DeepseekV32Attention._sparse_indexer_and_attn(
|
||||
layer,
|
||||
layer, # type: ignore[arg-type]
|
||||
torch.empty(1, dtype=torch.long),
|
||||
torch.empty(1, 1),
|
||||
torch.empty(1, 1, 1),
|
||||
@@ -80,7 +80,7 @@ def make_indexer_metadata(
|
||||
num_decode_tokens=num_decode_tokens,
|
||||
num_prefills=num_prefills,
|
||||
num_prefill_tokens=num_prefill_tokens,
|
||||
prefill=SimpleNamespace(chunks=[]) if num_prefills else None,
|
||||
prefill=SimpleNamespace(chunks=[]) if num_prefills else None, # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ def test_short_prefill_updates_k_cache_before_scoring_decision(
|
||||
slot_mapping=slot_mapping,
|
||||
)
|
||||
if indexer_metadata.num_decodes:
|
||||
indexer_metadata.decode = object()
|
||||
indexer_metadata.decode = object() # type: ignore[assignment]
|
||||
mla_metadata = make_mla_metadata(
|
||||
use_dense_mha=batch_kind != "force_mqa",
|
||||
num_decode_tokens=mla_num_decode_tokens,
|
||||
@@ -307,7 +307,7 @@ def test_deepseek_v32_dispatches_selected_mha(
|
||||
output = torch.empty(2, 2)
|
||||
|
||||
DeepseekV32Attention._sparse_indexer_and_attn(
|
||||
layer,
|
||||
layer, # type: ignore[arg-type]
|
||||
torch.arange(2),
|
||||
torch.empty(2, 2),
|
||||
q_nope,
|
||||
|
||||
@@ -224,11 +224,11 @@ class TestResolveClassifierActFn:
|
||||
model_config = SimpleNamespace(
|
||||
hf_config=SimpleNamespace(num_labels=3, problem_type="")
|
||||
)
|
||||
result = resolve_classifier_act_fn(model_config, act_fn=None)
|
||||
result = resolve_classifier_act_fn(model_config, act_fn=None) # type: ignore[arg-type]
|
||||
assert isinstance(result, PoolerClassify)
|
||||
assert result.num_labels == 3
|
||||
|
||||
def test_passes_through_provided_act_fn(self):
|
||||
custom = PoolerIdentity()
|
||||
result = resolve_classifier_act_fn(None, act_fn=custom)
|
||||
result = resolve_classifier_act_fn(None, act_fn=custom) # type: ignore[arg-type]
|
||||
assert result is custom
|
||||
@@ -15,6 +15,7 @@ from vllm.model_executor.layers.pooler.tokwise.heads import (
|
||||
TokenEmbeddingPoolerHead,
|
||||
)
|
||||
from vllm.pooling_params import PoolingParams
|
||||
from vllm.tasks import PoolingTask
|
||||
from vllm.v1.pool.metadata import PoolingMetadata, PoolingStates
|
||||
|
||||
_HIDDEN = 16
|
||||
@@ -24,7 +25,7 @@ _BATCH = 3
|
||||
def _make_params(
|
||||
n: int,
|
||||
*,
|
||||
task: str = "embed",
|
||||
task: PoolingTask = "embed",
|
||||
dimensions: int | None = None,
|
||||
use_activation: bool | None = None,
|
||||
) -> list[PoolingParams]:
|
||||
@@ -320,6 +321,7 @@ class TestTokenEmbeddingPoolerHead:
|
||||
x = torch.randn(5, _HIDDEN)
|
||||
param = PoolingParams(task="token_embed")
|
||||
out = head.forward_chunk(x, param)
|
||||
assert out is not None
|
||||
assert out.dtype == torch.float16
|
||||
|
||||
def test_projector(self):
|
||||
@@ -328,6 +330,7 @@ class TestTokenEmbeddingPoolerHead:
|
||||
x = torch.randn(5, _HIDDEN)
|
||||
param = PoolingParams(task="token_embed")
|
||||
out = head.forward_chunk(x, param)
|
||||
assert out is not None
|
||||
assert out.shape == (5, 8)
|
||||
assert torch.allclose(out, proj(x))
|
||||
|
||||
@@ -336,6 +339,7 @@ class TestTokenEmbeddingPoolerHead:
|
||||
x = torch.randn(5, _HIDDEN)
|
||||
param = PoolingParams(task="token_embed", dimensions=4)
|
||||
out = head.forward_chunk(x, param)
|
||||
assert out is not None
|
||||
assert out.shape == (5, 4)
|
||||
assert torch.equal(out, x[..., :4])
|
||||
|
||||
@@ -360,6 +364,7 @@ class TestTokenEmbeddingPoolerHead:
|
||||
x = torch.randn(5, _HIDDEN)
|
||||
param = PoolingParams(task="token_embed", dimensions=4)
|
||||
out = head.forward_chunk(x, param)
|
||||
assert out is not None
|
||||
assert out.shape == (5, 4)
|
||||
assert torch.equal(out, proj(x)[..., :4])
|
||||
|
||||
@@ -368,6 +373,7 @@ class TestTokenEmbeddingPoolerHead:
|
||||
x = torch.randn(5, _HIDDEN)
|
||||
param = PoolingParams(task="token_embed", dimensions=4, use_activation=True)
|
||||
out = head.forward_chunk(x, param)
|
||||
assert out is not None
|
||||
assert out.shape == (5, 4)
|
||||
norms = torch.linalg.norm(out, dim=-1)
|
||||
assert torch.allclose(norms, torch.ones(5), atol=1e-5)
|
||||
@@ -416,6 +422,7 @@ class TestTokenClassifierPoolerHead:
|
||||
x = torch.randn(5, _HIDDEN)
|
||||
param = PoolingParams(task="token_classify")
|
||||
out = head.forward_chunk(x, param)
|
||||
assert out is not None
|
||||
assert out.dtype == torch.float16
|
||||
|
||||
def test_classifier(self):
|
||||
@@ -424,6 +431,7 @@ class TestTokenClassifierPoolerHead:
|
||||
x = torch.randn(5, _HIDDEN)
|
||||
param = PoolingParams(task="token_classify")
|
||||
out = head.forward_chunk(x, param)
|
||||
assert out is not None
|
||||
assert out.shape == (5, 3)
|
||||
assert torch.allclose(out, clf(x))
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ from vllm.model_executor.layers.pooler.tokwise.methods import (
|
||||
get_tok_pooling_method,
|
||||
)
|
||||
from vllm.pooling_params import PoolingParams
|
||||
from vllm.tasks import PoolingTask
|
||||
from vllm.v1.pool.metadata import PoolingCursor, PoolingMetadata, PoolingStates
|
||||
|
||||
_CPU = torch.device("cpu")
|
||||
@@ -66,7 +67,7 @@ def _make_pooling_cursor(
|
||||
def _make_metadata(
|
||||
prompt_lens: list[int],
|
||||
*,
|
||||
tasks: list[str] | None = None,
|
||||
tasks: list[PoolingTask] | None = None,
|
||||
token_ids: list[list[int]] | None = None,
|
||||
pooling_params: list[PoolingParams] | None = None,
|
||||
num_scheduled_tokens: list[int] | None = None,
|
||||
@@ -319,7 +320,7 @@ def test_dispatch_seq_cls_honors_token_pooling_type(tok_pooling_type):
|
||||
),
|
||||
)
|
||||
classifier = torch.nn.Linear(4, 3)
|
||||
with set_current_vllm_config(config):
|
||||
with set_current_vllm_config(config): # type: ignore[arg-type]
|
||||
pooler = DispatchPooler.for_seq_cls(pooler_config, classifier=classifier)
|
||||
|
||||
token_ids = [[2, 99, 3, 99], [4, 99], [5, 6]]
|
||||
|
||||
@@ -114,7 +114,8 @@ async def test_bge_m3_sparse_plugin_online(
|
||||
response = ret.json()
|
||||
|
||||
# Verify the request response is in the correct format
|
||||
assert (parsed_response := IOProcessorResponse(**response).data)
|
||||
parsed_response: object = IOProcessorResponse(**response).data
|
||||
assert parsed_response
|
||||
|
||||
# Verify the output is formatted as expected for this plugin
|
||||
assert _get_attr_or_val(parsed_response, "data")
|
||||
|
||||
@@ -79,7 +79,7 @@ def _post_pooling(server: RemoteOpenAIServer, data: dict):
|
||||
ret = requests.post(server.url_for("pooling"), json=request_payload)
|
||||
ret.raise_for_status()
|
||||
response = ret.json()
|
||||
parsed_response = IOProcessorResponse(**response).data
|
||||
parsed_response: object = IOProcessorResponse(**response).data
|
||||
assert parsed_response
|
||||
return parsed_response
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ async def test_init_state_is_noop_without_phase_a(monkeypatch: pytest.MonkeyPatc
|
||||
monkeypatch.setenv("VLLM_PLUGINS", "dummy_admin_endpoint_plugin")
|
||||
|
||||
state = State()
|
||||
await init_endpoint_plugins_state(_FakeEngineClient(), state, _build_args())
|
||||
await init_endpoint_plugins_state(_FakeEngineClient(), state, _build_args()) # type: ignore[arg-type]
|
||||
|
||||
assert not hasattr(state, "dummy_engine_client")
|
||||
|
||||
@@ -223,7 +223,7 @@ async def test_endpoint_plugin_end_to_end(monkeypatch: pytest.MonkeyPatch):
|
||||
)
|
||||
|
||||
fake_engine_client = _FakeEngineClient(rpc_result=["cfg-a", "cfg-b"])
|
||||
await init_endpoint_plugins_state(fake_engine_client, app.state, args)
|
||||
await init_endpoint_plugins_state(fake_engine_client, app.state, args) # type: ignore[arg-type]
|
||||
|
||||
assert app.state.dummy_engine_client is fake_engine_client
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ def test_oot_registration_multimodal(
|
||||
)
|
||||
|
||||
first_token = llm.get_tokenizer().decode(0)
|
||||
outputs = llm.generate(prompts, sampling_params)
|
||||
outputs = llm.generate(prompts, sampling_params) # type: ignore[arg-type]
|
||||
|
||||
for output in outputs:
|
||||
generated_text = output.outputs[0].text
|
||||
|
||||
@@ -23,7 +23,8 @@ def test_stat_logger_plugin_is_discovered(monkeypatch: pytest.MonkeyPatch):
|
||||
# instantiate and confirm the right type
|
||||
vllm_config = VllmConfig()
|
||||
instance = factories[0](vllm_config)
|
||||
assert isinstance(instance, DummyStatLogger)
|
||||
# The `is` check above narrows DummyStatLogger to a Callable
|
||||
assert isinstance(instance, DummyStatLogger) # type: ignore[arg-type]
|
||||
|
||||
|
||||
def test_no_plugins_loaded_if_env_empty(monkeypatch: pytest.MonkeyPatch):
|
||||
@@ -66,10 +67,11 @@ async def test_stat_logger_plugin_integration_with_engine(
|
||||
|
||||
engine = AsyncLLM.from_engine_args(engine_args=engine_args)
|
||||
|
||||
assert engine.logger_manager is not None
|
||||
assert len(engine.logger_manager.stat_loggers) == 2
|
||||
assert len(engine.logger_manager.stat_loggers[0].per_engine_stat_loggers) == 1
|
||||
assert len(engine.logger_manager.stat_loggers[0].per_engine_stat_loggers) == 1 # type: ignore[attr-defined]
|
||||
assert isinstance(
|
||||
engine.logger_manager.stat_loggers[0].per_engine_stat_loggers[0],
|
||||
engine.logger_manager.stat_loggers[0].per_engine_stat_loggers[0], # type: ignore[attr-defined]
|
||||
DummyStatLogger,
|
||||
)
|
||||
|
||||
|
||||
@@ -95,7 +95,8 @@ async def test_prithvi_mae_plugin_online(
|
||||
response = ret.json()
|
||||
|
||||
# verify the request response is in the correct format
|
||||
assert (parsed_response := IOProcessorResponse(**response))
|
||||
parsed_response: IOProcessorResponse = IOProcessorResponse(**response)
|
||||
assert parsed_response
|
||||
|
||||
# verify the output is formatted as expected for this plugin
|
||||
plugin_data = parsed_response.data
|
||||
|
||||
@@ -16,6 +16,7 @@ from transformers import AutoModelForSeq2SeqLM
|
||||
from vllm import CompletionOutput, RequestOutput
|
||||
from vllm.assets.audio import AudioAsset
|
||||
from vllm.entrypoints.llm import LLM
|
||||
from vllm.inputs import TokensInput
|
||||
from vllm.logprobs import Logprob, SampleLogprobs
|
||||
from vllm.platforms import current_platform
|
||||
from vllm.sampling_params import BeamSearchParams, StructuredOutputsParams
|
||||
@@ -107,11 +108,12 @@ def test_beam_search_abort_returns_partial_outputs_and_continues_other_prompts(
|
||||
llm.renderer = Mock(get_tokenizer=Mock(return_value=tokenizer))
|
||||
monkeypatch.setattr(llm, "_preprocess_cmpl", lambda prompts: prompts)
|
||||
monkeypatch.setattr(llm, "_render_and_run_requests", run_requests)
|
||||
prompts = [
|
||||
# Engine inputs, since _preprocess_cmpl is patched to the identity
|
||||
prompts: list[TokensInput] = [
|
||||
{"type": "token", "prompt_token_ids": [token]} for token in [prompt_token, 2]
|
||||
]
|
||||
params = BeamSearchParams(beam_width=2, max_tokens=3)
|
||||
outputs = llm.beam_search(prompts, params)
|
||||
outputs = llm.beam_search(prompts, params) # type: ignore[arg-type]
|
||||
|
||||
aborted, normal = outputs
|
||||
expected_tokens = (
|
||||
@@ -324,7 +326,7 @@ def test_beam_search_structured_output(
|
||||
|
||||
llm = LLM(
|
||||
model=model,
|
||||
dtype=dtype,
|
||||
dtype=dtype, # type: ignore[arg-type]
|
||||
max_model_len=512,
|
||||
structured_outputs_config=dict(
|
||||
backend="xgrammar",
|
||||
@@ -343,7 +345,7 @@ def test_beam_search_structured_output(
|
||||
"Generate a JSON object for a person with name and age:",
|
||||
]
|
||||
|
||||
outputs = llm.beam_search(prompts, params)
|
||||
outputs = llm.beam_search(prompts, params) # type: ignore[arg-type]
|
||||
|
||||
assert len(outputs) == len(prompts)
|
||||
for output in outputs:
|
||||
|
||||
@@ -5,6 +5,7 @@ import pytest
|
||||
|
||||
from vllm import CompletionOutput, RequestOutput
|
||||
from vllm.entrypoints.generate.beam_search.online import BeamSearchOnlineMixin
|
||||
from vllm.inputs import TokensInput
|
||||
from vllm.logprobs import Logprob, SampleLogprobs
|
||||
from vllm.sampling_params import BeamSearchParams
|
||||
|
||||
@@ -56,13 +57,13 @@ class _EngineClient:
|
||||
|
||||
|
||||
class _Serving(BeamSearchOnlineMixin):
|
||||
renderer = _Renderer()
|
||||
engine_client = _EngineClient()
|
||||
renderer = _Renderer() # type: ignore[assignment]
|
||||
engine_client = _EngineClient() # type: ignore[assignment]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_beam_search_handles_extra_logprob_candidates() -> None:
|
||||
prompt = {
|
||||
prompt: TokensInput = {
|
||||
"type": "token",
|
||||
"prompt": "prompt",
|
||||
"prompt_token_ids": [1],
|
||||
@@ -90,7 +91,7 @@ async def test_beam_search_handles_extra_logprob_candidates() -> None:
|
||||
async def test_beam_search_respects_skip_special_tokens(
|
||||
skip_special_tokens: bool, expected_text: str
|
||||
) -> None:
|
||||
prompt = {
|
||||
prompt: TokensInput = {
|
||||
"type": "token",
|
||||
"prompt": "prompt",
|
||||
"prompt_token_ids": [1],
|
||||
@@ -140,7 +141,11 @@ async def test_beam_search_abort_returns_partial_outputs(
|
||||
|
||||
serving = _Serving()
|
||||
monkeypatch.setattr(serving.engine_client, "generate", generate)
|
||||
prompt = {"type": "token", "prompt": "prompt", "prompt_token_ids": [prompt_token]}
|
||||
prompt: TokensInput = {
|
||||
"type": "token",
|
||||
"prompt": "prompt",
|
||||
"prompt_token_ids": [prompt_token],
|
||||
}
|
||||
outputs = [
|
||||
output
|
||||
async for output in serving.beam_search(
|
||||
|
||||
@@ -8,11 +8,12 @@ Run `pytest tests/samplers/test_no_bad_words.py`.
|
||||
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
from vllm import LLM, SamplingParams
|
||||
from tests.conftest import VllmRunner
|
||||
from vllm import SamplingParams
|
||||
|
||||
|
||||
def _generate(
|
||||
llm: LLM,
|
||||
llm: VllmRunner,
|
||||
prompt: str,
|
||||
num_prompt_tokens: int,
|
||||
temperature: float = 0,
|
||||
@@ -56,7 +57,9 @@ class TestOneTokenBadWord:
|
||||
output_token_ids = self._generate(llm, bad_words=[self.TARGET_TOKEN])
|
||||
assert self.target_token_id not in output_token_ids
|
||||
|
||||
def _generate(self, llm: LLM, bad_words: list[str] | None = None) -> list[int]:
|
||||
def _generate(
|
||||
self, llm: VllmRunner, bad_words: list[str] | None = None
|
||||
) -> list[int]:
|
||||
return _generate(
|
||||
llm=llm,
|
||||
prompt=self.PROMPT,
|
||||
@@ -151,7 +154,9 @@ class TestTwoTokenBadWord:
|
||||
self.neighbour_token_id2 in output_token_ids
|
||||
)
|
||||
|
||||
def _generate(self, llm: LLM, bad_words: list[str] | None = None) -> list[int]:
|
||||
def _generate(
|
||||
self, llm: VllmRunner, bad_words: list[str] | None = None
|
||||
) -> list[int]:
|
||||
return _generate(
|
||||
llm=llm,
|
||||
prompt=self.PROMPT,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
|
||||
from collections.abc import Generator
|
||||
from typing import Any
|
||||
from typing import Any, cast
|
||||
|
||||
import pytest
|
||||
from transformers import AutoTokenizer, PythonBackend, TokenizersBackend
|
||||
@@ -10,6 +10,7 @@ from transformers import AutoTokenizer, PythonBackend, TokenizersBackend
|
||||
from vllm.sampling_params import SamplingParams
|
||||
from vllm.tokenizers.detokenizer_utils import convert_ids_list_to_tokens
|
||||
from vllm.tokenizers.mistral import MistralTokenizer
|
||||
from vllm.tokenizers.protocol import TokenizerLike
|
||||
from vllm.v1.engine import EngineCoreRequest
|
||||
from vllm.v1.engine.detokenizer import (
|
||||
FastIncrementalDetokenizer,
|
||||
@@ -281,9 +282,26 @@ class _MockTokenizer:
|
||||
return "".join(self._decoded[tid] for tid in ids)
|
||||
|
||||
|
||||
def _mock_tokenizer(
|
||||
raw_tokens: dict[int, str],
|
||||
decoded_tokens: dict[int, str],
|
||||
pre_tokenizer_type: str = "Metaspace",
|
||||
replacement: str | None = "▁",
|
||||
) -> TokenizerLike:
|
||||
return cast(
|
||||
TokenizerLike,
|
||||
_MockTokenizer(
|
||||
raw_tokens=raw_tokens,
|
||||
decoded_tokens=decoded_tokens,
|
||||
pre_tokenizer_type=pre_tokenizer_type,
|
||||
replacement=replacement,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_sentencepiece_leading_space_preserved():
|
||||
"""▁true and true must produce distinct strings."""
|
||||
tok = _MockTokenizer(
|
||||
tok = _mock_tokenizer(
|
||||
raw_tokens={0: "▁true", 1: "true", 2: "▁false", 3: "false"},
|
||||
decoded_tokens={0: "true", 1: "true", 2: "false", 3: "false"},
|
||||
)
|
||||
@@ -297,7 +315,7 @@ def test_sentencepiece_leading_space_preserved():
|
||||
|
||||
def test_whitespace_run_tokens_stay_distinct():
|
||||
"""▁, ▁▁, ▁▁▁ must produce different-length space strings."""
|
||||
tok = _MockTokenizer(
|
||||
tok = _mock_tokenizer(
|
||||
raw_tokens={0: "▁", 1: "▁▁", 2: "▁▁▁"},
|
||||
decoded_tokens={0: "", 1: " ", 2: " "},
|
||||
)
|
||||
@@ -307,7 +325,7 @@ def test_whitespace_run_tokens_stay_distinct():
|
||||
|
||||
def test_bpe_leading_space_already_preserved():
|
||||
"""GPT-2 BPE: Ġtrue already decodes to ' true', no fix needed."""
|
||||
tok = _MockTokenizer(
|
||||
tok = _mock_tokenizer(
|
||||
raw_tokens={0: "Ġtrue", 1: "true"},
|
||||
decoded_tokens={0: " true", 1: "true"},
|
||||
pre_tokenizer_type="ByteLevel",
|
||||
@@ -319,7 +337,7 @@ def test_bpe_leading_space_already_preserved():
|
||||
|
||||
def test_logprobs_count_stable_across_k():
|
||||
"""logprobs=4 and logprobs=10 must return 4 and 10 entries."""
|
||||
tok = _MockTokenizer(
|
||||
tok = _mock_tokenizer(
|
||||
raw_tokens={
|
||||
0: "▁true",
|
||||
1: "a",
|
||||
|
||||
@@ -61,7 +61,7 @@ def test_thread_pool_tokenizer_pickle(model_id: str):
|
||||
unpickled_tokenizer = pickle.loads(pickle.dumps(pooled_tokenizer))
|
||||
assert unpickled_tokenizer is not None
|
||||
assert isinstance(unpickled_tokenizer, ThreadSafeHFTokenizerMixin)
|
||||
assert unpickled_tokenizer.encode("prompt") == reference_tokenizer.encode("prompt")
|
||||
assert unpickled_tokenizer.encode("prompt") == reference_tokenizer.encode("prompt") # type: ignore[attr-defined]
|
||||
|
||||
# Idempotence: wrapping an already-pooled tokenizer returns it unchanged.
|
||||
assert maybe_make_thread_pool(pooled_tokenizer) is pooled_tokenizer
|
||||
assert maybe_make_thread_pool(pooled_tokenizer) is pooled_tokenizer # type: ignore[type-var]
|
||||
@@ -10,6 +10,7 @@ from mistral_common.exceptions import InvalidMessageStructureException
|
||||
from mistral_common.guidance.grammar_factory import GrammarFactory
|
||||
from mistral_common.tokens.tokenizers.base import SpecialTokenPolicy, SpecialTokens
|
||||
|
||||
from vllm.entrypoints.chat_utils import ChatCompletionMessageParam
|
||||
from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest
|
||||
from vllm.exceptions import VLLMValidationError
|
||||
from vllm.tokenizers.mistral import (
|
||||
@@ -21,7 +22,9 @@ from vllm.tokenizers.mistral import (
|
||||
|
||||
def test_validate_apply_chat_template_args():
|
||||
# add_generation_prompt with assistant last message → error
|
||||
messages = [{"role": "assistant", "content": "Hello"}]
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{"role": "assistant", "content": "Hello"}
|
||||
]
|
||||
with pytest.raises(ValueError):
|
||||
_validate_apply_chat_template_args(messages, add_generation_prompt=True)
|
||||
|
||||
@@ -32,7 +35,9 @@ def test_validate_apply_chat_template_args():
|
||||
# both add_generation_prompt and continue_final_message → error
|
||||
with pytest.raises(ValueError):
|
||||
_validate_apply_chat_template_args(
|
||||
messages, add_generation_prompt=True, continue_final_message=True
|
||||
messages,
|
||||
add_generation_prompt=True,
|
||||
continue_final_message=True,
|
||||
)
|
||||
|
||||
# continue_final_message with assistant last message → ok
|
||||
@@ -835,7 +840,9 @@ class TestMistralTokenizer:
|
||||
)
|
||||
|
||||
def test_apply_chat_template_error(self, mistral_tokenizer: MistralTokenizer):
|
||||
messages = [{"role": "user", "content": "Hello world !"}]
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{"role": "user", "content": "Hello world !"}
|
||||
]
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
mistral_tokenizer.apply_chat_template(
|
||||
@@ -968,7 +975,7 @@ class TestMistralTokenizer:
|
||||
mistral_tokenizer: MistralTokenizer,
|
||||
):
|
||||
assert mistral_tokenizer.batch_decode(
|
||||
[[]],
|
||||
[[]], # type: ignore[arg-type]
|
||||
) == [""]
|
||||
|
||||
def test_convert_tokens_to_string(self, mistral_tokenizer: MistralTokenizer):
|
||||
@@ -2167,13 +2174,15 @@ class TestMistralTokenizer:
|
||||
def test_apply_chat_template_tool_optional_fields(
|
||||
self,
|
||||
mistral_tokenizer: MistralTokenizer,
|
||||
messages: list[dict[str, Any]],
|
||||
messages: list[ChatCompletionMessageParam],
|
||||
tools: list[dict[str, Any]],
|
||||
tekken_expected_substrings: list[str],
|
||||
spm_expected_substrings: list[str],
|
||||
) -> None:
|
||||
output = mistral_tokenizer.apply_chat_template(
|
||||
messages, tools=tools, add_generation_prompt=True
|
||||
messages,
|
||||
tools=tools,
|
||||
add_generation_prompt=True,
|
||||
)
|
||||
decoded = mistral_tokenizer.tokenizer.decode(output, SpecialTokenPolicy.KEEP)
|
||||
|
||||
@@ -2188,7 +2197,7 @@ class TestMistralTokenizer:
|
||||
def test_apply_chat_template_tools_not_mutated(
|
||||
self, mistral_tokenizer: MistralTokenizer
|
||||
) -> None:
|
||||
messages: list[dict[str, Any]] = [
|
||||
messages: list[ChatCompletionMessageParam] = [
|
||||
{"role": "user", "content": "Hello"},
|
||||
]
|
||||
tools: list[dict[str, Any]] = [
|
||||
@@ -2209,7 +2218,9 @@ class TestMistralTokenizer:
|
||||
original_tools = copy.deepcopy(tools)
|
||||
|
||||
mistral_tokenizer.apply_chat_template(
|
||||
messages, tools=tools, add_generation_prompt=True
|
||||
messages,
|
||||
tools=tools,
|
||||
add_generation_prompt=True,
|
||||
)
|
||||
|
||||
assert tools == original_tools
|
||||
@@ -2235,7 +2246,8 @@ class TestMistralTokenizer:
|
||||
]
|
||||
|
||||
output = mistral_tokenizer.apply_chat_template(
|
||||
messages, add_generation_prompt=True
|
||||
messages, # type: ignore[arg-type]
|
||||
add_generation_prompt=True,
|
||||
)
|
||||
decoded = mistral_tokenizer.tokenizer.decode(output, SpecialTokenPolicy.KEEP)
|
||||
|
||||
@@ -2310,6 +2322,7 @@ def v15_mistral_tokenizer() -> MistralTokenizer:
|
||||
return MistralTokenizer.from_pretrained("mistralai/Mistral-Small-4-119B-2603")
|
||||
except Exception:
|
||||
pytest.skip("v15 tokenizer unavailable")
|
||||
raise AssertionError("unreachable")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
@@ -2319,6 +2332,7 @@ def v13_mistral_tokenizer() -> MistralTokenizer:
|
||||
return MistralTokenizer.from_pretrained("mistralai/Magistral-Small-2509")
|
||||
except Exception:
|
||||
pytest.skip("v13 tokenizer unavailable")
|
||||
raise AssertionError("unreachable")
|
||||
|
||||
|
||||
def test_v15_apply_chat_template_passes_reasoning_effort_high(
|
||||
@@ -2338,7 +2352,7 @@ def test_v15_apply_chat_template_passes_reasoning_effort_high(
|
||||
)
|
||||
|
||||
v15_mistral_tokenizer.apply_chat_template(
|
||||
messages=_PASSTHROUGH_MESSAGES,
|
||||
messages=_PASSTHROUGH_MESSAGES, # type: ignore[arg-type]
|
||||
reasoning_effort="high",
|
||||
)
|
||||
|
||||
@@ -2361,7 +2375,7 @@ def test_v15_apply_chat_template_passes_reasoning_effort_none_by_default(
|
||||
fake_apply_chat_template,
|
||||
)
|
||||
|
||||
v15_mistral_tokenizer.apply_chat_template(messages=_PASSTHROUGH_MESSAGES)
|
||||
v15_mistral_tokenizer.apply_chat_template(messages=_PASSTHROUGH_MESSAGES) # type: ignore[arg-type]
|
||||
|
||||
assert "reasoning_effort" in captured_kwargs[-1]
|
||||
assert captured_kwargs[-1]["reasoning_effort"] is None
|
||||
@@ -2384,7 +2398,7 @@ def test_pre_v15_apply_chat_template_omits_reasoning_effort(
|
||||
)
|
||||
|
||||
v13_mistral_tokenizer.apply_chat_template(
|
||||
messages=_PASSTHROUGH_MESSAGES,
|
||||
messages=_PASSTHROUGH_MESSAGES, # type: ignore[arg-type]
|
||||
reasoning_effort="high",
|
||||
)
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ def test_cached_tokenizer_from_config_registers_local_config(tmp_path: Path):
|
||||
side_effect=lambda tokenizer: tokenizer,
|
||||
),
|
||||
):
|
||||
tokenizer = cached_tokenizer_from_config(model_config)
|
||||
tokenizer = cached_tokenizer_from_config(model_config) # type: ignore[arg-type]
|
||||
|
||||
assert tokenizer.is_fast is True
|
||||
finally:
|
||||
|
||||
@@ -148,7 +148,7 @@ def test_tool_parser_adjust_request_builds_valid_response_text_config() -> None:
|
||||
description string that the previous two-step construction injected.
|
||||
"""
|
||||
parser = ToolParser.__new__(ToolParser)
|
||||
parser.model_tokenizer = None
|
||||
parser.model_tokenizer = None # type: ignore[assignment]
|
||||
|
||||
request = _build_responses_request(tool_choice="required")
|
||||
ToolParser.adjust_request(parser, request)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
|
||||
import json
|
||||
from typing import cast
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -15,6 +16,7 @@ from vllm.exceptions import VLLMValidationError
|
||||
from vllm.parser.kimi_k3 import KimiK3Parser
|
||||
from vllm.parser.parser_manager import ParserManager
|
||||
from vllm.reasoning.kimi_k3_reasoning_parser import KimiK3ReasoningParser
|
||||
from vllm.tokenizers.protocol import TokenizerLike
|
||||
from vllm.tool_parsers.kimi_k3_tool_parser import KimiK3ToolParser
|
||||
|
||||
OPEN = "<|open|>"
|
||||
@@ -37,6 +39,10 @@ class DummyTokenizer:
|
||||
return [ord(ch) for ch in text]
|
||||
|
||||
|
||||
def _dummy_tokenizer() -> TokenizerLike:
|
||||
return cast(TokenizerLike, DummyTokenizer())
|
||||
|
||||
|
||||
class KimiK3DelegatingParser(KimiK3Parser):
|
||||
reasoning_parser_cls = KimiK3ReasoningParser
|
||||
tool_parser_cls = KimiK3ToolParser
|
||||
@@ -124,7 +130,7 @@ def _tools(*calls: str) -> str:
|
||||
|
||||
|
||||
def test_extract_tool_calls_with_response_and_typed_arguments():
|
||||
parser = KimiK3ToolParser(DummyTokenizer())
|
||||
parser = KimiK3ToolParser(_dummy_tokenizer())
|
||||
|
||||
output = _response("answer") + _tools(
|
||||
_call(
|
||||
@@ -150,7 +156,7 @@ def test_extract_tool_calls_with_response_and_typed_arguments():
|
||||
|
||||
|
||||
def test_delegating_parser_preserves_tool_calls_after_reasoning():
|
||||
parser = KimiK3DelegatingParser(DummyTokenizer())
|
||||
parser = KimiK3DelegatingParser(_dummy_tokenizer())
|
||||
output = (
|
||||
f"{THINK_OPEN}step{THINK_CLOSE}"
|
||||
+ _response("answer")
|
||||
@@ -172,7 +178,7 @@ def test_delegating_parser_preserves_tool_calls_after_reasoning():
|
||||
|
||||
|
||||
def test_delegating_parser_required_tool_choice_uses_xtml_parser():
|
||||
parser = KimiK3DelegatingParser(DummyTokenizer())
|
||||
parser = KimiK3DelegatingParser(_dummy_tokenizer())
|
||||
request = _request().model_copy(update={"tool_choice": "required"})
|
||||
output = (
|
||||
f"{THINK_OPEN}step{THINK_CLOSE}"
|
||||
@@ -195,7 +201,7 @@ def test_delegating_parser_required_tool_choice_uses_xtml_parser():
|
||||
|
||||
|
||||
def test_delegating_parser_named_tool_choice_uses_xtml_parser():
|
||||
parser = KimiK3DelegatingParser(DummyTokenizer())
|
||||
parser = KimiK3DelegatingParser(_dummy_tokenizer())
|
||||
output = (
|
||||
f"{THINK_OPEN}step{THINK_CLOSE}"
|
||||
+ _response("")
|
||||
@@ -218,7 +224,7 @@ def test_delegating_parser_named_tool_choice_uses_xtml_parser():
|
||||
|
||||
def test_delegating_parser_auto_no_call_strips_consumed_response_prefix():
|
||||
parser = KimiK3DelegatingParser(
|
||||
DummyTokenizer(), chat_template_kwargs={"thinking": False}
|
||||
_dummy_tokenizer(), chat_template_kwargs={"thinking": False}
|
||||
)
|
||||
request = _request().model_copy(
|
||||
update={"chat_template_kwargs": {"thinking": False}}
|
||||
@@ -237,7 +243,7 @@ def test_delegating_parser_auto_no_call_strips_consumed_response_prefix():
|
||||
|
||||
def test_delegating_parser_required_call_strips_consumed_response_prefix():
|
||||
parser = KimiK3DelegatingParser(
|
||||
DummyTokenizer(), chat_template_kwargs={"thinking": False}
|
||||
_dummy_tokenizer(), chat_template_kwargs={"thinking": False}
|
||||
)
|
||||
request = _request().model_copy(
|
||||
update={
|
||||
@@ -263,7 +269,7 @@ def test_delegating_parser_required_call_strips_consumed_response_prefix():
|
||||
|
||||
def test_delegating_parser_truncated_tools_do_not_leak_xtml():
|
||||
parser = KimiK3DelegatingParser(
|
||||
DummyTokenizer(), chat_template_kwargs={"thinking": False}
|
||||
_dummy_tokenizer(), chat_template_kwargs={"thinking": False}
|
||||
)
|
||||
request = _request().model_copy(
|
||||
update={
|
||||
@@ -284,7 +290,7 @@ def test_delegating_parser_truncated_tools_do_not_leak_xtml():
|
||||
|
||||
|
||||
def test_extract_tool_calls_unescapes_attributes():
|
||||
parser = KimiK3ToolParser(DummyTokenizer())
|
||||
parser = KimiK3ToolParser(_dummy_tokenizer())
|
||||
|
||||
output = _tools(_call("a&b"c", 1, _arg("k&q", "string", "v")))
|
||||
extracted = parser.extract_tool_calls(output, _request())
|
||||
@@ -295,7 +301,7 @@ def test_extract_tool_calls_unescapes_attributes():
|
||||
|
||||
|
||||
def test_extract_tool_calls_allows_less_than_in_attributes():
|
||||
parser = KimiK3ToolParser(DummyTokenizer())
|
||||
parser = KimiK3ToolParser(_dummy_tokenizer())
|
||||
|
||||
output = _tools(_call("calc<beta", 1, _arg("foo<bar", "string", "raw")))
|
||||
extracted = parser.extract_tool_calls(output, _request())
|
||||
@@ -306,7 +312,7 @@ def test_extract_tool_calls_allows_less_than_in_attributes():
|
||||
|
||||
|
||||
def test_extract_content_from_whitespace_degraded_markers():
|
||||
parser = KimiK3ToolParser(DummyTokenizer())
|
||||
parser = KimiK3ToolParser(_dummy_tokenizer())
|
||||
|
||||
extracted = parser.extract_tool_calls(
|
||||
f"{OPEN} response {SEP}answer{CLOSE} response {SEP}",
|
||||
@@ -318,7 +324,7 @@ def test_extract_content_from_whitespace_degraded_markers():
|
||||
|
||||
|
||||
def test_streaming_split_markers_do_not_leak():
|
||||
parser = KimiK3ToolParser(DummyTokenizer())
|
||||
parser = KimiK3ToolParser(_dummy_tokenizer())
|
||||
request = _request()
|
||||
previous_text = ""
|
||||
previous_ids: list[int] = []
|
||||
@@ -362,21 +368,22 @@ def test_streaming_split_markers_do_not_leak():
|
||||
assert OPEN not in content
|
||||
assert SEP not in content
|
||||
assert len(tool_deltas) == 1
|
||||
assert tool_deltas[0].function is not None
|
||||
assert tool_deltas[0].function.name == "calc"
|
||||
assert json.loads(tool_deltas[0].function.arguments) == {"x": 1}
|
||||
assert json.loads(tool_deltas[0].function.arguments) == {"x": 1} # type: ignore[arg-type]
|
||||
|
||||
|
||||
def test_tool_call_ids_are_unique_across_messages():
|
||||
output = _tools(_call("calc", 1))
|
||||
|
||||
first = KimiK3ToolParser(DummyTokenizer()).extract_tool_calls(output, _request())
|
||||
second = KimiK3ToolParser(DummyTokenizer()).extract_tool_calls(output, _request())
|
||||
first = KimiK3ToolParser(_dummy_tokenizer()).extract_tool_calls(output, _request())
|
||||
second = KimiK3ToolParser(_dummy_tokenizer()).extract_tool_calls(output, _request())
|
||||
|
||||
assert first.tool_calls[0].id != second.tool_calls[0].id
|
||||
|
||||
|
||||
def test_streaming_consumed_response_prefix_no_call_keeps_content():
|
||||
parser = KimiK3ToolParser(DummyTokenizer())
|
||||
parser = KimiK3ToolParser(_dummy_tokenizer())
|
||||
request = _request()
|
||||
previous_text = ""
|
||||
previous_ids: list[int] = []
|
||||
@@ -406,7 +413,7 @@ def test_streaming_consumed_response_prefix_no_call_keeps_content():
|
||||
|
||||
def test_delegating_parser_tool_choice_none_strips_xtml_and_suppresses_calls():
|
||||
parser = KimiK3DelegatingParser(
|
||||
DummyTokenizer(), chat_template_kwargs={"thinking": False}
|
||||
_dummy_tokenizer(), chat_template_kwargs={"thinking": False}
|
||||
)
|
||||
request = _request().model_copy(
|
||||
update={
|
||||
@@ -443,7 +450,7 @@ def test_delegating_parser_tool_choice_none_strips_xtml_and_suppresses_calls():
|
||||
|
||||
|
||||
def test_adjust_request_keeps_xtml_markers_contiguous():
|
||||
parser = KimiK3ToolParser(DummyTokenizer())
|
||||
parser = KimiK3ToolParser(_dummy_tokenizer())
|
||||
request = _request()
|
||||
|
||||
adjusted = parser.adjust_request(request)
|
||||
@@ -455,7 +462,7 @@ def test_adjust_request_keeps_xtml_markers_contiguous():
|
||||
|
||||
|
||||
def test_adjust_request_required_uses_xtml_parser_not_json_guidance():
|
||||
parser = KimiK3ToolParser(DummyTokenizer())
|
||||
parser = KimiK3ToolParser(_dummy_tokenizer())
|
||||
request = _request().model_copy(update={"tool_choice": "required"})
|
||||
|
||||
adjusted = parser.adjust_request(request)
|
||||
@@ -476,7 +483,7 @@ def test_adjust_request_required_uses_xtml_parser_not_json_guidance():
|
||||
],
|
||||
)
|
||||
def test_adjust_request_rejects_named_tool_choice(tool_request):
|
||||
parser = KimiK3ToolParser(DummyTokenizer())
|
||||
parser = KimiK3ToolParser(_dummy_tokenizer())
|
||||
|
||||
with pytest.raises(VLLMValidationError) as exc_info:
|
||||
parser.adjust_request(tool_request)
|
||||
@@ -512,7 +519,7 @@ def test_responses_chat_params_keeps_template_tool_choice_when_api_auto():
|
||||
|
||||
def test_responses_required_tool_choice_uses_xtml_parser():
|
||||
parser = KimiK3DelegatingParser(
|
||||
DummyTokenizer(), chat_template_kwargs={"thinking": False}
|
||||
_dummy_tokenizer(), chat_template_kwargs={"thinking": False}
|
||||
)
|
||||
request = _responses_request(tool_choice="required").model_copy(
|
||||
update={"chat_template_kwargs": {"thinking": False}}
|
||||
@@ -538,7 +545,7 @@ def test_responses_required_tool_choice_uses_xtml_parser():
|
||||
|
||||
def test_responses_named_tool_choice_uses_xtml_parser():
|
||||
parser = KimiK3DelegatingParser(
|
||||
DummyTokenizer(), chat_template_kwargs={"thinking": False}
|
||||
_dummy_tokenizer(), chat_template_kwargs={"thinking": False}
|
||||
)
|
||||
request = _responses_request(
|
||||
tool_choice={"type": "function", "name": "calc"}
|
||||
|
||||
@@ -24,9 +24,11 @@ a real tokenizer live in ``test_muse_glimmer_parse_delta.py``.
|
||||
|
||||
import json
|
||||
from types import SimpleNamespace
|
||||
from typing import cast
|
||||
|
||||
import pytest
|
||||
|
||||
from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest
|
||||
from vllm.reasoning.muse_glimmer_reasoning_parser import MuseGlimmerReasoningParser
|
||||
from vllm.tool_parsers.muse_glimmer_tool_parser import MuseGlimmerToolParser
|
||||
|
||||
@@ -61,10 +63,21 @@ class _FakeReq:
|
||||
tools = None
|
||||
|
||||
|
||||
def _req(*names):
|
||||
def _fake_req() -> ChatCompletionRequest:
|
||||
return cast(ChatCompletionRequest, _FakeReq())
|
||||
|
||||
|
||||
# The parsers accept a missing request at runtime.
|
||||
_NO_REQ = cast(ChatCompletionRequest, None)
|
||||
|
||||
|
||||
def _req(*names: str) -> ChatCompletionRequest:
|
||||
"""A request with ``names`` registered as tools."""
|
||||
return SimpleNamespace(
|
||||
tools=[SimpleNamespace(function=SimpleNamespace(name=n)) for n in names]
|
||||
return cast(
|
||||
ChatCompletionRequest,
|
||||
SimpleNamespace(
|
||||
tools=[SimpleNamespace(function=SimpleNamespace(name=n)) for n in names]
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -90,7 +103,7 @@ def test_single_tool_call_after_reasoning():
|
||||
'<atem:parameter name="units">celsius</atem:parameter>\n'
|
||||
"</atem:invoke>\n</atem:function_calls><|eot|>"
|
||||
)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, raw, None)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, raw, _NO_REQ)
|
||||
assert out.tools_called and len(out.tool_calls) == 1
|
||||
assert out.tool_calls[0].function.name == "weather.get"
|
||||
assert json.loads(out.tool_calls[0].function.arguments) == {
|
||||
@@ -112,7 +125,7 @@ def test_parallel_calls_across_eom_boundaries():
|
||||
'<atem:parameter name="b">4</atem:parameter>\n'
|
||||
"</atem:invoke>\n</atem:function_calls><|eot|>"
|
||||
)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, raw, None)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, raw, _NO_REQ)
|
||||
assert out.tools_called and len(out.tool_calls) == 2, len(out.tool_calls)
|
||||
assert [t.function.name for t in out.tool_calls] == ["math.add", "math.mul"]
|
||||
# JSON-typed values decode to ints
|
||||
@@ -127,14 +140,14 @@ def test_echoed_invoke_in_reasoning_is_not_parsed():
|
||||
"but I will not.<|eom|>"
|
||||
"<|start|>assistant to=user<|message|>The answer is 42.<|eot|>"
|
||||
)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, raw, None)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, raw, _NO_REQ)
|
||||
assert not out.tools_called, "channel scoping failed -- echoed invoke parsed!"
|
||||
assert out.content == "The answer is 42.", repr(out.content)
|
||||
|
||||
|
||||
def test_plain_answer_yields_no_tool_calls():
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(
|
||||
T, "to=user<|message|>Just a plain answer.<|eot|>", None
|
||||
T, "to=user<|message|>Just a plain answer.<|eot|>", _NO_REQ
|
||||
)
|
||||
assert not out.tools_called
|
||||
|
||||
@@ -147,7 +160,7 @@ def test_json_object_array_and_bool_params_decode():
|
||||
'<atem:parameter name="flag">true</atem:parameter>\n'
|
||||
"</atem:invoke>\n</atem:function_calls><|eot|>"
|
||||
)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, raw, None)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, raw, _NO_REQ)
|
||||
assert json.loads(out.tool_calls[0].function.arguments) == {
|
||||
"payload": {"nested": [1, 2, 3]},
|
||||
"flag": True,
|
||||
@@ -166,10 +179,10 @@ def test_reasoning_to_toolcall_handoff():
|
||||
'<atem:parameter name="city">Paris</atem:parameter>\n'
|
||||
"</atem:invoke>\n</atem:function_calls>"
|
||||
)
|
||||
reasoning, content = MuseGlimmerReasoningParser.extract_reasoning(R, raw, None)
|
||||
reasoning, content = MuseGlimmerReasoningParser.extract_reasoning(R, raw, _NO_REQ)
|
||||
assert reasoning == "Let me call the tool.", repr(reasoning)
|
||||
assert content is not None and "<atem:invoke" in content, repr(content)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, content, None)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, content, _NO_REQ)
|
||||
assert out.tools_called and len(out.tool_calls) == 1
|
||||
assert out.tool_calls[0].function.name == "weather.get"
|
||||
|
||||
@@ -179,15 +192,17 @@ def test_reasoning_then_user_answer():
|
||||
" to=self<|message|>thinking<|eom|>"
|
||||
"<|start|>assistant to=user<|message|>The answer is 42.<|eot|>"
|
||||
)
|
||||
reasoning, content = MuseGlimmerReasoningParser.extract_reasoning(R, raw, None)
|
||||
reasoning, content = MuseGlimmerReasoningParser.extract_reasoning(R, raw, _NO_REQ)
|
||||
assert reasoning == "thinking", repr(reasoning)
|
||||
assert content == "The answer is 42.", repr(content)
|
||||
assert not MuseGlimmerToolParser.extract_tool_calls(T, content, None).tools_called
|
||||
assert not MuseGlimmerToolParser.extract_tool_calls(
|
||||
T, content, _NO_REQ
|
||||
).tools_called
|
||||
|
||||
|
||||
def test_plain_content_without_framing_passes_through():
|
||||
reasoning, content = MuseGlimmerReasoningParser.extract_reasoning(
|
||||
R, "Just a direct answer.", None
|
||||
R, "Just a direct answer.", _NO_REQ
|
||||
)
|
||||
assert reasoning is None and content == "Just a direct answer.", (
|
||||
reasoning,
|
||||
@@ -207,9 +222,10 @@ def test_reasoning_then_parallel_calls():
|
||||
'<atem:parameter name="a">3</atem:parameter>\n</atem:invoke>\n'
|
||||
"</atem:function_calls><|eot|>"
|
||||
)
|
||||
reasoning, content = MuseGlimmerReasoningParser.extract_reasoning(R, raw, None)
|
||||
reasoning, content = MuseGlimmerReasoningParser.extract_reasoning(R, raw, _NO_REQ)
|
||||
assert reasoning == "need two calls", repr(reasoning)
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, content, None)
|
||||
assert content is not None
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, content, _NO_REQ)
|
||||
assert [t.function.name for t in out.tool_calls] == ["math.add", "math.mul"], (
|
||||
out.tool_calls
|
||||
)
|
||||
@@ -231,7 +247,7 @@ def _stream(raw: str, chunk: int):
|
||||
R, prev, cur, delta, [], [], []
|
||||
)
|
||||
if dm is not None:
|
||||
if getattr(dm, "reasoning", None):
|
||||
if dm.reasoning:
|
||||
reasoning.append(dm.reasoning)
|
||||
content_delta = getattr(dm, "content", None)
|
||||
# Tool-channel content is an internal handoff to the tool parser,
|
||||
@@ -239,7 +255,7 @@ def _stream(raw: str, chunk: int):
|
||||
if content_delta and "<atem:function_calls>" not in content_delta:
|
||||
content.append(content_delta)
|
||||
dt = MuseGlimmerToolParser.extract_tool_calls_streaming(
|
||||
T, prev, cur, delta, [], [], [], _FakeReq()
|
||||
T, prev, cur, delta, [], [], [], _fake_req()
|
||||
)
|
||||
if dt is not None and dt.tool_calls:
|
||||
toolcalls.extend(dt.tool_calls)
|
||||
@@ -319,11 +335,11 @@ def test_streaming_reasoning_then_content():
|
||||
|
||||
|
||||
def test_truncated_cot_no_toolcall_nonstreaming():
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, RAW_TRUNCATED, _FakeReq())
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(T, RAW_TRUNCATED, _fake_req())
|
||||
assert not out.tools_called and out.tool_calls == []
|
||||
# partial reasoning must still be recovered by the reasoning parser
|
||||
reasoning, _ = MuseGlimmerReasoningParser.extract_reasoning(
|
||||
R, RAW_TRUNCATED, _FakeReq()
|
||||
R, RAW_TRUNCATED, _fake_req()
|
||||
)
|
||||
assert reasoning and "Maybe I should call" in reasoning, repr(reasoning)
|
||||
|
||||
@@ -374,7 +390,7 @@ def test_trailing_segment_ambiguous_left_alone():
|
||||
|
||||
def test_no_registered_tools_passthrough():
|
||||
out = MuseGlimmerToolParser.extract_tool_calls(
|
||||
T, _call("get_weather.get_weather"), None
|
||||
T, _call("get_weather.get_weather"), _NO_REQ
|
||||
)
|
||||
assert out.tool_calls[0].function.name == "get_weather.get_weather"
|
||||
|
||||
|
||||
@@ -203,6 +203,7 @@ def test_input_image_detail_defaults_or_preserves(detail: str | None) -> None:
|
||||
|
||||
request = ResponsesRequest.model_validate({"input": [item]})
|
||||
|
||||
assert isinstance(request.input, list)
|
||||
assert request.input[0]["content"][0]["detail"] == (
|
||||
"auto" if detail is None else detail
|
||||
)
|
||||
|
||||
@@ -306,18 +306,17 @@ def _collect_required_tool_streaming_json(output_json: str, delta_len: int) -> s
|
||||
|
||||
combined_messages = "["
|
||||
for message in messages:
|
||||
if message.tool_calls[0].function.name:
|
||||
fn = message.tool_calls[0].function
|
||||
assert fn is not None
|
||||
if fn.name:
|
||||
if len(combined_messages) > 1:
|
||||
combined_messages += "},"
|
||||
|
||||
combined_messages += (
|
||||
'{"name": "'
|
||||
+ message.tool_calls[0].function.name
|
||||
+ '", "parameters": '
|
||||
+ message.tool_calls[0].function.arguments
|
||||
'{"name": "' + fn.name + '", "parameters": ' + (fn.arguments or "")
|
||||
)
|
||||
else:
|
||||
combined_messages += message.tool_calls[0].function.arguments
|
||||
combined_messages += fn.arguments or ""
|
||||
combined_messages += "}]"
|
||||
return combined_messages
|
||||
|
||||
|
||||
@@ -476,32 +476,32 @@ def test_compilation_config_mode_validator():
|
||||
"""Test that CompilationConfig.mode field validator converts strings to integers."""
|
||||
from vllm.config.compilation import CompilationConfig, CompilationMode
|
||||
|
||||
config = CompilationConfig(mode=0)
|
||||
config = CompilationConfig(mode=0) # type: ignore[arg-type]
|
||||
assert config.mode == CompilationMode.NONE
|
||||
|
||||
config = CompilationConfig(mode=3)
|
||||
config = CompilationConfig(mode=3) # type: ignore[arg-type]
|
||||
assert config.mode == CompilationMode.VLLM_COMPILE
|
||||
|
||||
config = CompilationConfig(mode="NONE")
|
||||
config = CompilationConfig(mode="NONE") # type: ignore[arg-type]
|
||||
assert config.mode == CompilationMode.NONE
|
||||
|
||||
config = CompilationConfig(mode="STOCK_TORCH_COMPILE")
|
||||
config = CompilationConfig(mode="STOCK_TORCH_COMPILE") # type: ignore[arg-type]
|
||||
assert config.mode == CompilationMode.STOCK_TORCH_COMPILE
|
||||
|
||||
config = CompilationConfig(mode="DYNAMO_TRACE_ONCE")
|
||||
config = CompilationConfig(mode="DYNAMO_TRACE_ONCE") # type: ignore[arg-type]
|
||||
assert config.mode == CompilationMode.DYNAMO_TRACE_ONCE
|
||||
|
||||
config = CompilationConfig(mode="VLLM_COMPILE")
|
||||
config = CompilationConfig(mode="VLLM_COMPILE") # type: ignore[arg-type]
|
||||
assert config.mode == CompilationMode.VLLM_COMPILE
|
||||
|
||||
config = CompilationConfig(mode="none")
|
||||
config = CompilationConfig(mode="none") # type: ignore[arg-type]
|
||||
assert config.mode == CompilationMode.NONE
|
||||
|
||||
config = CompilationConfig(mode="vllm_compile")
|
||||
config = CompilationConfig(mode="vllm_compile") # type: ignore[arg-type]
|
||||
assert config.mode == CompilationMode.VLLM_COMPILE
|
||||
|
||||
with pytest.raises(ValidationError, match="Invalid compilation mode"):
|
||||
CompilationConfig(mode="INVALID_MODE")
|
||||
CompilationConfig(mode="INVALID_MODE") # type: ignore[arg-type]
|
||||
|
||||
|
||||
def test_flat_product():
|
||||
|
||||
@@ -128,7 +128,7 @@ def test_lru_cache():
|
||||
|
||||
|
||||
def test_lru_cache_put_if_fits():
|
||||
cache = LRUCache(10, getsizeof=lambda x: x)
|
||||
cache = LRUCache[str, int](10, getsizeof=lambda x: x)
|
||||
|
||||
assert cache.put_if_fits("ok", 4) is True
|
||||
assert cache["ok"] == 4
|
||||
|
||||
@@ -206,8 +206,8 @@ def test_make_zmq_socket_ipv6():
|
||||
|
||||
|
||||
def test_make_zmq_path():
|
||||
assert make_zmq_path("tcp", "127.0.0.1", "5555") == "tcp://127.0.0.1:5555"
|
||||
assert make_zmq_path("tcp", "::1", "5555") == "tcp://[::1]:5555"
|
||||
assert make_zmq_path("tcp", "127.0.0.1", 5555) == "tcp://127.0.0.1:5555"
|
||||
assert make_zmq_path("tcp", "::1", 5555) == "tcp://[::1]:5555"
|
||||
|
||||
|
||||
def test_get_tcp_uri():
|
||||
|
||||
@@ -257,7 +257,7 @@ class TestCudagraphDispatcher:
|
||||
def test_get_capture_descs_empty_when_not_initialized(self):
|
||||
"""Test that get_capture_descs returns empty list when keys not initialized."""
|
||||
comp_config = CompilationConfig(
|
||||
cudagraph_mode="FULL",
|
||||
cudagraph_mode=CUDAGraphMode.FULL,
|
||||
mode=CompilationMode.NONE,
|
||||
cudagraph_capture_sizes=[1, 8],
|
||||
)
|
||||
@@ -419,7 +419,7 @@ def _run_and_monitor_call(
|
||||
def test_capture_replay_bypass_logic():
|
||||
comp_config = CompilationConfig(
|
||||
mode=CompilationMode.VLLM_COMPILE,
|
||||
cudagraph_mode="FULL",
|
||||
cudagraph_mode=CUDAGraphMode.FULL,
|
||||
cudagraph_capture_sizes=[1, 2],
|
||||
)
|
||||
vllm_config = _create_vllm_config(comp_config)
|
||||
@@ -489,7 +489,7 @@ def test_nested_wrappers():
|
||||
"""Tests a scenario with a PIECEWISE wrapper inside a FULL one."""
|
||||
comp_config = CompilationConfig(
|
||||
mode=CompilationMode.VLLM_COMPILE,
|
||||
cudagraph_mode="FULL",
|
||||
cudagraph_mode=CUDAGraphMode.FULL,
|
||||
cudagraph_capture_sizes=[1],
|
||||
)
|
||||
vllm_config = _create_vllm_config(comp_config)
|
||||
|
||||
@@ -38,7 +38,7 @@ def _reset_graph_pool_id():
|
||||
|
||||
def _create_vllm_config() -> MagicMock:
|
||||
compilation_config = CompilationConfig(
|
||||
cudagraph_mode="FULL",
|
||||
cudagraph_mode=CUDAGraphMode.FULL,
|
||||
cudagraph_capture_sizes=[4],
|
||||
)
|
||||
compilation_config.max_cudagraph_capture_size = 4
|
||||
@@ -134,7 +134,7 @@ def test_piecewise_capture_uses_pcp_dummy_slot_mappings():
|
||||
device=torch.device("cpu"),
|
||||
max_num_reqs=num_reqs,
|
||||
max_num_tokens=num_tokens,
|
||||
block_tables=pcp_block_tables,
|
||||
block_tables=pcp_block_tables, # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
block_tables = MagicMock()
|
||||
@@ -224,7 +224,7 @@ def test_speculator_capture_preserves_decode_query_bounds(
|
||||
)
|
||||
manager = SpeculatorCudaGraphManager.__new__(SpeculatorCudaGraphManager)
|
||||
manager.max_num_reqs = num_reqs
|
||||
manager.vllm_config = SimpleNamespace(
|
||||
manager.vllm_config = SimpleNamespace( # type: ignore[assignment]
|
||||
parallel_config=SimpleNamespace(data_parallel_size=1)
|
||||
)
|
||||
buffers = InputBuffers(num_reqs, num_tokens, torch.device("cpu"))
|
||||
@@ -264,7 +264,7 @@ def _create_decode_vllm_config(
|
||||
use_kda_recoverssm: bool = False,
|
||||
) -> MagicMock:
|
||||
compilation_config = CompilationConfig(
|
||||
cudagraph_mode="FULL_AND_PIECEWISE",
|
||||
cudagraph_mode=CUDAGraphMode.FULL_AND_PIECEWISE,
|
||||
cudagraph_capture_sizes=capture_sizes,
|
||||
)
|
||||
compilation_config.max_cudagraph_capture_size = capture_sizes[-1]
|
||||
@@ -473,6 +473,7 @@ def test_dynamic_spec_decode_shared_token_count_stays_reachable(monkeypatch):
|
||||
assert any(len(descs) > 1 for descs in by_num_tokens.values())
|
||||
|
||||
for desc in full_descs:
|
||||
assert desc.num_reqs is not None
|
||||
assert desc in manager._candidates[(desc.num_tokens, 0)], desc
|
||||
assert (
|
||||
manager.dispatch(
|
||||
|
||||
@@ -14,7 +14,7 @@ Test organization:
|
||||
|
||||
from collections.abc import Hashable
|
||||
from types import SimpleNamespace
|
||||
from typing import Any
|
||||
from typing import Any, cast
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
@@ -100,6 +100,50 @@ class _MockModel(SupportsEncoderCudaGraph):
|
||||
def get_encoder_cudagraph_budget_range(self, vllm_config):
|
||||
return (self._min_budget, self._max_budget)
|
||||
|
||||
def get_max_frames_per_video(self) -> int:
|
||||
return 0
|
||||
|
||||
def get_encoder_cudagraph_item_specs(
|
||||
self, mm_kwargs: dict[str, Any]
|
||||
) -> list[EncoderItemSpec]:
|
||||
return []
|
||||
|
||||
def prepare_encoder_cudagraph_capture_inputs(
|
||||
self,
|
||||
token_budget: int,
|
||||
max_batch_size: int,
|
||||
max_frames_per_batch: int,
|
||||
device: torch.device,
|
||||
dtype: torch.dtype,
|
||||
path: str = "default",
|
||||
axis_keys: tuple[Hashable, ...] | None = None,
|
||||
) -> EncoderCudaGraphCaptureInputs:
|
||||
return EncoderCudaGraphCaptureInputs(values={})
|
||||
|
||||
def prepare_encoder_cudagraph_replay_buffers(
|
||||
self,
|
||||
mm_kwargs: dict[str, Any],
|
||||
max_batch_size: int,
|
||||
max_frames_per_batch: int,
|
||||
path: str = "default",
|
||||
) -> EncoderCudaGraphReplayBuffers:
|
||||
return EncoderCudaGraphReplayBuffers(values={})
|
||||
|
||||
def encoder_cudagraph_forward(
|
||||
self, inputs: dict[str, torch.Tensor], path: str = "default"
|
||||
) -> torch.Tensor:
|
||||
return torch.zeros(0)
|
||||
|
||||
def encoder_eager_forward(
|
||||
self, mm_kwargs: dict[str, Any], path: str = "default"
|
||||
) -> torch.Tensor:
|
||||
return torch.zeros(0)
|
||||
|
||||
def select_encoder_cudagraph_items(
|
||||
self, mm_kwargs: dict[str, Any], indices: list[int]
|
||||
) -> dict[str, Any]:
|
||||
return {}
|
||||
|
||||
|
||||
def _make_manager_with_budgets(budgets: list[int]) -> EncoderCudaGraphManager:
|
||||
"""Create a minimal EncoderCudaGraphManager with only token_budgets set.
|
||||
@@ -594,6 +638,7 @@ def test_eonly_capture_preserves_outputs_across_replay_and_fallback(profile_only
|
||||
ECConnectorBase,
|
||||
ECConnectorMetadata,
|
||||
)
|
||||
from vllm.v1.core.sched.output import SchedulerOutput
|
||||
from vllm.v1.worker.gpu.ec_connector import ActiveECConnector
|
||||
from vllm.v1.worker.gpu.mm.encoder_runner import EncoderRunner
|
||||
from vllm.v1.worker.mm_encoder_model_runner import MMEncoderModelRunner
|
||||
@@ -607,7 +652,7 @@ def test_eonly_capture_preserves_outputs_across_replay_and_fallback(profile_only
|
||||
encoder.device = device
|
||||
encoder.cudagraph_manager = manager
|
||||
runner = object.__new__(MMEncoderModelRunner)
|
||||
runner.model_state = SimpleNamespace(encoder_runner=encoder)
|
||||
runner.model_state = SimpleNamespace(encoder_runner=encoder) # type: ignore[assignment]
|
||||
# No decoder manager is installed: capture must be encoder-only.
|
||||
with patch(
|
||||
"vllm.v1.worker.mm_encoder_model_runner.lock_workspace", wraps=lock_workspace
|
||||
@@ -628,9 +673,12 @@ def test_eonly_capture_preserves_outputs_across_replay_and_fallback(profile_only
|
||||
with patch(
|
||||
"vllm.v1.worker.gpu.ec_connector.get_ec_transfer", return_value=connector
|
||||
):
|
||||
ec = ActiveECConnector(SimpleNamespace(), cache)
|
||||
scheduled = SimpleNamespace(
|
||||
ec_connector_metadata=ECConnectorMetadata(), finished_req_ids=frozenset()
|
||||
ec = ActiveECConnector(SimpleNamespace(), cache) # type: ignore[arg-type]
|
||||
scheduled = cast(
|
||||
SchedulerOutput,
|
||||
SimpleNamespace(
|
||||
ec_connector_metadata=ECConnectorMetadata(), finished_req_ids=frozenset()
|
||||
),
|
||||
)
|
||||
saved_outputs: list[tuple[torch.Tensor, torch.Tensor]] = []
|
||||
# Mixed sizes exercise packing order; 64 is the boundary, 81 falls back.
|
||||
@@ -643,6 +691,7 @@ def test_eonly_capture_preserves_outputs_across_replay_and_fallback(profile_only
|
||||
outputs = manager.execute(inputs)
|
||||
assert outputs is not None
|
||||
cache[str(len(cache))] = outputs[0]
|
||||
assert ec_output is not None
|
||||
assert ec_output.finished_sending is None
|
||||
assert outputs is not None
|
||||
for actual, eager in zip(outputs, expected):
|
||||
@@ -656,6 +705,7 @@ def test_eonly_capture_preserves_outputs_across_replay_and_fallback(profile_only
|
||||
connector.get_finished.return_value = (set(cache), None)
|
||||
with ec.maybe_get_output(scheduled) as ec_output:
|
||||
pass
|
||||
assert ec_output is not None
|
||||
assert ec_output.finished_sending == set(cache)
|
||||
|
||||
|
||||
@@ -666,7 +716,7 @@ def test_eonly_without_encoder_graph_skips_capture():
|
||||
encoder = object.__new__(EncoderRunner)
|
||||
encoder.cudagraph_manager = None
|
||||
runner = object.__new__(MMEncoderModelRunner)
|
||||
runner.model_state = SimpleNamespace(encoder_runner=encoder)
|
||||
runner.model_state = SimpleNamespace(encoder_runner=encoder) # type: ignore[assignment]
|
||||
assert runner.capture_model() == 0
|
||||
|
||||
|
||||
@@ -973,7 +1023,7 @@ class TestInitInvariantValidation:
|
||||
vllm_config = _MockVllmConfig(token_budgets, max_mm_items)
|
||||
model = _MockModel(min_budget, max_budget)
|
||||
return EncoderCudaGraphManager(
|
||||
vllm_config=vllm_config,
|
||||
vllm_config=vllm_config, # type: ignore[arg-type]
|
||||
device=torch.device("cpu"),
|
||||
dtype=torch.float32,
|
||||
model=model,
|
||||
|
||||
@@ -155,7 +155,7 @@ def test_v1_generation_is_deterministic_across_batch_sizes_with_needle(
|
||||
# Ensure engines are shutdown to free GPU/VRAM across test sessions
|
||||
if llm is not None:
|
||||
with contextlib.suppress(Exception):
|
||||
llm.shutdown()
|
||||
llm.llm_engine.engine_core.shutdown()
|
||||
|
||||
|
||||
@skip_unsupported
|
||||
@@ -456,7 +456,7 @@ def test_logprobs_bitwise_batch_invariance_ragged_chunked_prefill(backend):
|
||||
)
|
||||
finally:
|
||||
with contextlib.suppress(Exception):
|
||||
llm.shutdown()
|
||||
llm.llm_engine.engine_core.shutdown()
|
||||
|
||||
|
||||
@skip_unsupported
|
||||
@@ -505,7 +505,7 @@ def test_simple_generation(backend):
|
||||
|
||||
finally:
|
||||
with contextlib.suppress(Exception):
|
||||
llm.shutdown()
|
||||
llm.llm_engine.engine_core.shutdown()
|
||||
|
||||
|
||||
@skip_unsupported
|
||||
@@ -815,15 +815,8 @@ def test_decode_logprobs_match_prefill_logprobs(
|
||||
if token_idx == 0:
|
||||
prefix_prompt = prompt
|
||||
else:
|
||||
# Use the partial output text up to this token
|
||||
# We'll need to construct this from the full output
|
||||
prefix_output = decode_output.outputs[0]
|
||||
# Get the text for tokens 0 to token_idx-1
|
||||
# Unfortunately, we don't have per-token text, so we'll use
|
||||
# a different approach: run prefill with prompt + tokens[0:token_idx]
|
||||
|
||||
# Actually, we need to get the actual text. Let's use a workaround:
|
||||
# Run a generation with max_tokens = token_idx to get that prefix
|
||||
# No per-token text, so regenerate with max_tokens = token_idx
|
||||
# to get the prefix text
|
||||
prefix_sp = SamplingParams(
|
||||
temperature=0.0,
|
||||
max_tokens=token_idx,
|
||||
|
||||
@@ -12,6 +12,7 @@ from PIL import Image
|
||||
from utils import _extract_step_logprobs, skip_if_not_cuda
|
||||
|
||||
from vllm import LLM, SamplingParams
|
||||
from vllm.inputs import TextPrompt
|
||||
|
||||
VLM_TEST_MODEL = os.getenv("VLLM_VLM_TEST_MODEL", "Qwen/Qwen3-VL-2B-Instruct")
|
||||
|
||||
@@ -30,8 +31,8 @@ def _make_image(seed: int, size: int) -> Image.Image:
|
||||
return Image.fromarray(rng.integers(0, 255, (size, size, 3), dtype=np.uint8))
|
||||
|
||||
|
||||
def _make_inputs(input_type: str, num_reqs: int) -> list[dict]:
|
||||
inputs = []
|
||||
def _make_inputs(input_type: str, num_reqs: int) -> list[TextPrompt]:
|
||||
inputs: list[TextPrompt] = []
|
||||
for i in range(num_reqs):
|
||||
if input_type == "image":
|
||||
prompt = IMAGE_PROMPT
|
||||
@@ -54,7 +55,7 @@ def _make_inputs(input_type: str, num_reqs: int) -> list[dict]:
|
||||
return inputs
|
||||
|
||||
|
||||
def _assert_batch_invariant(llm: LLM, inputs: list[dict], sampling) -> None:
|
||||
def _assert_batch_invariant(llm: LLM, inputs: list[TextPrompt], sampling) -> None:
|
||||
bs1 = [
|
||||
_extract_step_logprobs(llm.generate([inp], sampling, use_tqdm=False)[0])
|
||||
for inp in inputs
|
||||
@@ -134,4 +135,4 @@ def _run_vlm_batch_invariance(
|
||||
_assert_batch_invariant(llm, inputs, sampling)
|
||||
finally:
|
||||
with contextlib.suppress(Exception):
|
||||
llm.shutdown()
|
||||
llm.llm_engine.engine_core.shutdown()
|
||||
@@ -221,13 +221,15 @@ def _make_cutlass_fp4_moe_batch_invariant_case(
|
||||
in_dtype=dtype,
|
||||
activation=activation,
|
||||
)
|
||||
prepare_finalize = maybe_make_prepare_finalize(
|
||||
moe=moe_config,
|
||||
quant_config=quant_config,
|
||||
allow_new_interface=True,
|
||||
use_monolithic=False,
|
||||
)
|
||||
assert prepare_finalize is not None
|
||||
kernel = mk.FusedMoEKernel(
|
||||
maybe_make_prepare_finalize(
|
||||
moe=moe_config,
|
||||
quant_config=quant_config,
|
||||
allow_new_interface=True,
|
||||
use_monolithic=False,
|
||||
),
|
||||
prepare_finalize,
|
||||
CutlassExpertsFp4(
|
||||
moe_config=moe_config,
|
||||
quant_config=quant_config,
|
||||
|
||||
@@ -97,4 +97,4 @@ def test_dense_nvfp4_generation_is_deterministic_across_batch_sizes_e2e(backend)
|
||||
finally:
|
||||
if llm is not None:
|
||||
with contextlib.suppress(Exception):
|
||||
llm.shutdown()
|
||||
llm.llm_engine.engine_core.shutdown()
|
||||
@@ -524,6 +524,7 @@ def test_rms_norm_batch_invariance(dtype):
|
||||
batch[4] = row[0]
|
||||
out_batch = rms_norm_batch_invariant(batch, weight, eps=eps)
|
||||
|
||||
assert isinstance(out_single, torch.Tensor) and isinstance(out_batch, torch.Tensor)
|
||||
assert torch.equal(out_single[0], out_batch[4]), (
|
||||
"rms_norm output for a row differs when batch context changes"
|
||||
)
|
||||
@@ -547,6 +548,7 @@ if __name__ == "__main__":
|
||||
|
||||
# Batch-invariant implementation
|
||||
triton_output = rms_norm_batch_invariant(input_tensor, weight, eps=eps)
|
||||
assert isinstance(triton_output, torch.Tensor)
|
||||
|
||||
# Compare
|
||||
max_diff = (triton_output - reference_output).abs().max().item()
|
||||
|
||||
@@ -85,12 +85,12 @@ def test_multiproc_executor_worker_termination_timeout(
|
||||
monkeypatch.setattr(multiproc_executor_module.time, "sleep", clock.sleep)
|
||||
executor = MultiprocExecutor.__new__(MultiprocExecutor)
|
||||
proc = _FakeProcess(clock, exits_at=exits_at)
|
||||
executor._ensure_worker_termination([proc])
|
||||
executor._ensure_worker_termination([proc]) # type: ignore[list-item]
|
||||
assert proc.terminate_called is expected_terminate
|
||||
|
||||
|
||||
class CustomMultiprocExecutor(MultiprocExecutor):
|
||||
def collective_rpc(
|
||||
def collective_rpc( # type: ignore[override]
|
||||
self,
|
||||
method: str | Callable,
|
||||
timeout: float | None = None,
|
||||
@@ -98,7 +98,7 @@ class CustomMultiprocExecutor(MultiprocExecutor):
|
||||
kwargs: dict | None = None,
|
||||
non_block: bool = False,
|
||||
unique_reply_rank: int | None = None,
|
||||
kv_output_aggregator: KVOutputAggregator = None,
|
||||
kv_output_aggregator: KVOutputAggregator | None = None,
|
||||
ec_output_aggregator: ECOutputAggregator | None = None,
|
||||
) -> Any | list[Any] | Future[Any | list[Any]]:
|
||||
# Drop marker to show that this was run
|
||||
@@ -126,7 +126,7 @@ def test_custom_executor_type_checking():
|
||||
model=MODEL,
|
||||
gpu_memory_utilization=0.2,
|
||||
max_model_len=8192,
|
||||
distributed_executor_backend=Mock,
|
||||
distributed_executor_backend=Mock, # type: ignore[arg-type]
|
||||
)
|
||||
LLMEngine.from_engine_args(engine_args)
|
||||
with pytest.raises(ValueError):
|
||||
@@ -134,7 +134,7 @@ def test_custom_executor_type_checking():
|
||||
model=MODEL,
|
||||
gpu_memory_utilization=0.2,
|
||||
max_model_len=8192,
|
||||
distributed_executor_backend=Mock,
|
||||
distributed_executor_backend=Mock, # type: ignore[arg-type]
|
||||
)
|
||||
AsyncLLM.from_engine_args(engine_args)
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ def _flush_gpu_cache(llm: LLM, sampling_params: SamplingParams, seed: int = 0):
|
||||
block_size = cache_config.block_size
|
||||
# Use 1.2x GPU capacity to give the lazy cursor enough scheduling steps
|
||||
# to walk past all target blocks near the tail of the free queue.
|
||||
assert num_gpu_blocks is not None
|
||||
total_tokens_needed = int(num_gpu_blocks * block_size * 1.5)
|
||||
|
||||
# Use token-id prompts so each filler is unique (no prefix sharing).
|
||||
|
||||
@@ -260,6 +260,7 @@ def test_block_stored_per_group_metadata_full_attention() -> None:
|
||||
)
|
||||
assert ev.block_hashes == [expected_hash_0]
|
||||
assert ev.parent_block_hash is None
|
||||
assert req.prompt_token_ids is not None
|
||||
assert ev.token_ids == req.prompt_token_ids[0:BLOCK_SIZE]
|
||||
|
||||
# Second block's parent_block_hash equals the first block's hash.
|
||||
@@ -296,7 +297,7 @@ def test_eager_store_lora_metadata() -> None:
|
||||
f"expected lora_name='test-lora', got {ev.lora_name!r}"
|
||||
)
|
||||
assert ev.extra_keys is not None, "expected extra_keys for lora request"
|
||||
assert any("test-lora" in keys for keys in ev.extra_keys), (
|
||||
assert any(keys is not None and "test-lora" in keys for keys in ev.extra_keys), (
|
||||
f"expected 'test-lora' in extra_keys, got {ev.extra_keys}"
|
||||
)
|
||||
assert len(ev.token_ids) == BLOCK_SIZE
|
||||
@@ -372,6 +373,7 @@ def test_finished_eager_store_emits_all_storage_events() -> None:
|
||||
secondary_event_hash = maybe_convert_block_hash(get_block_hash(secondary_hash))
|
||||
by_hash = {event.block_hashes[0]: event for event in stored}
|
||||
assert set(by_hash) == {*primary_event_hashes, secondary_event_hash}
|
||||
assert req.prompt_token_ids is not None
|
||||
assert (
|
||||
by_hash[primary_event_hashes[0]].token_ids == req.prompt_token_ids[:BLOCK_SIZE]
|
||||
)
|
||||
@@ -451,6 +453,7 @@ def test_secondary_hash_block_stored_metadata() -> None:
|
||||
by_hash = {event.block_hashes[0]: event for event in stored}
|
||||
assert set(by_hash) == {primary_event_hash, secondary_event_hash}
|
||||
assert by_hash[primary_event_hash].block_size == BLOCK_SIZE
|
||||
assert req.prompt_token_ids is not None
|
||||
assert by_hash[primary_event_hash].token_ids == req.prompt_token_ids[:BLOCK_SIZE]
|
||||
assert by_hash[secondary_event_hash].block_size == BLOCK_SIZE // 2
|
||||
assert (
|
||||
@@ -752,6 +755,7 @@ def test_mamba_align_skips_positional_event_metadata() -> None:
|
||||
stored = [e for e in events if isinstance(e, BlockStored)]
|
||||
assert len(stored) == 2
|
||||
assert {ev.group_idx for ev in stored} == {0}
|
||||
assert req.prompt_token_ids is not None
|
||||
for idx, ev in enumerate(stored):
|
||||
assert ev.block_size == vbs
|
||||
assert ev.token_ids == req.prompt_token_ids[idx * vbs : (idx + 1) * vbs]
|
||||
|
||||
@@ -19,6 +19,7 @@ from vllm.config import (
|
||||
SchedulerConfig,
|
||||
VllmConfig,
|
||||
)
|
||||
from vllm.config.cache import MambaCacheMode
|
||||
from vllm.config.kv_events import KVEventsConfig
|
||||
from vllm.distributed.kv_transfer.kv_connector.v1.simple_cpu_offload_connector import (
|
||||
SimpleCPUOffloadConnector,
|
||||
@@ -1243,7 +1244,7 @@ def test_preemption_no_cpu_block_leak() -> None:
|
||||
block_hasher=req._block_hasher,
|
||||
)
|
||||
hit_tokens, is_async = sched.get_num_new_matched_tokens(req2, num_computed_tokens=0)
|
||||
assert hit_tokens > 0
|
||||
assert hit_tokens is not None and hit_tokens > 0
|
||||
|
||||
gpu_blocks2 = fix.gpu_block_pool.get_new_blocks(num_blocks)
|
||||
kv_blocks2 = KVCacheBlocks(blocks=(gpu_blocks2,))
|
||||
@@ -1338,7 +1339,7 @@ def test_inflight_finish_deferred_cleanup() -> None:
|
||||
block_hasher=req._block_hasher,
|
||||
)
|
||||
hit_tokens, _ = sched.get_num_new_matched_tokens(req2, num_computed_tokens=0)
|
||||
assert hit_tokens > 0
|
||||
assert hit_tokens is not None and hit_tokens > 0
|
||||
|
||||
gpu_blocks2 = fix.gpu_block_pool.get_new_blocks(num_blocks)
|
||||
kv_blocks2 = KVCacheBlocks(blocks=(gpu_blocks2,))
|
||||
@@ -1896,7 +1897,7 @@ def test_reset_pending_loads() -> None:
|
||||
block_hasher=req._block_hasher,
|
||||
)
|
||||
hit_tokens, is_async = sched.get_num_new_matched_tokens(req2, num_computed_tokens=0)
|
||||
assert hit_tokens > 0
|
||||
assert hit_tokens is not None and hit_tokens > 0
|
||||
|
||||
gpu_blocks2 = gpu_pool.get_new_blocks(num_blocks)
|
||||
kv_blocks2 = KVCacheBlocks(blocks=(gpu_blocks2,))
|
||||
@@ -2246,7 +2247,7 @@ def _make_hybrid_attention_mamba_scheduler(
|
||||
hash_block_size: int | None = None,
|
||||
dcp_world_size: int = 4,
|
||||
lazy: bool = False,
|
||||
mamba_cache_mode: str = "align",
|
||||
mamba_cache_mode: MambaCacheMode = "align",
|
||||
enable_kv_cache_events: bool = False,
|
||||
) -> SchedulerFixture:
|
||||
"""Build a scheduler for one attention group plus one Mamba group."""
|
||||
|
||||
@@ -36,6 +36,7 @@ from vllm.v1.core.kv_cache_utils import (
|
||||
)
|
||||
from vllm.v1.kv_cache_interface import (
|
||||
FullAttentionSpec,
|
||||
KVCacheConfig,
|
||||
KVCacheGroupSpec,
|
||||
KVCacheLayout,
|
||||
KVCacheSpec,
|
||||
@@ -50,7 +51,10 @@ from vllm.v1.simple_kv_offload.cuda_mem_ops import (
|
||||
build_params,
|
||||
)
|
||||
from vllm.v1.simple_kv_offload.disk_backend import DiskBackend
|
||||
from vllm.v1.simple_kv_offload.metadata import SimpleCPUOffloadMetadata
|
||||
from vllm.v1.simple_kv_offload.metadata import (
|
||||
SimpleCPUOffloadMetadata,
|
||||
SimpleCPUOffloadWorkerMetadata,
|
||||
)
|
||||
from vllm.v1.simple_kv_offload.worker import SimpleCPUOffloadWorker
|
||||
from vllm.v1.worker.gpu.kv_connector import ActiveKVConnector
|
||||
from vllm.v1.worker.kv_connector_model_runner_mixin import KVConnectorModelRunnerMixin
|
||||
@@ -64,6 +68,12 @@ ITERS = 30
|
||||
SLEEP_CYCLES = 50_000_000
|
||||
|
||||
|
||||
def _make_worker(
|
||||
kv_cache_config: KVCacheConfig | None, cpu_capacity_bytes: int
|
||||
) -> SimpleCPUOffloadWorker:
|
||||
return SimpleCPUOffloadWorker(None, kv_cache_config, cpu_capacity_bytes) # type: ignore[arg-type]
|
||||
|
||||
|
||||
def _make_backend() -> tuple[DmaCopyBackend, torch.Tensor, torch.Tensor]:
|
||||
gpu = {"k": torch.zeros((NUM_BLOCKS, BLOCK_BYTES), dtype=torch.int8, device="cuda")}
|
||||
cpu = {
|
||||
@@ -87,7 +97,7 @@ def _make_backend() -> tuple[DmaCopyBackend, torch.Tensor, torch.Tensor]:
|
||||
def test_no_forward_step_completes_cpu_store(monkeypatch, use_v2):
|
||||
"""A finished request's final store must drain without another model step."""
|
||||
backend, gpu, cpu = _make_backend()
|
||||
worker = SimpleCPUOffloadWorker(None, None, cpu_capacity_bytes=0)
|
||||
worker = _make_worker(None, 0)
|
||||
worker._backend = backend
|
||||
connector = SimpleCPUOffloadConnector.__new__(SimpleCPUOffloadConnector)
|
||||
connector.worker_handler = worker
|
||||
@@ -105,13 +115,13 @@ def test_no_forward_step_completes_cpu_store(monkeypatch, use_v2):
|
||||
active = ActiveKVConnector.__new__(ActiveKVConnector)
|
||||
active.kv_connector = connector
|
||||
active._disabled = False
|
||||
active._pending_load_start = False
|
||||
active._pending_load_kwargs = None
|
||||
module = "vllm.v1.worker.gpu.kv_connector"
|
||||
monkeypatch.setattr(f"{module}.is_forward_context_available", lambda: True)
|
||||
monkeypatch.setattr(f"{module}.get_forward_context", lambda: None)
|
||||
result = active.no_forward(output)
|
||||
else:
|
||||
result = KVConnectorModelRunnerMixin.kv_connector_no_forward(output, None)
|
||||
result = KVConnectorModelRunnerMixin.kv_connector_no_forward(output, None) # type: ignore[arg-type]
|
||||
completion = (
|
||||
result.kv_connector_output.kv_connector_worker_meta
|
||||
if result.kv_connector_output is not None
|
||||
@@ -123,6 +133,7 @@ def test_no_forward_step_completes_cpu_store(monkeypatch, use_v2):
|
||||
completion = connector.build_connector_worker_meta()
|
||||
time.sleep(0.001)
|
||||
assert completion is not None, "CPU store never completed on the empty step"
|
||||
assert isinstance(completion, SimpleCPUOffloadWorkerMetadata)
|
||||
assert completion.completed_store_events == {0: 1}
|
||||
assert torch.equal(cpu[0], gpu[0].cpu())
|
||||
finally:
|
||||
@@ -132,7 +143,7 @@ def test_no_forward_step_completes_cpu_store(monkeypatch, use_v2):
|
||||
def test_deferred_store_waits_for_draft_forward(monkeypatch):
|
||||
"""Target completion must not submit the store before draft finalization."""
|
||||
backend, gpu, cpu = _make_backend()
|
||||
worker = SimpleCPUOffloadWorker(None, None, cpu_capacity_bytes=0)
|
||||
worker = _make_worker(None, 0)
|
||||
worker._backend = backend
|
||||
connector = SimpleCPUOffloadConnector.__new__(SimpleCPUOffloadConnector)
|
||||
connector.worker_handler = worker
|
||||
@@ -267,11 +278,12 @@ class _RecordingBackend:
|
||||
|
||||
def test_transfer_hooks_pass_wait_event_for_store_only():
|
||||
"""wait_for_save gates stores on a compute-done event; start_load_kv does not."""
|
||||
worker = SimpleCPUOffloadWorker(
|
||||
vllm_config=None, kv_cache_config=None, cpu_capacity_bytes=0
|
||||
worker = _make_worker(
|
||||
kv_cache_config=None,
|
||||
cpu_capacity_bytes=0,
|
||||
)
|
||||
recording = _RecordingBackend()
|
||||
worker._backend = recording
|
||||
worker._backend = recording # type: ignore[assignment]
|
||||
worker._connector_metadata = SimpleCPUOffloadMetadata(
|
||||
load_event=0,
|
||||
load_gpu_blocks=[0],
|
||||
@@ -332,8 +344,7 @@ def test_register_shared_kv_cache_storage(monkeypatch, layout: KVCacheLayout):
|
||||
)
|
||||
],
|
||||
)
|
||||
worker = SimpleCPUOffloadWorker(
|
||||
vllm_config=None,
|
||||
worker = _make_worker(
|
||||
kv_cache_config=cache_config,
|
||||
cpu_capacity_bytes=raw.nbytes,
|
||||
)
|
||||
@@ -366,8 +377,7 @@ def test_register_kv_cache_storage_with_trailing_padding(monkeypatch):
|
||||
cache_bytes = num_blocks * block_bytes
|
||||
raw = torch.zeros(4096, dtype=torch.int8, device="cuda")
|
||||
cache = raw[:cache_bytes].view(num_blocks, block_bytes)
|
||||
worker = SimpleCPUOffloadWorker(
|
||||
vllm_config=None,
|
||||
worker = _make_worker(
|
||||
kv_cache_config=MagicMock(
|
||||
num_blocks=num_blocks,
|
||||
kv_cache_tensors=[
|
||||
@@ -412,8 +422,7 @@ def test_register_separate_kv_head_groups(monkeypatch):
|
||||
)
|
||||
caches = dense_kv_cache_views(raw, spec, num_blocks, num_layers, layout)
|
||||
layer_names = [f"layer.{i}" for i in range(num_layers)]
|
||||
worker = SimpleCPUOffloadWorker(
|
||||
vllm_config=None,
|
||||
worker = _make_worker(
|
||||
kv_cache_config=MagicMock(
|
||||
num_blocks=num_blocks,
|
||||
kv_cache_tensors=[
|
||||
@@ -509,8 +518,7 @@ def test_register_mixed_page_sizes_in_one_cache_group(monkeypatch):
|
||||
assert len(set(pages)) > 1, "the mixed page sizes are what this test covers"
|
||||
|
||||
kv_caches = allocate_kv_cache(kv_cache_config, torch.device("cuda"), layout)
|
||||
worker = SimpleCPUOffloadWorker(
|
||||
vllm_config=None,
|
||||
worker = _make_worker(
|
||||
kv_cache_config=kv_cache_config,
|
||||
cpu_capacity_bytes=sum(pages) * num_blocks,
|
||||
)
|
||||
@@ -567,8 +575,7 @@ def test_register_mixed_page_sizes_odd_block_counts(monkeypatch, rank_blocks):
|
||||
assert kv_cache_config.num_blocks == rank_blocks
|
||||
|
||||
kv_caches = allocate_kv_cache(kv_cache_config, torch.device("cuda"), layout)
|
||||
worker = SimpleCPUOffloadWorker(
|
||||
vllm_config=None,
|
||||
worker = _make_worker(
|
||||
kv_cache_config=kv_cache_config,
|
||||
cpu_capacity_bytes=sum(pages) * rank_blocks,
|
||||
)
|
||||
|
||||
@@ -91,7 +91,7 @@ def test_grammar_bitmask_with_specdec():
|
||||
json='{"type": "object"}',
|
||||
),
|
||||
)
|
||||
sampling_params.structured_outputs._backend = "guidance"
|
||||
sampling_params.structured_outputs._backend = "guidance" # type: ignore[union-attr]
|
||||
sampling_params.update_from_generation_config({}, tokenizer.eos_token_id)
|
||||
|
||||
my_req_id = f"my_req_id_{i}"
|
||||
@@ -107,19 +107,23 @@ def test_grammar_bitmask_with_specdec():
|
||||
def grammar_bitmask(req: Request, tokens: list[int]) -> None:
|
||||
structured_output_manager.grammar_bitmask(
|
||||
requests={req.request_id: req},
|
||||
structured_output_request_ids={req.request_id: 0},
|
||||
structured_output_request_ids=[req.request_id],
|
||||
scheduled_spec_decode_tokens={req.request_id: tokens},
|
||||
)
|
||||
# At this point, we rolled-back, so should not be terminated
|
||||
assert not req.structured_output_request.grammar.is_terminated()
|
||||
assert req.structured_output_request is not None
|
||||
grammar = req.structured_output_request.grammar
|
||||
assert grammar is not None and not isinstance(grammar, Exception)
|
||||
assert not grammar.is_terminated()
|
||||
|
||||
# The grammar might not yet be compiled, so we wait for it
|
||||
assert request.structured_output_request is not None
|
||||
while not request.structured_output_request._check_grammar_completion():
|
||||
continue
|
||||
|
||||
assert request.structured_output_request.grammar.accept_tokens(
|
||||
request.request_id, prompt[:i]
|
||||
)
|
||||
grammar = request.structured_output_request.grammar
|
||||
assert grammar is not None and not isinstance(grammar, Exception)
|
||||
assert grammar.accept_tokens(request.request_id, prompt[:i])
|
||||
|
||||
grammar_bitmask(request, prompt[i:] + [tokenizer.eos_token_id])
|
||||
grammar_bitmask(
|
||||
@@ -155,7 +159,7 @@ def test_grammar_init_async_and_sync(async_grammar):
|
||||
json='{"type": "object"}',
|
||||
),
|
||||
)
|
||||
sampling_params.structured_outputs._backend = "guidance"
|
||||
sampling_params.structured_outputs._backend = "guidance" # type: ignore[union-attr]
|
||||
sampling_params.update_from_generation_config({}, tokenizer.eos_token_id)
|
||||
|
||||
request = Request(
|
||||
@@ -169,6 +173,7 @@ def test_grammar_init_async_and_sync(async_grammar):
|
||||
|
||||
# Check the internal _grammar type immediately after init
|
||||
# Before _check_grammar_completion is called, async mode should have a Future
|
||||
assert request.structured_output_request is not None
|
||||
raw_grammar = request.structured_output_request._grammar
|
||||
if async_grammar:
|
||||
assert isinstance(raw_grammar, Future), (
|
||||
@@ -191,7 +196,7 @@ def test_grammar_init_async_and_sync(async_grammar):
|
||||
|
||||
# Verify grammar is properly initialized and functional
|
||||
grammar = request.structured_output_request.grammar
|
||||
assert grammar is not None
|
||||
assert grammar is not None and not isinstance(grammar, Exception)
|
||||
assert not grammar.is_terminated()
|
||||
|
||||
# Verify the grammar can accept valid tokens
|
||||
|
||||
@@ -13,6 +13,7 @@ from mistral_common.protocol.instruct.tool_calls import Tool, ToolChoiceEnum
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
from vllm.config import StructuredOutputsConfig, VllmConfig
|
||||
from vllm.config.structured_outputs import StructuredOutputsBackend
|
||||
from vllm.exceptions import VLLMValidationError
|
||||
from vllm.sampling_params import SamplingParams, StructuredOutputsParams
|
||||
from vllm.tokenizers.mistral import MistralTokenizer
|
||||
@@ -41,13 +42,15 @@ EBNF_GRAMMAR = 'root ::= "id=" [0-9]+'
|
||||
|
||||
|
||||
def _validate(
|
||||
grammar: str, backend: str = "xgrammar", tokenizer: object | None = None
|
||||
grammar: str,
|
||||
backend: StructuredOutputsBackend = "xgrammar",
|
||||
tokenizer: object | None = None,
|
||||
) -> StructuredOutputsParams:
|
||||
params = SamplingParams(structured_outputs=StructuredOutputsParams(grammar=grammar))
|
||||
params._validate_structured_outputs(
|
||||
_StubModelConfig(),
|
||||
_StubModelConfig(), # type: ignore[arg-type]
|
||||
StructuredOutputsConfig(backend=backend),
|
||||
tokenizer=tokenizer or object(),
|
||||
tokenizer=tokenizer or object(), # type: ignore[arg-type]
|
||||
)
|
||||
assert params.structured_outputs is not None
|
||||
return params.structured_outputs
|
||||
|
||||
@@ -51,7 +51,7 @@ def make_vllm_config() -> VllmConfig:
|
||||
config = VllmConfig(
|
||||
structured_outputs_config=StructuredOutputsConfig(backend="xgrammar"),
|
||||
)
|
||||
config.model_config = SimpleNamespace(
|
||||
config.model_config = SimpleNamespace( # type: ignore[assignment]
|
||||
hf_config=SimpleNamespace(model_type="plamo3")
|
||||
)
|
||||
return config
|
||||
@@ -73,7 +73,7 @@ def test_plamo3_python_tokenizer_compiles_and_accepts_structural_tag():
|
||||
tokenizer = Plamo3Tokenizer(["<eos>", *call_tokens])
|
||||
backend = XgrammarBackend(
|
||||
make_vllm_config(),
|
||||
tokenizer=tokenizer,
|
||||
tokenizer=tokenizer, # type: ignore[arg-type]
|
||||
vocab_size=len(tokenizer.get_vocab()),
|
||||
)
|
||||
tools = [
|
||||
@@ -107,7 +107,7 @@ def test_plamo3_grammar_matches_decoded_bytes(value):
|
||||
tokenizer = Plamo3Tokenizer(list(dict.fromkeys(["<eos>", value, *pieces])))
|
||||
backend = XgrammarBackend(
|
||||
make_vllm_config(),
|
||||
tokenizer=tokenizer,
|
||||
tokenizer=tokenizer, # type: ignore[arg-type]
|
||||
vocab_size=len(tokenizer.get_vocab()),
|
||||
)
|
||||
for tokens in ([value], pieces):
|
||||
|
||||
@@ -10,9 +10,11 @@ from transformers import AutoTokenizer
|
||||
from vllm.config import DeviceConfig, StructuredOutputsConfig, VllmConfig
|
||||
from vllm.config.model import ModelConfig
|
||||
from vllm.config.speculative import SpeculativeConfig
|
||||
from vllm.config.structured_outputs import StructuredOutputsBackend
|
||||
from vllm.sampling_params import SamplingParams, StructuredOutputsParams
|
||||
from vllm.v1.request import Request
|
||||
from vllm.v1.structured_output import StructuredOutputManager
|
||||
from vllm.v1.structured_output.backend_outlines import OutlinesGrammar
|
||||
|
||||
TOKENIZER = "gpt2"
|
||||
THINK_END = "\n" # reasoning-end marker (single GPT-2 token)
|
||||
@@ -84,7 +86,7 @@ def _wait_for_grammar(request: Request) -> None:
|
||||
|
||||
def _build_harness(
|
||||
tokenizer,
|
||||
backend: str,
|
||||
backend: StructuredOutputsBackend,
|
||||
prefix: str = "",
|
||||
use_reasoner: bool = True,
|
||||
reasoning_ended: bool | None = None,
|
||||
@@ -106,13 +108,13 @@ def _build_harness(
|
||||
)
|
||||
manager = StructuredOutputManager(vllm_config)
|
||||
if use_reasoner:
|
||||
manager.reasoner_cls = MockReasoner
|
||||
manager.reasoner_cls = MockReasoner # type: ignore[assignment]
|
||||
|
||||
sampling_params = SamplingParams(
|
||||
structured_outputs=structured_outputs
|
||||
or StructuredOutputsParams(json=JSON_SCHEMA)
|
||||
)
|
||||
sampling_params.structured_outputs._backend = backend
|
||||
sampling_params.structured_outputs._backend = backend # type: ignore[union-attr]
|
||||
sampling_params.update_from_generation_config({}, tokenizer.eos_token_id)
|
||||
|
||||
prompt_ids = tokenizer.encode(prefix) if prefix else []
|
||||
@@ -130,9 +132,10 @@ def _build_harness(
|
||||
structured_req = request.structured_output_request
|
||||
assert request.prompt_token_ids is not None
|
||||
assert structured_req is not None
|
||||
assert structured_req.grammar is not None
|
||||
grammar = structured_req.grammar
|
||||
assert grammar is not None and not isinstance(grammar, Exception)
|
||||
if prompt_ids:
|
||||
assert structured_req.grammar.accept_tokens(
|
||||
assert grammar.accept_tokens(
|
||||
request.request_id,
|
||||
prompt_ids,
|
||||
)
|
||||
@@ -173,7 +176,7 @@ def _run_real_flow(
|
||||
structured_req = request.structured_output_request
|
||||
assert structured_req is not None
|
||||
grammar = structured_req.grammar
|
||||
assert grammar is not None
|
||||
assert grammar is not None and not isinstance(grammar, Exception)
|
||||
assert not grammar.is_terminated()
|
||||
# `bitmask[i]` is the grammar state after the first `i` scheduled tokens.
|
||||
# These tests commit the validated prefix, so the matching post-accept
|
||||
@@ -335,7 +338,7 @@ FLOW_CASES = [
|
||||
@pytest.mark.parametrize("case", FLOW_CASES)
|
||||
def test_real_flow(
|
||||
tokenizer,
|
||||
backend: str,
|
||||
backend: StructuredOutputsBackend,
|
||||
case: FlowCase,
|
||||
):
|
||||
if backend == "guidance" and case.xfail_guidance:
|
||||
@@ -379,7 +382,7 @@ def test_real_flow(
|
||||
)
|
||||
def test_initial_constraint_activation(
|
||||
tokenizer,
|
||||
backend: str,
|
||||
backend: StructuredOutputsBackend,
|
||||
use_reasoner: bool,
|
||||
reasoning_ended: bool | None,
|
||||
enable_in_reasoning: bool,
|
||||
@@ -431,7 +434,7 @@ def test_initial_constraint_activation(
|
||||
)
|
||||
def test_regex_flow(
|
||||
tokenizer,
|
||||
backend: str,
|
||||
backend: StructuredOutputsBackend,
|
||||
raw_drafts: tuple[str, ...],
|
||||
expected_validated: tuple[str, ...] | None,
|
||||
expected_row_pattern: str,
|
||||
@@ -459,7 +462,9 @@ def test_regex_flow(
|
||||
|
||||
|
||||
@pytest.mark.parametrize("backend", REGEX_BACKENDS)
|
||||
def test_rejected_draft_keeps_later_rows_constrained(tokenizer, backend: str):
|
||||
def test_rejected_draft_keeps_later_rows_constrained(
|
||||
tokenizer, backend: StructuredOutputsBackend
|
||||
):
|
||||
"""A draft the grammar rejects during bitmask fill must not unconstrain
|
||||
the remaining rows or the bonus row."""
|
||||
manager, request = _build_harness(
|
||||
@@ -492,7 +497,7 @@ def test_outlines_termination(tokenizer):
|
||||
structured_req = request.structured_output_request
|
||||
assert structured_req is not None
|
||||
grammar = structured_req.grammar
|
||||
assert grammar is not None
|
||||
assert isinstance(grammar, OutlinesGrammar)
|
||||
one, eos = _to_token_ids(tokenizer, ("1", EOS))
|
||||
|
||||
assert not grammar.accept_tokens(request.request_id, [eos])
|
||||
|
||||
@@ -35,7 +35,7 @@ def test_structured_outputs_rejected_for_diffusion_models():
|
||||
)
|
||||
with pytest.raises(VLLMValidationError, match="not yet supported for diffusion"):
|
||||
params._validate_structured_outputs(
|
||||
_StubModelConfig(is_diffusion=True),
|
||||
_StubModelConfig(is_diffusion=True), # type: ignore[arg-type]
|
||||
StructuredOutputsConfig(),
|
||||
tokenizer=None,
|
||||
)
|
||||
@@ -45,7 +45,7 @@ def test_plain_request_allowed_for_diffusion_models():
|
||||
"""Requests without structured outputs are unaffected by the guard."""
|
||||
params = SamplingParams()
|
||||
params._validate_structured_outputs(
|
||||
_StubModelConfig(is_diffusion=True),
|
||||
_StubModelConfig(is_diffusion=True), # type: ignore[arg-type]
|
||||
StructuredOutputsConfig(),
|
||||
tokenizer=None,
|
||||
)
|
||||
@@ -71,9 +71,9 @@ def test_degenerate_structured_outputs_rejected(structured_outputs, match):
|
||||
params = SamplingParams(structured_outputs=structured_outputs)
|
||||
with pytest.raises(VLLMValidationError, match=match):
|
||||
params._validate_structured_outputs(
|
||||
_StubModelConfig(is_diffusion=False),
|
||||
_StubModelConfig(is_diffusion=False), # type: ignore[arg-type]
|
||||
StructuredOutputsConfig(),
|
||||
tokenizer=object(),
|
||||
tokenizer=object(), # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
|
||||
@@ -97,9 +97,9 @@ def test_regex_with_nul_byte_rejected(regex):
|
||||
# (which would otherwise catch the error and fall back to another backend).
|
||||
with pytest.raises(VLLMValidationError, match="NUL"):
|
||||
params._validate_structured_outputs(
|
||||
_StubModelConfig(is_diffusion=False),
|
||||
_StubModelConfig(is_diffusion=False), # type: ignore[arg-type]
|
||||
StructuredOutputsConfig(),
|
||||
tokenizer=object(),
|
||||
tokenizer=object(), # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
# The xgrammar backend also rejects it directly (defense in depth), before
|
||||
@@ -133,9 +133,9 @@ def test_unsupported_grammar_is_a_client_error(backend, structured_outputs):
|
||||
params = SamplingParams(structured_outputs=structured_outputs)
|
||||
with pytest.raises(VLLMClientError):
|
||||
params._validate_structured_outputs(
|
||||
_StubModelConfig(is_diffusion=False),
|
||||
_StubModelConfig(is_diffusion=False), # type: ignore[arg-type]
|
||||
StructuredOutputsConfig(backend=backend),
|
||||
tokenizer=object(),
|
||||
tokenizer=object(), # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
|
||||
@@ -180,8 +180,9 @@ def test_auto_backend_falls_back_on_unsupported_schema(schema, expected_backend)
|
||||
"""`auto` falls back on rejection, so it must catch what the validators raise."""
|
||||
params = SamplingParams(structured_outputs=StructuredOutputsParams(json=schema))
|
||||
params._validate_structured_outputs(
|
||||
_StubModelConfig(is_diffusion=False),
|
||||
_StubModelConfig(is_diffusion=False), # type: ignore[arg-type]
|
||||
StructuredOutputsConfig(backend="auto"),
|
||||
tokenizer=object(),
|
||||
tokenizer=object(), # type: ignore[arg-type]
|
||||
)
|
||||
assert params.structured_outputs is not None
|
||||
assert params.structured_outputs._backend == expected_backend
|
||||
+15
-17
@@ -31,24 +31,37 @@ SILENT_GROUPS = [
|
||||
"tests/compile/correctness_e2e",
|
||||
"tests/compile/fullgraph",
|
||||
"tests/compile/fusions_e2e",
|
||||
"tests/compile/passes",
|
||||
"tests/config",
|
||||
"tests/entrypoints/generate",
|
||||
"tests/entrypoints/serve",
|
||||
"tests/entrypoints/tool_parsers",
|
||||
"tests/entrypoints/unit_tests",
|
||||
"tests/entrypoints/weight_transfer",
|
||||
"tests/kernels/core",
|
||||
"tests/kernels/mamba",
|
||||
"tests/kernels/quantization",
|
||||
"tests/model_executor/layers",
|
||||
"tests/models/language",
|
||||
"tests/models/quantization",
|
||||
"tests/plugins/bge_m3_sparse_plugin",
|
||||
"tests/plugins/prithvi_io_processor_plugin",
|
||||
"tests/plugins/vllm_add_dummy_platform",
|
||||
"tests/plugins/vllm_add_dummy_stat_logger",
|
||||
"tests/plugins_tests/gguf",
|
||||
"tests/plugins_tests/lora_resolvers",
|
||||
"tests/plugins_tests",
|
||||
"tests/samplers",
|
||||
"tests/spec_decode",
|
||||
"tests/tokenizers_",
|
||||
"tests/tool_use",
|
||||
"tests/transformers_utils",
|
||||
"tests/utils_",
|
||||
"tests/v1/cudagraph",
|
||||
"tests/v1/determinism",
|
||||
"tests/v1/distributed",
|
||||
"tests/v1/executor",
|
||||
"tests/v1/shutdown",
|
||||
"tests/v1/simple_kv_offload",
|
||||
"tests/v1/structured_output",
|
||||
]
|
||||
|
||||
# After fixing errors resulting from changing follow_imports
|
||||
@@ -57,57 +70,42 @@ SEPARATE_GROUPS = [
|
||||
"tests",
|
||||
"tests/benchmarks",
|
||||
"tests/compile",
|
||||
"tests/compile/passes",
|
||||
"tests/distributed",
|
||||
"tests/entrypoints/anthropic",
|
||||
"tests/entrypoints/llm",
|
||||
"tests/entrypoints/multimodal",
|
||||
"tests/entrypoints/openai",
|
||||
"tests/entrypoints/pooling",
|
||||
"tests/entrypoints/serve",
|
||||
"tests/entrypoints/speech_to_text",
|
||||
"tests/entrypoints/unit_tests",
|
||||
"tests/kernels",
|
||||
"tests/kernels/attention",
|
||||
"tests/kernels/helion",
|
||||
"tests/kernels/moe",
|
||||
"tests/kernels/quantization",
|
||||
"tests/lora",
|
||||
"tests/model_executor",
|
||||
"tests/model_executor/layers",
|
||||
"tests/model_executor/model_loader",
|
||||
"tests/models",
|
||||
"tests/models/test_initialization.py",
|
||||
"tests/models/multimodal",
|
||||
"tests/multimodal",
|
||||
"tests/parser",
|
||||
"tests/plugins_tests",
|
||||
"tests/quantization",
|
||||
"tests/reasoning",
|
||||
"tests/renderers",
|
||||
"tests/samplers",
|
||||
"tests/tokenizers_",
|
||||
"tests/tool_parsers",
|
||||
"tests/tool_use",
|
||||
"tests/utils_",
|
||||
"tests/v1",
|
||||
"tests/v1/attention",
|
||||
"tests/v1/core",
|
||||
"tests/v1/cudagraph",
|
||||
"tests/v1/determinism",
|
||||
"tests/v1/e2e",
|
||||
"tests/v1/ec_connector",
|
||||
"tests/v1/engine",
|
||||
"tests/v1/executor",
|
||||
"tests/v1/kv_connector",
|
||||
"tests/v1/kv_offload",
|
||||
"tests/v1/logits_processors",
|
||||
"tests/v1/metrics",
|
||||
"tests/v1/sample",
|
||||
"tests/v1/simple_kv_offload",
|
||||
"tests/v1/spec_decode",
|
||||
"tests/v1/streaming_input",
|
||||
"tests/v1/structured_output",
|
||||
"tests/v1/worker",
|
||||
]
|
||||
|
||||
|
||||
Reference in new issue
Block a user