Unverified Commit 4e256cad authored by Harry Mellor's avatar Harry Mellor Committed by GitHub
Browse files

Remove all references to `yapf` as it's no longer used (#26251)


Signed-off-by: default avatarHarry Mellor <19981378+hmellor@users.noreply.github.com>
parent d6953beb
This diff is collapsed.
...@@ -71,25 +71,27 @@ def _dummy_items( ...@@ -71,25 +71,27 @@ def _dummy_items(
) )
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
("item", "expected_size"), ("item", "expected_size"),
[ [
(_dummy_item("a", {"a1": 100}), 100), (_dummy_item("a", {"a1": 100}), 100),
(_dummy_item("a", {"a1": 100, "a2": 110}), 210), (_dummy_item("a", {"a1": 100, "a2": 110}), 210),
(_dummy_items({"a": {"a1": 100, "a2": 110}, "b": {"b1": 120, "b2": 130}}), 460), # noqa: E501 (_dummy_items({"a": {"a1": 100, "a2": 110}, "b": {"b1": 120, "b2": 130}}), 460), # noqa: E501
(_dummy_items({"a": {"a1": 100, "a2": 110}, "b": {"b1": 120, "b2": 130}}).get_data(), 460), # noqa: E501 (
_dummy_items(
{"a": {"a1": 100, "a2": 110}, "b": {"b1": 120, "b2": 130}}
).get_data(),
460,
), # noqa: E501
], ],
) )
# yapf: enable
def test_cache_item_size(item, expected_size): def test_cache_item_size(item, expected_size):
cache = MultiModalCache.get_lru_cache(2048, type(item)) cache = MultiModalCache.get_lru_cache(2048, type(item))
cache[""] = item cache[""] = item
assert cache.currsize == expected_size assert cache.currsize == expected_size
prompt_update = PromptInsertion("dummy", "target", "insertion") \ prompt_update = PromptInsertion("dummy", "target", "insertion").resolve(0)
.resolve(0)
cache[""] = MultiModalProcessorCacheItem(item, [prompt_update]) cache[""] = MultiModalProcessorCacheItem(item, [prompt_update])
assert cache.currsize == expected_size assert cache.currsize == expected_size
...@@ -106,9 +108,9 @@ def _create_vllm_config( ...@@ -106,9 +108,9 @@ def _create_vllm_config(
return VllmConfig( return VllmConfig(
model_config=ModelConfig( model_config=ModelConfig(
model="llava-hf/llava-onevision-qwen2-0.5b-ov-hf", model="llava-hf/llava-onevision-qwen2-0.5b-ov-hf",
mm_processor_cache_gb=mm_processor_cache_gb), mm_processor_cache_gb=mm_processor_cache_gb,
parallel_config=ParallelConfig( ),
data_parallel_size=1 if enable_ipc else 2), parallel_config=ParallelConfig(data_parallel_size=1 if enable_ipc else 2),
) )
...@@ -124,11 +126,9 @@ def _compare_caches( ...@@ -124,11 +126,9 @@ def _compare_caches(
seed: int = 0, seed: int = 0,
): ):
cache_0_p0 = processor_cache_from_config(config_0, MULTIMODAL_REGISTRY) cache_0_p0 = processor_cache_from_config(config_0, MULTIMODAL_REGISTRY)
cache_0_p1 = engine_receiver_cache_from_config(config_0, cache_0_p1 = engine_receiver_cache_from_config(config_0, MULTIMODAL_REGISTRY)
MULTIMODAL_REGISTRY)
cache_1_p0 = processor_cache_from_config(config_1, MULTIMODAL_REGISTRY) cache_1_p0 = processor_cache_from_config(config_1, MULTIMODAL_REGISTRY)
cache_1_p1 = engine_receiver_cache_from_config(config_1, cache_1_p1 = engine_receiver_cache_from_config(config_1, MULTIMODAL_REGISTRY)
MULTIMODAL_REGISTRY)
cache_size_gb = max( cache_size_gb = max(
config_0.model_config.multimodal_config.mm_processor_cache_gb, config_0.model_config.multimodal_config.mm_processor_cache_gb,
...@@ -142,8 +142,7 @@ def _compare_caches( ...@@ -142,8 +142,7 @@ def _compare_caches(
for _ in range(int(item_capacity / hit_rate)) for _ in range(int(item_capacity / hit_rate))
] ]
all_hashes = [ all_hashes = [
MultiModalHasher.hash_kwargs(item=item.get_data()) MultiModalHasher.hash_kwargs(item=item.get_data()) for item in all_items
for item in all_items
] ]
# Should not be used since there is nothing to convert to text # Should not be used since there is nothing to convert to text
...@@ -162,7 +161,8 @@ def _compare_caches( ...@@ -162,7 +161,8 @@ def _compare_caches(
for _ in range(is_cached_calls_per_iter): for _ in range(is_cached_calls_per_iter):
cache_0_p0.is_cached(selected_hashes) cache_0_p0.is_cached(selected_hashes)
cache_0_p0_out = [ cache_0_p0_out = [
item for item, _ in cache_0_p0.get_and_update( item
for item, _ in cache_0_p0.get_and_update(
[(item, prompt_update.content) for item in selected_items], [(item, prompt_update.content) for item in selected_items],
selected_hashes, selected_hashes,
) )
...@@ -174,7 +174,8 @@ def _compare_caches( ...@@ -174,7 +174,8 @@ def _compare_caches(
for _ in range(is_cached_calls_per_iter): for _ in range(is_cached_calls_per_iter):
cache_1_p0.is_cached(selected_hashes) cache_1_p0.is_cached(selected_hashes)
cache_1_p0_out = [ cache_1_p0_out = [
item for item, _ in cache_1_p0.get_and_update( item
for item, _ in cache_1_p0.get_and_update(
[(item, prompt_update.content) for item in selected_items], [(item, prompt_update.content) for item in selected_items],
selected_hashes, selected_hashes,
) )
...@@ -183,14 +184,12 @@ def _compare_caches( ...@@ -183,14 +184,12 @@ def _compare_caches(
if cache_0_p1 is None: if cache_0_p1 is None:
cache_0_p1_out = cache_0_p0_out cache_0_p1_out = cache_0_p0_out
else: else:
cache_0_p1_out = cache_0_p1.get_and_update(cache_0_p0_out, cache_0_p1_out = cache_0_p1.get_and_update(cache_0_p0_out, selected_hashes)
selected_hashes)
if cache_1_p1 is None: if cache_1_p1 is None:
cache_1_p1_out = cache_1_p0_out cache_1_p1_out = cache_1_p0_out
else: else:
cache_1_p1_out = cache_1_p1.get_and_update(cache_1_p0_out, cache_1_p1_out = cache_1_p1.get_and_update(cache_1_p0_out, selected_hashes)
selected_hashes)
assert cache_0_p1_out == cache_1_p1_out, f"Failed at {it=}" assert cache_0_p1_out == cache_1_p1_out, f"Failed at {it=}"
......
...@@ -9,9 +9,6 @@ import pytest ...@@ -9,9 +9,6 @@ import pytest
from vllm.config import ModelConfig from vllm.config import ModelConfig
from vllm.multimodal import MULTIMODAL_REGISTRY from vllm.multimodal import MULTIMODAL_REGISTRY
# yapf conflicts with isort for this block
# yapf: disable
from vllm.multimodal.processing import ( from vllm.multimodal.processing import (
InputProcessingContext, InputProcessingContext,
PlaceholderFeaturesInfo, PlaceholderFeaturesInfo,
...@@ -24,8 +21,6 @@ from vllm.multimodal.processing import ( ...@@ -24,8 +21,6 @@ from vllm.multimodal.processing import (
iter_token_matches, iter_token_matches,
replace_token_matches, replace_token_matches,
) )
# yapf: enable
from vllm.multimodal.profiling import MultiModalProfiler from vllm.multimodal.profiling import MultiModalProfiler
from vllm.transformers_utils.tokenizer import AnyTokenizer from vllm.transformers_utils.tokenizer import AnyTokenizer
...@@ -34,7 +29,6 @@ from .utils import random_image ...@@ -34,7 +29,6 @@ from .utils import random_image
pytestmark = pytest.mark.cpu_test pytestmark = pytest.mark.cpu_test
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
("token_ids", "match_ids", "expected"), ("token_ids", "match_ids", "expected"),
[ [
...@@ -44,34 +38,34 @@ pytestmark = pytest.mark.cpu_test ...@@ -44,34 +38,34 @@ pytestmark = pytest.mark.cpu_test
[32000, 32000, 32000], [32000, 32000, 32000],
[32000], [32000],
[ [
{ "start_idx": 0, "end_idx": 1 }, {"start_idx": 0, "end_idx": 1},
{ "start_idx": 1, "end_idx": 2 }, {"start_idx": 1, "end_idx": 2},
{ "start_idx": 2, "end_idx": 3 }, {"start_idx": 2, "end_idx": 3},
], ],
), ),
( (
[32000, 32000, 32000], [32000, 32000, 32000],
[32000, 32000], [32000, 32000],
[{ "start_idx": 0, "end_idx": 2 }], [{"start_idx": 0, "end_idx": 2}],
), ),
( (
[32000, 32000, 32000], [32000, 32000, 32000],
[32000, 32000, 32000], [32000, 32000, 32000],
[{ "start_idx": 0, "end_idx": 3 }], [{"start_idx": 0, "end_idx": 3}],
), ),
( (
[9833, 28747, 32000, 32000, 32000, 9833, 28747, 32000, 32000, 918], [9833, 28747, 32000, 32000, 32000, 9833, 28747, 32000, 32000, 918],
[28747, 32000], [28747, 32000],
[ [
{ "start_idx": 1, "end_idx": 3 }, {"start_idx": 1, "end_idx": 3},
{ "start_idx": 6, "end_idx": 8 }, {"start_idx": 6, "end_idx": 8},
], ],
), ),
( (
[9833, 28747, 32000, 32000, 32000, 9833, 28747, 32000, 32000, 918], [9833, 28747, 32000, 32000, 32000, 9833, 28747, 32000, 32000, 918],
[28747, 32000, 32000, 32000], [28747, 32000, 32000, 32000],
[ [
{ "start_idx": 1, "end_idx": 5 }, {"start_idx": 1, "end_idx": 5},
], ],
), ),
( (
...@@ -82,14 +76,13 @@ pytestmark = pytest.mark.cpu_test ...@@ -82,14 +76,13 @@ pytestmark = pytest.mark.cpu_test
], ],
) )
@pytest.mark.parametrize("start_idx", [0, 4, 8]) @pytest.mark.parametrize("start_idx", [0, 4, 8])
# yapf: enable
def test_iter_token_matches(token_ids, match_ids, expected, start_idx): def test_iter_token_matches(token_ids, match_ids, expected, start_idx):
result = list(iter_token_matches(token_ids, match_ids, result = list(iter_token_matches(token_ids, match_ids, start_idx=start_idx))
start_idx=start_idx))
# Manually constructed results # Manually constructed results
assert [item._asdict() for item in result assert [item._asdict() for item in result] == [
] == [item for item in expected if item["start_idx"] >= start_idx] item for item in expected if item["start_idx"] >= start_idx
]
# Invariants # Invariants
match_lens = [end - start for start, end in result] match_lens = [end - start for start, end in result]
...@@ -97,7 +90,6 @@ def test_iter_token_matches(token_ids, match_ids, expected, start_idx): ...@@ -97,7 +90,6 @@ def test_iter_token_matches(token_ids, match_ids, expected, start_idx):
assert all(match_len == len(match_ids) for match_len in match_lens) assert all(match_len == len(match_ids) for match_len in match_lens)
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
("token_ids", "match_ids", "new_ids", "expected"), ("token_ids", "match_ids", "new_ids", "expected"),
[ [
...@@ -141,7 +133,6 @@ def test_iter_token_matches(token_ids, match_ids, expected, start_idx): ...@@ -141,7 +133,6 @@ def test_iter_token_matches(token_ids, match_ids, expected, start_idx):
), ),
], ],
) )
# yapf: enable
def test_replace_token_matches(token_ids, match_ids, new_ids, expected): def test_replace_token_matches(token_ids, match_ids, new_ids, expected):
result = replace_token_matches(token_ids, match_ids, new_ids) result = replace_token_matches(token_ids, match_ids, new_ids)
...@@ -149,7 +140,6 @@ def test_replace_token_matches(token_ids, match_ids, new_ids, expected): ...@@ -149,7 +140,6 @@ def test_replace_token_matches(token_ids, match_ids, new_ids, expected):
assert result == expected assert result == expected
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
("prompt", "target_by_key", "expected_by_key"), ("prompt", "target_by_key", "expected_by_key"),
[ [
...@@ -166,11 +156,11 @@ def test_replace_token_matches(token_ids, match_ids, new_ids, expected): ...@@ -166,11 +156,11 @@ def test_replace_token_matches(token_ids, match_ids, new_ids, expected):
"pattern_1": [], "pattern_1": [],
"pattern_2": [], "pattern_2": [],
"pattern_3": [ "pattern_3": [
{ "start_idx": 0, "end_idx": 0 }, {"start_idx": 0, "end_idx": 0},
], ],
"pattern_4": [], "pattern_4": [],
"pattern_5": [ "pattern_5": [
{ "start_idx": 0, "end_idx": 0 }, {"start_idx": 0, "end_idx": 0},
], ],
}, },
), ),
...@@ -186,26 +176,26 @@ def test_replace_token_matches(token_ids, match_ids, new_ids, expected): ...@@ -186,26 +176,26 @@ def test_replace_token_matches(token_ids, match_ids, new_ids, expected):
}, },
{ {
"pattern_1": [ "pattern_1": [
{ "start_idx": 0, "end_idx": 1 }, {"start_idx": 0, "end_idx": 1},
{ "start_idx": 1, "end_idx": 2 }, {"start_idx": 1, "end_idx": 2},
{ "start_idx": 2, "end_idx": 3 }, {"start_idx": 2, "end_idx": 3},
{ "start_idx": 3, "end_idx": 4 }, {"start_idx": 3, "end_idx": 4},
], ],
"pattern_2": [ "pattern_2": [
{ "start_idx": 0, "end_idx": 2 }, {"start_idx": 0, "end_idx": 2},
{ "start_idx": 2, "end_idx": 4 }, {"start_idx": 2, "end_idx": 4},
], ],
"pattern_3": [ "pattern_3": [
{ "start_idx": 0, "end_idx": 3 }, {"start_idx": 0, "end_idx": 3},
], ],
"pattern_4": [ "pattern_4": [
{ "start_idx": 0, "end_idx": 0 }, {"start_idx": 0, "end_idx": 0},
], ],
"pattern_5": [ "pattern_5": [
{ "start_idx": 1, "end_idx": 1 }, {"start_idx": 1, "end_idx": 1},
], ],
"pattern_6": [ "pattern_6": [
{ "start_idx": 4, "end_idx": 4 }, {"start_idx": 4, "end_idx": 4},
], ],
}, },
), ),
...@@ -221,26 +211,25 @@ def test_replace_token_matches(token_ids, match_ids, new_ids, expected): ...@@ -221,26 +211,25 @@ def test_replace_token_matches(token_ids, match_ids, new_ids, expected):
}, },
{ {
"pattern_1": [ "pattern_1": [
{ "start_idx": 1, "end_idx": 3 }, {"start_idx": 1, "end_idx": 3},
{ "start_idx": 6, "end_idx": 8 }, {"start_idx": 6, "end_idx": 8},
], ],
"pattern_2": [ "pattern_2": [
{ "start_idx": 1, "end_idx": 5 }, {"start_idx": 1, "end_idx": 5},
], ],
"pattern_3": [], "pattern_3": [],
"pattern_4": [ "pattern_4": [
{ "start_idx": 0, "end_idx": 0 }, {"start_idx": 0, "end_idx": 0},
], ],
"pattern_5": [], "pattern_5": [],
"pattern_6": [ "pattern_6": [
{ "start_idx": 10, "end_idx": 10 }, {"start_idx": 10, "end_idx": 10},
], ],
}, },
), ),
], ],
) )
@pytest.mark.parametrize("update_type", [PromptInsertion, PromptReplacement]) @pytest.mark.parametrize("update_type", [PromptInsertion, PromptReplacement])
# yapf: enable
def test_find_token_matches( def test_find_token_matches(
prompt, prompt,
target_by_key, target_by_key,
...@@ -272,7 +261,6 @@ def test_find_token_matches( ...@@ -272,7 +261,6 @@ def test_find_token_matches(
} == expected_by_key } == expected_by_key
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
("prompt", "target_by_key", "expected_by_key"), ("prompt", "target_by_key", "expected_by_key"),
[ [
...@@ -288,16 +276,16 @@ def test_find_token_matches( ...@@ -288,16 +276,16 @@ def test_find_token_matches(
"pattern_5": PromptIndexTargets.end(), "pattern_5": PromptIndexTargets.end(),
}, },
{ {
"pattern_1": [{ "start_idx": 0, "end_idx": 0 }], "pattern_1": [{"start_idx": 0, "end_idx": 0}],
"pattern_2": [], "pattern_2": [],
"pattern_3": [ "pattern_3": [
{ "start_idx": 0, "end_idx": 0 }, {"start_idx": 0, "end_idx": 0},
], ],
"pattern_4": [], "pattern_4": [],
"pattern_5": [ "pattern_5": [
{ "start_idx": 0, "end_idx": 0 }, {"start_idx": 0, "end_idx": 0},
], ],
} },
), ),
( (
"<image><image><image><image>", "<image><image><image><image>",
...@@ -311,26 +299,26 @@ def test_find_token_matches( ...@@ -311,26 +299,26 @@ def test_find_token_matches(
}, },
{ {
"pattern_1": [ "pattern_1": [
{ "start_idx": 0, "end_idx": 7 }, {"start_idx": 0, "end_idx": 7},
{ "start_idx": 7, "end_idx": 14 }, {"start_idx": 7, "end_idx": 14},
{ "start_idx": 14, "end_idx": 21 }, {"start_idx": 14, "end_idx": 21},
{ "start_idx": 21, "end_idx": 28 }, {"start_idx": 21, "end_idx": 28},
], ],
"pattern_2": [ "pattern_2": [
{ "start_idx": 0, "end_idx": 14 }, {"start_idx": 0, "end_idx": 14},
{ "start_idx": 14, "end_idx": 28 }, {"start_idx": 14, "end_idx": 28},
], ],
"pattern_3": [ "pattern_3": [
{ "start_idx": 0, "end_idx": 21 }, {"start_idx": 0, "end_idx": 21},
], ],
"pattern_4": [ "pattern_4": [
{ "start_idx": 0, "end_idx": 0 }, {"start_idx": 0, "end_idx": 0},
], ],
"pattern_5": [ "pattern_5": [
{ "start_idx": 7, "end_idx": 7 }, {"start_idx": 7, "end_idx": 7},
], ],
"pattern_6": [ "pattern_6": [
{ "start_idx": 28, "end_idx": 28 }, {"start_idx": 28, "end_idx": 28},
], ],
}, },
), ),
...@@ -346,21 +334,21 @@ def test_find_token_matches( ...@@ -346,21 +334,21 @@ def test_find_token_matches(
}, },
{ {
"pattern_1": [ "pattern_1": [
{ "start_idx": 0, "end_idx": 13 }, {"start_idx": 0, "end_idx": 13},
{ "start_idx": 27, "end_idx": 40 }, {"start_idx": 27, "end_idx": 40},
], ],
"pattern_2": [ "pattern_2": [
{ "start_idx": 0, "end_idx": 27 }, {"start_idx": 0, "end_idx": 27},
], ],
"pattern_3": [], "pattern_3": [],
"pattern_4": [ "pattern_4": [
{ "start_idx": 0, "end_idx": 0 }, {"start_idx": 0, "end_idx": 0},
], ],
"pattern_5": [ "pattern_5": [
{ "start_idx": 13, "end_idx": 13 }, {"start_idx": 13, "end_idx": 13},
], ],
"pattern_6": [ "pattern_6": [
{ "start_idx": 48, "end_idx": 48 }, {"start_idx": 48, "end_idx": 48},
], ],
}, },
), ),
...@@ -374,22 +362,21 @@ def test_find_token_matches( ...@@ -374,22 +362,21 @@ def test_find_token_matches(
}, },
{ {
"pattern_1": [ "pattern_1": [
{ "start_idx": 0, "end_idx": 9 }, {"start_idx": 0, "end_idx": 9},
{ "start_idx": 16, "end_idx": 25 }, {"start_idx": 16, "end_idx": 25},
], ],
"pattern_2": [ "pattern_2": [
{ "start_idx": 0, "end_idx": 16 }, {"start_idx": 0, "end_idx": 16},
{ "start_idx": 16, "end_idx": 32 }, {"start_idx": 16, "end_idx": 32},
], ],
"pattern_3": [ "pattern_3": [
{ "start_idx": 0, "end_idx": 25 }, {"start_idx": 0, "end_idx": 25},
], ],
}, },
), ),
], ],
) )
@pytest.mark.parametrize("update_type", [PromptInsertion, PromptReplacement]) @pytest.mark.parametrize("update_type", [PromptInsertion, PromptReplacement])
# yapf: enable
def test_find_text_matches( def test_find_text_matches(
prompt, prompt,
target_by_key, target_by_key,
...@@ -421,7 +408,6 @@ def test_find_text_matches( ...@@ -421,7 +408,6 @@ def test_find_text_matches(
} == expected_by_key } == expected_by_key
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
("prompt", "target_by_key", "repl_by_key", "expected_by_update_type_mm_count"), # noqa: E501 ("prompt", "target_by_key", "repl_by_key", "expected_by_update_type_mm_count"), # noqa: E501
[ [
...@@ -549,9 +535,8 @@ def test_find_text_matches( ...@@ -549,9 +535,8 @@ def test_find_text_matches(
}, },
}, },
), ),
] ],
) )
# yapf: enable
def test_find_update_text( def test_find_update_text(
prompt, prompt,
target_by_key, target_by_key,
...@@ -562,13 +547,15 @@ def test_find_update_text( ...@@ -562,13 +547,15 @@ def test_find_update_text(
mock_tokenizer = cast(AnyTokenizer, object()) mock_tokenizer = cast(AnyTokenizer, object())
for ( for (
update_type, update_type,
expected_by_mm_count, expected_by_mm_count,
) in expected_by_update_type_mm_count.items(): ) in expected_by_update_type_mm_count.items():
for mm_count, expected in expected_by_mm_count.items(): for mm_count, expected in expected_by_mm_count.items():
mm_prompt_updates = { mm_prompt_updates = {
key: [[update_type(key, target, repl_by_key[key]).resolve(i)] key: [
for i in range(mm_count)] [update_type(key, target, repl_by_key[key]).resolve(i)]
for i in range(mm_count)
]
for key, target in target_by_key.items() for key, target in target_by_key.items()
} }
...@@ -589,7 +576,6 @@ def test_find_update_text( ...@@ -589,7 +576,6 @@ def test_find_update_text(
assert new_prompt == expected assert new_prompt == expected
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
("prompt", "target_by_key", "repl_by_key", "expected_by_update_type_mm_count"), # noqa: E501 ("prompt", "target_by_key", "repl_by_key", "expected_by_update_type_mm_count"), # noqa: E501
[ [
...@@ -615,8 +601,43 @@ def test_find_update_text( ...@@ -615,8 +601,43 @@ def test_find_update_text(
{ {
PromptInsertion: { PromptInsertion: {
0: [1, 9833, 28747, 32000, 9833, 28747, 32000, 32000, 918], 0: [1, 9833, 28747, 32000, 9833, 28747, 32000, 32000, 918],
1: [1, 9833, 28747, 32000, 32000, 32000, 9833, 28747, 32000, 32000, 918, 1550, 918, 1550], # noqa: E501 1: [
2: [1, 9833, 28747, 32000, 32000, 32000, 32000, 32000, 9833, 28747, 32000, 32000, 918, 1550, 918, 1550, 1550, 918, 1550], # noqa: E501 1,
9833,
28747,
32000,
32000,
32000,
9833,
28747,
32000,
32000,
918,
1550,
918,
1550,
], # noqa: E501
2: [
1,
9833,
28747,
32000,
32000,
32000,
32000,
32000,
9833,
28747,
32000,
32000,
918,
1550,
918,
1550,
1550,
918,
1550,
], # noqa: E501
}, },
PromptReplacement: { PromptReplacement: {
0: [1, 9833, 28747, 32000, 9833, 28747, 32000, 32000, 918], 0: [1, 9833, 28747, 32000, 9833, 28747, 32000, 32000, 918],
...@@ -719,9 +740,8 @@ def test_find_update_text( ...@@ -719,9 +740,8 @@ def test_find_update_text(
}, },
}, },
), ),
] ],
) )
# yapf: enable
def test_find_update_tokens( def test_find_update_tokens(
prompt, prompt,
target_by_key, target_by_key,
...@@ -732,13 +752,15 @@ def test_find_update_tokens( ...@@ -732,13 +752,15 @@ def test_find_update_tokens(
mock_tokenizer = cast(AnyTokenizer, object()) mock_tokenizer = cast(AnyTokenizer, object())
for ( for (
update_type, update_type,
expected_by_mm_count, expected_by_mm_count,
) in expected_by_update_type_mm_count.items(): ) in expected_by_update_type_mm_count.items():
for mm_count, expected in expected_by_mm_count.items(): for mm_count, expected in expected_by_mm_count.items():
mm_prompt_updates = { mm_prompt_updates = {
key: [[update_type(key, target, repl_by_key[key]).resolve(i)] key: [
for i in range(mm_count)] [update_type(key, target, repl_by_key[key]).resolve(i)]
for i in range(mm_count)
]
for key, target in target_by_key.items() for key, target in target_by_key.items()
} }
...@@ -759,7 +781,6 @@ def test_find_update_tokens( ...@@ -759,7 +781,6 @@ def test_find_update_tokens(
assert new_prompt == expected assert new_prompt == expected
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
"repl_by_key", "repl_by_key",
[ [
...@@ -796,8 +817,7 @@ def test_find_update_tokens( ...@@ -796,8 +817,7 @@ def test_find_update_tokens(
is_embed=None, is_embed=None,
), ),
], ],
} },
), ),
( (
[1, 32000, 32000, 9833, 28747, 32000, 32000, 1550, 918, 1550], [1, 32000, 32000, 9833, 28747, 32000, 32000, 1550, 918, 1550],
...@@ -828,7 +848,7 @@ def test_find_update_tokens( ...@@ -828,7 +848,7 @@ def test_find_update_tokens(
), ),
], ],
# No match for pattern_4 as it has lower priority than pattern_1 # No match for pattern_4 as it has lower priority than pattern_1
} },
), ),
( (
[1, 32000, 32000, 32000, 32000, 32000, 1550, 918, 1550], [1, 32000, 32000, 32000, 32000, 32000, 1550, 918, 1550],
...@@ -867,12 +887,11 @@ def test_find_update_tokens( ...@@ -867,12 +887,11 @@ def test_find_update_tokens(
is_embed=None, is_embed=None,
), ),
], ],
} },
), ),
] ],
) )
@pytest.mark.parametrize("update_type", [PromptInsertion, PromptReplacement]) @pytest.mark.parametrize("update_type", [PromptInsertion, PromptReplacement])
# yapf: enable
def test_find_mm_placeholders( def test_find_mm_placeholders(
repl_by_key, repl_by_key,
prompt, prompt,
...@@ -899,8 +918,15 @@ def test_find_mm_placeholders( ...@@ -899,8 +918,15 @@ def test_find_mm_placeholders(
@pytest.mark.parametrize("model_id", ["llava-hf/llava-v1.6-mistral-7b-hf"]) @pytest.mark.parametrize("model_id", ["llava-hf/llava-v1.6-mistral-7b-hf"])
@pytest.mark.parametrize( @pytest.mark.parametrize(
("limit", "num_supported", "is_valid"), ("limit", "num_supported", "is_valid"),
[(0, 0, True), (0, 1, True), (1, 0, False), (1, 1, True), (1, 2, True), [
(2, 1, False), (2, 2, True)], (0, 0, True),
(0, 1, True),
(1, 0, False),
(1, 1, True),
(1, 2, True),
(2, 1, False),
(2, 2, True),
],
) )
def test_limit_mm_per_prompt_dummy(model_id, limit, num_supported, is_valid): def test_limit_mm_per_prompt_dummy(model_id, limit, num_supported, is_valid):
limit_mm_per_prompt = {"image": limit} limit_mm_per_prompt = {"image": limit}
...@@ -930,8 +956,15 @@ def test_limit_mm_per_prompt_dummy(model_id, limit, num_supported, is_valid): ...@@ -930,8 +956,15 @@ def test_limit_mm_per_prompt_dummy(model_id, limit, num_supported, is_valid):
@pytest.mark.parametrize("model_id", ["llava-hf/llava-v1.6-mistral-7b-hf"]) @pytest.mark.parametrize("model_id", ["llava-hf/llava-v1.6-mistral-7b-hf"])
@pytest.mark.parametrize( @pytest.mark.parametrize(
("num_images", "limit", "is_valid"), ("num_images", "limit", "is_valid"),
[(0, 0, True), (0, 1, True), (1, 0, False), (1, 1, True), (1, 2, True), [
(2, 1, False), (2, 2, True)], (0, 0, True),
(0, 1, True),
(1, 0, False),
(1, 1, True),
(1, 2, True),
(2, 1, False),
(2, 2, True),
],
) )
def test_limit_mm_per_prompt_apply(model_id, num_images, limit, is_valid): def test_limit_mm_per_prompt_apply(model_id, num_images, limit, is_valid):
limit_mm_per_prompt = {"image": limit} limit_mm_per_prompt = {"image": limit}
...@@ -966,7 +999,6 @@ def test_limit_mm_per_prompt_apply(model_id, num_images, limit, is_valid): ...@@ -966,7 +999,6 @@ def test_limit_mm_per_prompt_apply(model_id, num_images, limit, is_valid):
class DummyProcessor: class DummyProcessor:
def __init__(self, a: int = 0, b: int = 0) -> None: def __init__(self, a: int = 0, b: int = 0) -> None:
super().__init__() super().__init__()
...@@ -982,7 +1014,6 @@ class DummyProcessor: ...@@ -982,7 +1014,6 @@ class DummyProcessor:
return dict(a=a, c=c) return dict(a=a, c=c)
# yapf: disable
@pytest.mark.parametrize("model_id", ["Qwen/Qwen2-VL-2B-Instruct"]) # Dummy @pytest.mark.parametrize("model_id", ["Qwen/Qwen2-VL-2B-Instruct"]) # Dummy
@pytest.mark.parametrize( @pytest.mark.parametrize(
("config_kwargs", "inference_kwargs", "expected_kwargs"), ("config_kwargs", "inference_kwargs", "expected_kwargs"),
...@@ -996,7 +1027,6 @@ class DummyProcessor: ...@@ -996,7 +1027,6 @@ class DummyProcessor:
({"b": 1, "c": 1}, {}, {"a": 0, "b": 1}), ({"b": 1, "c": 1}, {}, {"a": 0, "b": 1}),
], ],
) )
# yapf: enable
def test_hf_processor_init_kwargs( def test_hf_processor_init_kwargs(
model_id, model_id,
config_kwargs, config_kwargs,
...@@ -1020,7 +1050,6 @@ def test_hf_processor_init_kwargs( ...@@ -1020,7 +1050,6 @@ def test_hf_processor_init_kwargs(
assert getattr(processor, k) == v assert getattr(processor, k) == v
# yapf: disable
@pytest.mark.parametrize("model_id", ["Qwen/Qwen2-VL-2B-Instruct"]) # Dummy @pytest.mark.parametrize("model_id", ["Qwen/Qwen2-VL-2B-Instruct"]) # Dummy
@pytest.mark.parametrize( @pytest.mark.parametrize(
("config_kwargs", "inference_kwargs", "expected_kwargs"), ("config_kwargs", "inference_kwargs", "expected_kwargs"),
...@@ -1034,7 +1063,6 @@ def test_hf_processor_init_kwargs( ...@@ -1034,7 +1063,6 @@ def test_hf_processor_init_kwargs(
({"b": 1, "c": 1}, {}, {"a": 0, "c": 1}), ({"b": 1, "c": 1}, {}, {"a": 0, "c": 1}),
], ],
) )
# yapf: enable
def test_hf_processor_call_kwargs( def test_hf_processor_call_kwargs(
model_id, model_id,
config_kwargs, config_kwargs,
......
...@@ -233,7 +233,6 @@ async def test_fetch_video_http_with_dynamic_loader( ...@@ -233,7 +233,6 @@ async def test_fetch_video_http_with_dynamic_loader(
assert metadata_sync["video_backend"] == "opencv_dynamic" assert metadata_sync["video_backend"] == "opencv_dynamic"
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
"case", "case",
[ [
...@@ -264,7 +263,6 @@ async def test_fetch_video_http_with_dynamic_loader( ...@@ -264,7 +263,6 @@ async def test_fetch_video_http_with_dynamic_loader(
("image", 0), ("image", 0),
], ],
), ),
# Two modalities # Two modalities
## Internally sorted ## Internally sorted
dict( dict(
...@@ -276,7 +274,7 @@ async def test_fetch_video_http_with_dynamic_loader( ...@@ -276,7 +274,7 @@ async def test_fetch_video_http_with_dynamic_loader(
"audio": [ "audio": [
PlaceholderRange(offset=0, length=2), PlaceholderRange(offset=0, length=2),
PlaceholderRange(offset=2, length=3), PlaceholderRange(offset=2, length=3),
] ],
}, },
expected_modality_idxs=[ expected_modality_idxs=[
("audio", 0), ("audio", 0),
...@@ -295,7 +293,7 @@ async def test_fetch_video_http_with_dynamic_loader( ...@@ -295,7 +293,7 @@ async def test_fetch_video_http_with_dynamic_loader(
"audio": [ "audio": [
PlaceholderRange(offset=5, length=2), PlaceholderRange(offset=5, length=2),
PlaceholderRange(offset=11, length=4), PlaceholderRange(offset=11, length=4),
] ],
}, },
expected_modality_idxs=[ expected_modality_idxs=[
("image", 0), ("image", 0),
...@@ -314,7 +312,7 @@ async def test_fetch_video_http_with_dynamic_loader( ...@@ -314,7 +312,7 @@ async def test_fetch_video_http_with_dynamic_loader(
"audio": [ "audio": [
PlaceholderRange(offset=11, length=4), PlaceholderRange(offset=11, length=4),
PlaceholderRange(offset=5, length=2), PlaceholderRange(offset=5, length=2),
] ],
}, },
expected_modality_idxs=[ expected_modality_idxs=[
("image", 1), ("image", 1),
...@@ -323,7 +321,6 @@ async def test_fetch_video_http_with_dynamic_loader( ...@@ -323,7 +321,6 @@ async def test_fetch_video_http_with_dynamic_loader(
("audio", 0), ("audio", 0),
], ],
), ),
# Three modalities # Three modalities
## Internally sorted ## Internally sorted
dict( dict(
...@@ -339,7 +336,7 @@ async def test_fetch_video_http_with_dynamic_loader( ...@@ -339,7 +336,7 @@ async def test_fetch_video_http_with_dynamic_loader(
PlaceholderRange(offset=3, length=4), PlaceholderRange(offset=3, length=4),
PlaceholderRange(offset=7, length=5), PlaceholderRange(offset=7, length=5),
PlaceholderRange(offset=12, length=6), PlaceholderRange(offset=12, length=6),
] ],
}, },
expected_modality_idxs=[ expected_modality_idxs=[
("audio", 0), ("audio", 0),
...@@ -363,7 +360,7 @@ async def test_fetch_video_http_with_dynamic_loader( ...@@ -363,7 +360,7 @@ async def test_fetch_video_http_with_dynamic_loader(
], ],
"video": [ "video": [
PlaceholderRange(offset=8, length=5), PlaceholderRange(offset=8, length=5),
] ],
}, },
expected_modality_idxs=[ expected_modality_idxs=[
("image", 0), ("image", 0),
...@@ -386,7 +383,7 @@ async def test_fetch_video_http_with_dynamic_loader( ...@@ -386,7 +383,7 @@ async def test_fetch_video_http_with_dynamic_loader(
], ],
"video": [ "video": [
PlaceholderRange(offset=8, length=5), PlaceholderRange(offset=8, length=5),
] ],
}, },
expected_modality_idxs=[ expected_modality_idxs=[
("image", 0), ("image", 0),
...@@ -398,7 +395,6 @@ async def test_fetch_video_http_with_dynamic_loader( ...@@ -398,7 +395,6 @@ async def test_fetch_video_http_with_dynamic_loader(
), ),
], ],
) )
# yapf: enable
def test_argsort_mm_positions(case): def test_argsort_mm_positions(case):
mm_positions = case["mm_positions"] mm_positions = case["mm_positions"]
expected_modality_idxs = case["expected_modality_idxs"] expected_modality_idxs = case["expected_modality_idxs"]
...@@ -413,13 +409,16 @@ def test_argsort_mm_positions(case): ...@@ -413,13 +409,16 @@ def test_argsort_mm_positions(case):
@pytest.mark.parametrize("num_frames", [-1, 32, 1800]) @pytest.mark.parametrize("num_frames", [-1, 32, 1800])
async def test_allowed_media_domains(video_url: str, num_frames: int): async def test_allowed_media_domains(video_url: str, num_frames: int):
connector = MediaConnector( connector = MediaConnector(
media_io_kwargs={"video": { media_io_kwargs={
"num_frames": num_frames, "video": {
}}, "num_frames": num_frames,
}
},
allowed_media_domains=[ allowed_media_domains=[
"www.bogotobogo.com", "www.bogotobogo.com",
"github.com", "github.com",
]) ],
)
video_sync, metadata_sync = connector.fetch_video(video_url) video_sync, metadata_sync = connector.fetch_video(video_url)
video_async, metadata_async = await connector.fetch_video_async(video_url) video_async, metadata_async = await connector.fetch_video_async(video_url)
......
...@@ -59,48 +59,52 @@ def test_parse_raw_single_batch_string_slice(inputs_slice: slice): ...@@ -59,48 +59,52 @@ def test_parse_raw_single_batch_string_slice(inputs_slice: slice):
) )
# yapf: disable @pytest.mark.parametrize(
@pytest.mark.parametrize('mm_processor_kwargs,expected_mm_kwargs', [ "mm_processor_kwargs,expected_mm_kwargs",
(None, [{}, {}]), [
({}, [{}, {}]), (None, [{}, {}]),
({"foo": 100}, [{"foo": 100}, {"foo": 100}]), ({}, [{}, {}]),
([{"foo": 100}, {"bar": 200}], [{"foo": 100}, {"bar": 200}]), ({"foo": 100}, [{"foo": 100}, {"foo": 100}]),
]) ([{"foo": 100}, {"bar": 200}], [{"foo": 100}, {"bar": 200}]),
# yapf: enable ],
)
def test_zip_enc_dec_prompts(mm_processor_kwargs, expected_mm_kwargs): def test_zip_enc_dec_prompts(mm_processor_kwargs, expected_mm_kwargs):
"""Test mm_processor_kwargs init for zipping enc/dec prompts.""" """Test mm_processor_kwargs init for zipping enc/dec prompts."""
encoder_prompts = ['An encoder prompt', 'Another encoder prompt'] encoder_prompts = ["An encoder prompt", "Another encoder prompt"]
decoder_prompts = ['A decoder prompt', 'Another decoder prompt'] decoder_prompts = ["A decoder prompt", "Another decoder prompt"]
zipped_prompts = zip_enc_dec_prompts(encoder_prompts, decoder_prompts, zipped_prompts = zip_enc_dec_prompts(
mm_processor_kwargs) encoder_prompts, decoder_prompts, mm_processor_kwargs
)
assert len(zipped_prompts) == len(encoder_prompts) == len(decoder_prompts) assert len(zipped_prompts) == len(encoder_prompts) == len(decoder_prompts)
for enc, dec, exp_kwargs, zipped in zip(encoder_prompts, decoder_prompts, for enc, dec, exp_kwargs, zipped in zip(
expected_mm_kwargs, encoder_prompts, decoder_prompts, expected_mm_kwargs, zipped_prompts
zipped_prompts): ):
assert isinstance(zipped, dict) assert isinstance(zipped, dict)
assert len(zipped.keys()) == 3 assert len(zipped.keys()) == 3
assert zipped['encoder_prompt'] == enc assert zipped["encoder_prompt"] == enc
assert zipped['decoder_prompt'] == dec assert zipped["decoder_prompt"] == dec
assert zipped['mm_processor_kwargs'] == exp_kwargs assert zipped["mm_processor_kwargs"] == exp_kwargs
@pytest.mark.parametrize("model_id", [ @pytest.mark.parametrize(
"facebook/opt-125m", "model_id",
]) [
@pytest.mark.parametrize("prompt", [ "facebook/opt-125m",
{ ],
"prompt": "", )
"multi_modal_data": { @pytest.mark.parametrize(
"dummy": [] "prompt",
[
{
"prompt": "",
"multi_modal_data": {"dummy": []},
}, },
}, {
{ "prompt_token_ids": [],
"prompt_token_ids": [], "multi_modal_data": {"dummy": []},
"multi_modal_data": {
"dummy": []
}, },
}, ],
]) )
def test_preprocessor_text_no_mm_inputs(model_id, prompt): def test_preprocessor_text_no_mm_inputs(model_id, prompt):
model_config = ModelConfig(model=model_id) model_config = ModelConfig(model=model_id)
tokenizer = init_tokenizer_from_configs(model_config) tokenizer = init_tokenizer_from_configs(model_config)
...@@ -110,15 +114,19 @@ def test_preprocessor_text_no_mm_inputs(model_id, prompt): ...@@ -110,15 +114,19 @@ def test_preprocessor_text_no_mm_inputs(model_id, prompt):
input_preprocessor.preprocess(prompt) input_preprocessor.preprocess(prompt)
@pytest.mark.parametrize("model_id", [ @pytest.mark.parametrize(
"facebook/chameleon-7b", "model_id",
]) [
@pytest.mark.parametrize("prompt", [ "facebook/chameleon-7b",
"", ],
{ )
"prompt_token_ids": [] @pytest.mark.parametrize(
}, "prompt",
]) [
"",
{"prompt_token_ids": []},
],
)
def test_preprocessor_always_mm_code_path(model_id, prompt): def test_preprocessor_always_mm_code_path(model_id, prompt):
model_config = ModelConfig(model=model_id) model_config = ModelConfig(model=model_id)
tokenizer = init_tokenizer_from_configs(model_config) tokenizer = init_tokenizer_from_configs(model_config)
......
...@@ -9,14 +9,10 @@ import pytest ...@@ -9,14 +9,10 @@ import pytest
import torch import torch
import torch_xla import torch_xla
# yapf conflicts with isort for this block
# yapf: disable
from vllm.model_executor.layers.fused_moe.moe_pallas import fused_moe as pallas_moe from vllm.model_executor.layers.fused_moe.moe_pallas import fused_moe as pallas_moe
from vllm.model_executor.layers.fused_moe.moe_torch_iterative import ( from vllm.model_executor.layers.fused_moe.moe_torch_iterative import (
fused_moe as torch_moe, fused_moe as torch_moe,
) )
# yapf: enable
from vllm.platforms import current_platform from vllm.platforms import current_platform
if not current_platform.is_tpu(): if not current_platform.is_tpu():
......
...@@ -388,7 +388,6 @@ def test_duplicate_dict_args(caplog_vllm, parser): ...@@ -388,7 +388,6 @@ def test_duplicate_dict_args(caplog_vllm, parser):
assert "-O.level" in caplog_vllm.text assert "-O.level" in caplog_vllm.text
# yapf: enable
@pytest.mark.parametrize( @pytest.mark.parametrize(
"callable,kw_name,requires_kw_only,allow_var_kwargs,is_supported", "callable,kw_name,requires_kw_only,allow_var_kwargs,is_supported",
[ [
...@@ -408,7 +407,6 @@ def test_duplicate_dict_args(caplog_vllm, parser): ...@@ -408,7 +407,6 @@ def test_duplicate_dict_args(caplog_vllm, parser):
(lambda foo, **kwargs: None, "foo", True, True, False), (lambda foo, **kwargs: None, "foo", True, True, False),
], ],
) )
# yapf: disable
def test_supports_kw( def test_supports_kw(
callable, kw_name, requires_kw_only, allow_var_kwargs, is_supported callable, kw_name, requires_kw_only, allow_var_kwargs, is_supported
): ):
...@@ -681,7 +679,6 @@ def test_lru_cache(): ...@@ -681,7 +679,6 @@ def test_lru_cache():
assert 6 in cache assert 6 in cache
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
("src_dtype", "tgt_dtype", "expected_result"), ("src_dtype", "tgt_dtype", "expected_result"),
[ [
...@@ -715,12 +712,10 @@ def test_lru_cache(): ...@@ -715,12 +712,10 @@ def test_lru_cache():
(torch.complex64, torch.complex32, False), (torch.complex64, torch.complex32, False),
], ],
) )
# yapf: enable
def test_is_lossless_cast(src_dtype, tgt_dtype, expected_result): def test_is_lossless_cast(src_dtype, tgt_dtype, expected_result):
assert is_lossless_cast(src_dtype, tgt_dtype) == expected_result assert is_lossless_cast(src_dtype, tgt_dtype) == expected_result
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
("dtypes", "expected_result"), ("dtypes", "expected_result"),
[ [
...@@ -730,7 +725,6 @@ def test_is_lossless_cast(src_dtype, tgt_dtype, expected_result): ...@@ -730,7 +725,6 @@ def test_is_lossless_cast(src_dtype, tgt_dtype, expected_result):
([torch.bool, torch.int8, torch.float16, torch.complex32], torch.complex32), # noqa: E501 ([torch.bool, torch.int8, torch.float16, torch.complex32], torch.complex32), # noqa: E501
], ],
) )
# yapf: enable
def test_common_broadcastable_dtype(dtypes, expected_result): def test_common_broadcastable_dtype(dtypes, expected_result):
assert common_broadcastable_dtype(dtypes) == expected_result assert common_broadcastable_dtype(dtypes) == expected_result
...@@ -775,7 +769,6 @@ def test_placeholder_module_error_handling(): ...@@ -775,7 +769,6 @@ def test_placeholder_module_error_handling():
_ = placeholder_attr.module _ = placeholder_attr.module
# yapf: disable
@pytest.mark.parametrize( @pytest.mark.parametrize(
"obj,key1,key2", "obj,key1,key2",
[ [
...@@ -785,8 +778,8 @@ def test_placeholder_module_error_handling(): ...@@ -785,8 +778,8 @@ def test_placeholder_module_error_handling():
({1: "a", 2: "b"}, 1, 3), ({1: "a", 2: "b"}, 1, 3),
# Tests for both keys do not exist # Tests for both keys do not exist
({1: "a", 2: "b"}, 3, 4), ({1: "a", 2: "b"}, 3, 4),
]) ],
# yapf: enable )
def test_swap_dict_values(obj, key1, key2): def test_swap_dict_values(obj, key1, key2):
original_obj = obj.copy() original_obj = obj.copy()
swap_dict_values(obj, key1, key2) swap_dict_values(obj, key1, key2)
...@@ -800,26 +793,30 @@ def test_swap_dict_values(obj, key1, key2): ...@@ -800,26 +793,30 @@ def test_swap_dict_values(obj, key1, key2):
assert key1 not in obj assert key1 not in obj
def test_model_specification(parser_with_config, cli_config_file, def test_model_specification(
cli_config_file_with_model): parser_with_config, cli_config_file, cli_config_file_with_model
):
# Test model in CLI takes precedence over config # Test model in CLI takes precedence over config
args = parser_with_config.parse_args( args = parser_with_config.parse_args(
['serve', 'cli-model', '--config', cli_config_file_with_model]) ["serve", "cli-model", "--config", cli_config_file_with_model]
assert args.model_tag == 'cli-model' )
assert args.served_model_name == 'mymodel' assert args.model_tag == "cli-model"
assert args.served_model_name == "mymodel"
# Test model from config file works # Test model from config file works
args = parser_with_config.parse_args([ args = parser_with_config.parse_args(
'serve', [
'--config', "serve",
cli_config_file_with_model, "--config",
]) cli_config_file_with_model,
assert args.model == 'config-model' ]
assert args.served_model_name == 'mymodel' )
assert args.model == "config-model"
assert args.served_model_name == "mymodel"
# Test no model specified anywhere raises error # Test no model specified anywhere raises error
with pytest.raises(ValueError, match="No model specified!"): with pytest.raises(ValueError, match="No model specified!"):
parser_with_config.parse_args(['serve', '--config', cli_config_file]) parser_with_config.parse_args(["serve", "--config", cli_config_file])
# Test using --model option raises error # Test using --model option raises error
# with pytest.raises( # with pytest.raises(
...@@ -833,47 +830,52 @@ def test_model_specification(parser_with_config, cli_config_file, ...@@ -833,47 +830,52 @@ def test_model_specification(parser_with_config, cli_config_file,
# Test using --model option back-compatibility # Test using --model option back-compatibility
# (when back-compatibility ends, the above test should be uncommented # (when back-compatibility ends, the above test should be uncommented
# and the below test should be removed) # and the below test should be removed)
args = parser_with_config.parse_args([ args = parser_with_config.parse_args(
'serve', [
'--tensor-parallel-size', "serve",
'2', "--tensor-parallel-size",
'--model', "2",
'my-model', "--model",
'--trust-remote-code', "my-model",
'--port', "--trust-remote-code",
'8001', "--port",
]) "8001",
]
)
assert args.model is None assert args.model is None
assert args.tensor_parallel_size == 2 assert args.tensor_parallel_size == 2
assert args.trust_remote_code is True assert args.trust_remote_code is True
assert args.port == 8001 assert args.port == 8001
args = parser_with_config.parse_args([ args = parser_with_config.parse_args(
'serve', [
'--tensor-parallel-size=2', "serve",
'--model=my-model', "--tensor-parallel-size=2",
'--trust-remote-code', "--model=my-model",
'--port=8001', "--trust-remote-code",
]) "--port=8001",
]
)
assert args.model is None assert args.model is None
assert args.tensor_parallel_size == 2 assert args.tensor_parallel_size == 2
assert args.trust_remote_code is True assert args.trust_remote_code is True
assert args.port == 8001 assert args.port == 8001
# Test other config values are preserved # Test other config values are preserved
args = parser_with_config.parse_args([ args = parser_with_config.parse_args(
'serve', [
'cli-model', "serve",
'--config', "cli-model",
cli_config_file_with_model, "--config",
]) cli_config_file_with_model,
]
)
assert args.tensor_parallel_size == 2 assert args.tensor_parallel_size == 2
assert args.trust_remote_code is True assert args.trust_remote_code is True
assert args.port == 12312 assert args.port == 12312
@pytest.mark.parametrize("input", [(), ("abc", ), (None, ), @pytest.mark.parametrize("input", [(), ("abc",), (None,), (None, bool, [1, 2, 3])])
(None, bool, [1, 2, 3])])
def test_sha256(input: tuple): def test_sha256(input: tuple):
digest = sha256(input) digest = sha256(input)
assert digest is not None assert digest is not None
...@@ -887,7 +889,7 @@ def test_sha256(input: tuple): ...@@ -887,7 +889,7 @@ def test_sha256(input: tuple):
assert digest == sha256(input) assert digest == sha256(input)
# hashing different input, returns different value # hashing different input, returns different value
assert digest != sha256(input + (1, )) assert digest != sha256(input + (1,))
@pytest.mark.parametrize( @pytest.mark.parametrize(
...@@ -897,7 +899,8 @@ def test_sha256(input: tuple): ...@@ -897,7 +899,8 @@ def test_sha256(input: tuple):
("tcp://127.0.0.1:5555", ("tcp", "127.0.0.1", "5555")), ("tcp://127.0.0.1:5555", ("tcp", "127.0.0.1", "5555")),
("tcp://[::1]:5555", ("tcp", "::1", "5555")), # IPv6 address ("tcp://[::1]:5555", ("tcp", "::1", "5555")), # IPv6 address
("inproc://some_identifier", ("inproc", "some_identifier", "")), ("inproc://some_identifier", ("inproc", "some_identifier", "")),
]) ],
)
def test_split_zmq_path(path, expected): def test_split_zmq_path(path, expected):
assert split_zmq_path(path) == expected assert split_zmq_path(path) == expected
...@@ -909,7 +912,8 @@ def test_split_zmq_path(path, expected): ...@@ -909,7 +912,8 @@ def test_split_zmq_path(path, expected):
"tcp://127.0.0.1", # Missing port "tcp://127.0.0.1", # Missing port
"tcp://[::1]", # Missing port for IPv6 "tcp://[::1]", # Missing port for IPv6
"tcp://:5555", # Missing host "tcp://:5555", # Missing host
]) ],
)
def test_split_zmq_path_invalid(invalid_path): def test_split_zmq_path_invalid(invalid_path):
with pytest.raises(ValueError): with pytest.raises(ValueError):
split_zmq_path(invalid_path) split_zmq_path(invalid_path)
...@@ -931,8 +935,9 @@ def test_make_zmq_socket_ipv6(): ...@@ -931,8 +935,9 @@ def test_make_zmq_socket_ipv6():
zsock: zmq.Socket = make_zmq_socket(ctx, ipv6_path, socket_type) zsock: zmq.Socket = make_zmq_socket(ctx, ipv6_path, socket_type)
# Verify that the IPV6 option is set # Verify that the IPV6 option is set
assert zsock.getsockopt( assert zsock.getsockopt(zmq.IPV6) == 1, (
zmq.IPV6) == 1, "IPV6 option should be enabled for IPv6 addresses" "IPV6 option should be enabled for IPv6 addresses"
)
# Clean up # Clean up
zsock.close() zsock.close()
...@@ -1019,15 +1024,14 @@ def test_convert_ids_list_to_tokens(): ...@@ -1019,15 +1024,14 @@ def test_convert_ids_list_to_tokens():
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-1.5B-Instruct") tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-1.5B-Instruct")
token_ids = tokenizer.encode("Hello, world!") token_ids = tokenizer.encode("Hello, world!")
# token_ids = [9707, 11, 1879, 0] # token_ids = [9707, 11, 1879, 0]
assert tokenizer.convert_ids_to_tokens(token_ids) == [ assert tokenizer.convert_ids_to_tokens(token_ids) == ["Hello", ",", "Ġworld", "!"]
'Hello', ',', 'Ġworld', '!'
]
tokens = convert_ids_list_to_tokens(tokenizer, token_ids) tokens = convert_ids_list_to_tokens(tokenizer, token_ids)
assert tokens == ['Hello', ',', ' world', '!'] assert tokens == ["Hello", ",", " world", "!"]
def test_current_stream_multithread(): def test_current_stream_multithread():
import threading import threading
if not torch.cuda.is_available(): if not torch.cuda.is_available():
pytest.skip("CUDA not available") pytest.skip("CUDA not available")
...@@ -1046,13 +1050,18 @@ def test_current_stream_multithread(): ...@@ -1046,13 +1050,18 @@ def test_current_stream_multithread():
child_thread.start() child_thread.start()
try: try:
assert thread_stream_ready.wait( assert thread_stream_ready.wait(timeout=5), (
timeout=5), "Child thread failed to enter stream context in time" "Child thread failed to enter stream context in time"
)
main_current_stream = current_stream() main_current_stream = current_stream()
assert main_current_stream != child_stream, "Main thread's current_stream was contaminated by child thread" assert main_current_stream != child_stream, (
assert main_current_stream == main_default_stream, "Main thread's current_stream is not the default stream" "Main thread's current_stream was contaminated by child thread"
)
assert main_current_stream == main_default_stream, (
"Main thread's current_stream is not the default stream"
)
# Notify child thread it can exit # Notify child thread it can exit
thread_can_exit.set() thread_can_exit.set()
...@@ -1070,7 +1079,7 @@ def test_load_config_file(tmp_path): ...@@ -1070,7 +1079,7 @@ def test_load_config_file(tmp_path):
"enable-logging": True, "enable-logging": True,
"list-arg": ["item1", "item2"], "list-arg": ["item1", "item2"],
"port": 12323, "port": 12323,
"tensor-parallel-size": 4 "tensor-parallel-size": 4,
} }
# Write the configuration data to a temporary YAML file # Write the configuration data to a temporary YAML file
......
...@@ -16,9 +16,6 @@ from vllm.multimodal.inputs import ( ...@@ -16,9 +16,6 @@ from vllm.multimodal.inputs import (
from vllm.sampling_params import SamplingParams from vllm.sampling_params import SamplingParams
from vllm.utils import GiB_bytes, sha256, sha256_cbor from vllm.utils import GiB_bytes, sha256, sha256_cbor
from vllm.v1.core.kv_cache_manager import KVCacheManager from vllm.v1.core.kv_cache_manager import KVCacheManager
# disable yapf here as it formats differently than isort such that both fail
# yapf: disable
from vllm.v1.core.kv_cache_utils import ( from vllm.v1.core.kv_cache_utils import (
BlockHash, BlockHash,
FreeKVCacheBlockQueue, FreeKVCacheBlockQueue,
...@@ -48,8 +45,6 @@ from vllm.v1.kv_cache_interface import ( ...@@ -48,8 +45,6 @@ from vllm.v1.kv_cache_interface import (
from vllm.v1.metrics.stats import PrefixCacheStats from vllm.v1.metrics.stats import PrefixCacheStats
from vllm.v1.request import Request from vllm.v1.request import Request
# yapf: enable
pytestmark = pytest.mark.cpu_test pytestmark = pytest.mark.cpu_test
......
...@@ -22,8 +22,6 @@ from vllm.config import VllmConfig ...@@ -22,8 +22,6 @@ from vllm.config import VllmConfig
from vllm.platforms import current_platform from vllm.platforms import current_platform
from vllm.sampling_params import SamplingParams from vllm.sampling_params import SamplingParams
from vllm.utils import is_pin_memory_available from vllm.utils import is_pin_memory_available
# yapf: disable
from vllm.v1.sample.logits_processor import ( from vllm.v1.sample.logits_processor import (
BatchUpdate, BatchUpdate,
BatchUpdateBuilder, BatchUpdateBuilder,
...@@ -34,8 +32,6 @@ from vllm.v1.sample.logits_processor import ( ...@@ -34,8 +32,6 @@ from vllm.v1.sample.logits_processor import (
MoveDirectionality, MoveDirectionality,
build_logitsprocs, build_logitsprocs,
) )
# yapf: enable
from vllm.v1.sample.metadata import SamplingMetadata from vllm.v1.sample.metadata import SamplingMetadata
PIN_MEMORY_AVAILABLE = is_pin_memory_available() PIN_MEMORY_AVAILABLE = is_pin_memory_available()
......
...@@ -7,8 +7,6 @@ from typing import Union ...@@ -7,8 +7,6 @@ from typing import Union
import pytest import pytest
from tests.utils import create_new_process_for_each_test from tests.utils import create_new_process_for_each_test
# yapf: disable
from tests.v1.logits_processors.utils import ( from tests.v1.logits_processors.utils import (
DUMMY_LOGITPROC_ARG, DUMMY_LOGITPROC_ARG,
DUMMY_LOGITPROC_FQCN, DUMMY_LOGITPROC_FQCN,
...@@ -24,8 +22,6 @@ from tests.v1.logits_processors.utils import ( ...@@ -24,8 +22,6 @@ from tests.v1.logits_processors.utils import (
prompts, prompts,
) )
from tests.v1.logits_processors.utils import entry_points as fake_entry_points from tests.v1.logits_processors.utils import entry_points as fake_entry_points
# yapf: enable
from vllm import LLM, SamplingParams from vllm import LLM, SamplingParams
from vllm.v1.sample.logits_processor import ( from vllm.v1.sample.logits_processor import (
STR_POOLING_REJECTS_LOGITSPROCS, STR_POOLING_REJECTS_LOGITSPROCS,
......
...@@ -11,8 +11,6 @@ import pytest ...@@ -11,8 +11,6 @@ import pytest
import pytest_asyncio import pytest_asyncio
from tests.utils import RemoteOpenAIServerCustom, create_new_process_for_each_test from tests.utils import RemoteOpenAIServerCustom, create_new_process_for_each_test
# yapf: disable
from tests.v1.logits_processors.utils import ( from tests.v1.logits_processors.utils import (
DUMMY_LOGITPROC_ARG, DUMMY_LOGITPROC_ARG,
DUMMY_LOGITPROC_FQCN, DUMMY_LOGITPROC_FQCN,
...@@ -25,8 +23,6 @@ from tests.v1.logits_processors.utils import ( ...@@ -25,8 +23,6 @@ from tests.v1.logits_processors.utils import (
) )
from tests.v1.logits_processors.utils import entry_points as fake_entry_points from tests.v1.logits_processors.utils import entry_points as fake_entry_points
# yapf: enable
def _server_with_logitproc_entrypoint( def _server_with_logitproc_entrypoint(
env_dict: Optional[dict[str, str]], env_dict: Optional[dict[str, str]],
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import importlib import importlib
from typing import TYPE_CHECKING, Callable from typing import TYPE_CHECKING, Callable
# yapf: disable
import vllm.envs as envs import vllm.envs as envs
from vllm.distributed.kv_transfer.kv_connector.base import ( from vllm.distributed.kv_transfer.kv_connector.base import (
KVConnectorBase, KVConnectorBase,
...@@ -13,8 +12,6 @@ from vllm.distributed.kv_transfer.kv_connector.base import ( ...@@ -13,8 +12,6 @@ from vllm.distributed.kv_transfer.kv_connector.base import (
from vllm.distributed.kv_transfer.kv_connector.v1 import KVConnectorRole from vllm.distributed.kv_transfer.kv_connector.v1 import KVConnectorRole
from vllm.logger import init_logger from vllm.logger import init_logger
# yapf: enable
if TYPE_CHECKING: if TYPE_CHECKING:
from vllm.config import VllmConfig from vllm.config import VllmConfig
from vllm.config.kv_transfer import KVTransferConfig from vllm.config.kv_transfer import KVTransferConfig
......
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
# yapf: disable
import argparse import argparse
import copy import copy
import dataclasses import dataclasses
...@@ -88,8 +87,6 @@ from vllm.transformers_utils.utils import check_gguf_file ...@@ -88,8 +87,6 @@ from vllm.transformers_utils.utils import check_gguf_file
from vllm.utils import FlexibleArgumentParser, GiB_bytes, get_ip, is_in_ray_actor from vllm.utils import FlexibleArgumentParser, GiB_bytes, get_ip, is_in_ray_actor
from vllm.v1.sample.logits_processor import LogitsProcessor from vllm.v1.sample.logits_processor import LogitsProcessor
# yapf: enable
if TYPE_CHECKING: if TYPE_CHECKING:
from vllm.executor.executor_base import ExecutorBase from vllm.executor.executor_base import ExecutorBase
from vllm.model_executor.layers.quantization import QuantizationMethods from vllm.model_executor.layers.quantization import QuantizationMethods
......
...@@ -17,9 +17,6 @@ import jinja2.nodes ...@@ -17,9 +17,6 @@ import jinja2.nodes
import jinja2.parser import jinja2.parser
import jinja2.sandbox import jinja2.sandbox
import transformers.utils.chat_template_utils as hf_chat_utils import transformers.utils.chat_template_utils as hf_chat_utils
# yapf conflicts with isort for this block
# yapf: disable
from openai.types.chat import ( from openai.types.chat import (
ChatCompletionAssistantMessageParam, ChatCompletionAssistantMessageParam,
ChatCompletionContentPartImageParam, ChatCompletionContentPartImageParam,
...@@ -40,8 +37,6 @@ from openai.types.responses import ResponseInputImageParam ...@@ -40,8 +37,6 @@ from openai.types.responses import ResponseInputImageParam
from openai_harmony import Message as OpenAIHarmonyMessage from openai_harmony import Message as OpenAIHarmonyMessage
from PIL import Image from PIL import Image
from pydantic import BaseModel, ConfigDict, TypeAdapter from pydantic import BaseModel, ConfigDict, TypeAdapter
# yapf: enable
from transformers import PreTrainedTokenizer, PreTrainedTokenizerFast, ProcessorMixin from transformers import PreTrainedTokenizer, PreTrainedTokenizerFast, ProcessorMixin
# pydantic needs the TypedDict from typing_extensions # pydantic needs the TypedDict from typing_extensions
...@@ -52,11 +47,7 @@ from vllm.logger import init_logger ...@@ -52,11 +47,7 @@ from vllm.logger import init_logger
from vllm.model_executor.models import SupportsMultiModal from vllm.model_executor.models import SupportsMultiModal
from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalDataDict, MultiModalUUIDDict from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalDataDict, MultiModalUUIDDict
from vllm.multimodal.utils import MediaConnector from vllm.multimodal.utils import MediaConnector
# yapf: disable
from vllm.transformers_utils.chat_templates import get_chat_template_fallback_path from vllm.transformers_utils.chat_templates import get_chat_template_fallback_path
# yapf: enable
from vllm.transformers_utils.processor import cached_get_processor from vllm.transformers_utils.processor import cached_get_processor
from vllm.transformers_utils.tokenizer import AnyTokenizer, MistralTokenizer from vllm.transformers_utils.tokenizer import AnyTokenizer, MistralTokenizer
from vllm.utils import random_uuid, supports_kw from vllm.utils import random_uuid, supports_kw
...@@ -317,11 +308,7 @@ def _is_var_or_elems_access( ...@@ -317,11 +308,7 @@ def _is_var_or_elems_access(
): ):
return _is_var_or_elems_access(node.node, varname, key) return _is_var_or_elems_access(node.node, varname, key)
# yapf: disable return _is_attr_access(node, varname, key) if key else _is_var_access(node, varname)
return (
_is_attr_access(node, varname, key) if key
else _is_var_access(node, varname)
) # yapf: enable
def _iter_nodes_assign_var_or_elems(root: jinja2.nodes.Node, varname: str): def _iter_nodes_assign_var_or_elems(root: jinja2.nodes.Node, varname: str):
......
...@@ -39,9 +39,6 @@ from vllm.entrypoints.chat_utils import ( ...@@ -39,9 +39,6 @@ from vllm.entrypoints.chat_utils import (
parse_chat_messages, parse_chat_messages,
resolve_chat_template_content_format, resolve_chat_template_content_format,
) )
# yapf conflicts with isort for this block
# yapf: disable
from vllm.entrypoints.score_utils import ( from vllm.entrypoints.score_utils import (
ScoreContentPartParam, ScoreContentPartParam,
ScoreMultiModalParam, ScoreMultiModalParam,
...@@ -50,8 +47,6 @@ from vllm.entrypoints.score_utils import ( ...@@ -50,8 +47,6 @@ from vllm.entrypoints.score_utils import (
compress_token_type_ids, compress_token_type_ids,
get_score_prompt, get_score_prompt,
) )
# yapf: enable
from vllm.entrypoints.utils import _validate_truncation_size, log_non_default_args from vllm.entrypoints.utils import _validate_truncation_size, log_non_default_args
from vllm.inputs import ( from vllm.inputs import (
DataPrompt, DataPrompt,
......
...@@ -49,9 +49,6 @@ from vllm.entrypoints.chat_utils import ( ...@@ -49,9 +49,6 @@ from vllm.entrypoints.chat_utils import (
from vllm.entrypoints.launcher import serve_http from vllm.entrypoints.launcher import serve_http
from vllm.entrypoints.logger import RequestLogger from vllm.entrypoints.logger import RequestLogger
from vllm.entrypoints.openai.cli_args import make_arg_parser, validate_parsed_serve_args from vllm.entrypoints.openai.cli_args import make_arg_parser, validate_parsed_serve_args
# yapf conflicts with isort for this block
# yapf: disable
from vllm.entrypoints.openai.protocol import ( from vllm.entrypoints.openai.protocol import (
ChatCompletionRequest, ChatCompletionRequest,
ChatCompletionResponse, ChatCompletionResponse,
...@@ -84,8 +81,6 @@ from vllm.entrypoints.openai.protocol import ( ...@@ -84,8 +81,6 @@ from vllm.entrypoints.openai.protocol import (
TranslationResponse, TranslationResponse,
UnloadLoRAAdapterRequest, UnloadLoRAAdapterRequest,
) )
# yapf: enable
from vllm.entrypoints.openai.serving_chat import OpenAIServingChat from vllm.entrypoints.openai.serving_chat import OpenAIServingChat
from vllm.entrypoints.openai.serving_classification import ServingClassification from vllm.entrypoints.openai.serving_classification import ServingClassification
from vllm.entrypoints.openai.serving_completion import OpenAIServingCompletion from vllm.entrypoints.openai.serving_completion import OpenAIServingCompletion
......
...@@ -11,8 +11,6 @@ from typing import Annotated, Any, ClassVar, Generic, Literal, Optional, TypeVar ...@@ -11,8 +11,6 @@ from typing import Annotated, Any, ClassVar, Generic, Literal, Optional, TypeVar
import regex as re import regex as re
import torch import torch
from fastapi import HTTPException, UploadFile from fastapi import HTTPException, UploadFile
# yapf: disable
from openai.types.chat.chat_completion_audio import ( from openai.types.chat.chat_completion_audio import (
ChatCompletionAudio as OpenAIChatCompletionAudio, ChatCompletionAudio as OpenAIChatCompletionAudio,
) )
...@@ -46,8 +44,6 @@ from openai.types.responses import ResponseCreatedEvent as OpenAIResponseCreated ...@@ -46,8 +44,6 @@ from openai.types.responses import ResponseCreatedEvent as OpenAIResponseCreated
from openai.types.responses import ( from openai.types.responses import (
ResponseInProgressEvent as OpenAIResponseInProgressEvent, ResponseInProgressEvent as OpenAIResponseInProgressEvent,
) )
# yapf: enable
from openai.types.responses.response_reasoning_item import ( from openai.types.responses.response_reasoning_item import (
Content as ResponseReasoningTextContent, Content as ResponseReasoningTextContent,
) )
......
...@@ -18,8 +18,6 @@ from vllm.config import VllmConfig ...@@ -18,8 +18,6 @@ from vllm.config import VllmConfig
from vllm.engine.arg_utils import AsyncEngineArgs, optional_type from vllm.engine.arg_utils import AsyncEngineArgs, optional_type
from vllm.engine.protocol import EngineClient from vllm.engine.protocol import EngineClient
from vllm.entrypoints.logger import RequestLogger from vllm.entrypoints.logger import RequestLogger
# yapf: disable
from vllm.entrypoints.openai.protocol import ( from vllm.entrypoints.openai.protocol import (
BatchRequestInput, BatchRequestInput,
BatchRequestOutput, BatchRequestOutput,
...@@ -30,8 +28,6 @@ from vllm.entrypoints.openai.protocol import ( ...@@ -30,8 +28,6 @@ from vllm.entrypoints.openai.protocol import (
RerankResponse, RerankResponse,
ScoreResponse, ScoreResponse,
) )
# yapf: enable
from vllm.entrypoints.openai.serving_chat import OpenAIServingChat from vllm.entrypoints.openai.serving_chat import OpenAIServingChat
from vllm.entrypoints.openai.serving_embedding import OpenAIServingEmbedding from vllm.entrypoints.openai.serving_embedding import OpenAIServingEmbedding
from vllm.entrypoints.openai.serving_models import BaseModelPath, OpenAIServingModels from vllm.entrypoints.openai.serving_models import BaseModelPath, OpenAIServingModels
......
...@@ -1733,13 +1733,15 @@ class OpenAIServingChat(OpenAIServing): ...@@ -1733,13 +1733,15 @@ class OpenAIServingChat(OpenAIServing):
is a tool call with arguments. is a tool call with arguments.
""" """
# yapf: disable
return bool( return bool(
# if there is a delta message that includes tool calls which # if there is a delta message that includes tool calls which
# include a function that has arguments # include a function that has arguments
output.finish_reason is not None output.finish_reason is not None
and self.enable_auto_tools and self.tool_parser and delta_message and self.enable_auto_tools
and delta_message.tool_calls and delta_message.tool_calls[0] and self.tool_parser
and delta_message
and delta_message.tool_calls
and delta_message.tool_calls[0]
and delta_message.tool_calls[0].function and delta_message.tool_calls[0].function
and delta_message.tool_calls[0].function.arguments is not None and delta_message.tool_calls[0].function.arguments is not None
) )
......
...@@ -18,8 +18,6 @@ from vllm.entrypoints.openai.protocol import ( ...@@ -18,8 +18,6 @@ from vllm.entrypoints.openai.protocol import (
ErrorResponse, ErrorResponse,
UsageInfo, UsageInfo,
) )
# yapf: enable
from vllm.entrypoints.openai.serving_engine import ( from vllm.entrypoints.openai.serving_engine import (
ClassificationServeContext, ClassificationServeContext,
OpenAIServing, OpenAIServing,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment