Skip to content

Commit 5d198dc

Browse files
alex-jw-brooksLeiWang1999
authored andcommitted
[Frontend] Improve Nullable kv Arg Parsing (vllm-project#8525)
Signed-off-by: Alex-Brooks <Alex.Brooks@ibm.com> Signed-off-by: LeiWang1999 <leiwang1999@outlook.com>
1 parent 65e09d6 commit 5d198dc

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

tests/engine/test_arg_utils.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
from argparse import ArgumentTypeError
2+
13
import pytest
24

3-
from vllm.engine.arg_utils import EngineArgs
5+
from vllm.engine.arg_utils import EngineArgs, nullable_kvs
46
from vllm.utils import FlexibleArgumentParser
57

68

@@ -13,6 +15,10 @@
1315
"image": 16,
1416
"video": 2
1517
}),
18+
("Image=16, Video=2", {
19+
"image": 16,
20+
"video": 2
21+
}),
1622
])
1723
def test_limit_mm_per_prompt_parser(arg, expected):
1824
parser = EngineArgs.add_cli_args(FlexibleArgumentParser())
@@ -22,3 +28,15 @@ def test_limit_mm_per_prompt_parser(arg, expected):
2228
args = parser.parse_args(["--limit-mm-per-prompt", arg])
2329

2430
assert args.limit_mm_per_prompt == expected
31+
32+
33+
@pytest.mark.parametrize(
34+
("arg"),
35+
[
36+
"image", # Missing =
37+
"image=4,image=5", # Conflicting values
38+
"image=video=4" # Too many = in tokenized arg
39+
])
40+
def test_bad_nullable_kvs(arg):
41+
with pytest.raises(ArgumentTypeError):
42+
nullable_kvs(arg)

vllm/engine/arg_utils.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,36 @@ def nullable_str(val: str):
4444

4545

4646
def nullable_kvs(val: str) -> Optional[Mapping[str, int]]:
47+
"""Parses a string containing comma separate key [str] to value [int]
48+
pairs into a dictionary.
49+
50+
Args:
51+
val: String value to be parsed.
52+
53+
Returns:
54+
Dictionary with parsed values.
55+
"""
4756
if len(val) == 0:
4857
return None
4958

5059
out_dict: Dict[str, int] = {}
5160
for item in val.split(","):
52-
try:
53-
key, value = item.split("=")
54-
except TypeError as exc:
55-
msg = "Each item should be in the form KEY=VALUE"
56-
raise ValueError(msg) from exc
61+
kv_parts = [part.lower().strip() for part in item.split("=")]
62+
if len(kv_parts) != 2:
63+
raise argparse.ArgumentTypeError(
64+
"Each item should be in the form KEY=VALUE")
65+
key, value = kv_parts
5766

5867
try:
59-
out_dict[key] = int(value)
68+
parsed_value = int(value)
6069
except ValueError as exc:
6170
msg = f"Failed to parse value of item {key}={value}"
62-
raise ValueError(msg) from exc
71+
raise argparse.ArgumentTypeError(msg) from exc
72+
73+
if key in out_dict and out_dict[key] != parsed_value:
74+
raise argparse.ArgumentTypeError(
75+
f"Conflicting values specified for key: {key}")
76+
out_dict[key] = parsed_value
6377

6478
return out_dict
6579

0 commit comments

Comments
 (0)