@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / a2142f0196
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 15, 06:00 UTC

Support non-string values in JSON keys from CLI (#19471)

Signed-off-by: DarkLight1337 <tlleungac@connect.ust.hk>

Cyrus Leung committed Jun 11, 2025 at 17:34 UTC a2142f01969a7c327da69be1e82a6c01a530116c
3 files changed +48 -24
tests/test_config.py
+17 -17
@@ -13,32 +13,32 @@ from vllm.model_executor.layers.pooler import PoolingType
13 from vllm.platforms import current_platform
14
15
16 -class TestConfig1:
16 +class _TestConfig1:
17 pass
18
19
20 @dataclass
21 -class TestConfig2:
21 +class _TestConfig2:
22 a: int
23 """docstring"""
24
25
26 @dataclass
27 -class TestConfig3:
27 +class _TestConfig3:
28 a: int = 1
29
30
31 @dataclass
32 -class TestConfig4:
32 +class _TestConfig4:
33 a: Union[Literal[1], Literal[2]] = 1
34 """docstring"""
35
36
37 @pytest.mark.parametrize(("test_config", "expected_error"), [
38 - (TestConfig1, "must be a dataclass"),
39 - (TestConfig2, "must have a default"),
40 - (TestConfig3, "must have a docstring"),
41 - (TestConfig4, "must use a single Literal"),
38 + (_TestConfig1, "must be a dataclass"),
39 + (_TestConfig2, "must have a default"),
40 + (_TestConfig3, "must have a docstring"),
41 + (_TestConfig4, "must use a single Literal"),
42 ])
43 def test_config(test_config, expected_error):
44 with pytest.raises(Exception, match=expected_error):
@@ -57,23 +57,23 @@ def test_compile_config_repr_succeeds():
57 assert 'inductor_passes' in val
58
59
60 -def test_get_field():
60 +@dataclass
61 +class _TestConfigFields:
62 + a: int
63 + b: dict = field(default_factory=dict)
64 + c: str = "default"
65
62 - @dataclass
63 - class TestConfig:
64 - a: int
65 - b: dict = field(default_factory=dict)
66 - c: str = "default"
66
67 +def test_get_field():
68 with pytest.raises(ValueError):
69 - get_field(TestConfig, "a")
69 + get_field(_TestConfigFields, "a")
70
71 - b = get_field(TestConfig, "b")
71 + b = get_field(_TestConfigFields, "b")
72 assert isinstance(b, Field)
73 assert b.default is MISSING
74 assert b.default_factory is dict
75
76 - c = get_field(TestConfig, "c")
76 + c = get_field(_TestConfigFields, "c")
77 assert isinstance(c, Field)
78 assert c.default == "default"
79 assert c.default_factory is MISSING
tests/test_utils.py
+15
@@ -272,6 +272,15 @@ def test_dict_args(parser):
272 "val5",
273 "--hf_overrides.key-7.key_8",
274 "val6",
275 + # Test data type detection
276 + "--hf_overrides.key9",
277 + "100",
278 + "--hf_overrides.key10",
279 + "100.0",
280 + "--hf_overrides.key11",
281 + "true",
282 + "--hf_overrides.key12.key13",
283 + "null",
284 ]
285 parsed_args = parser.parse_args(args)
286 assert parsed_args.model_name == "something.something"
@@ -286,6 +295,12 @@ def test_dict_args(parser):
295 "key-7": {
296 "key_8": "val6",
297 },
298 + "key9": 100,
299 + "key10": 100.0,
300 + "key11": True,
301 + "key12": {
302 + "key13": None,
303 + },
304 }
305
306
vllm/utils.py
+16 -7
@@ -1466,7 +1466,7 @@ class FlexibleArgumentParser(ArgumentParser):
1466 pattern = re.compile(r"(?<=--)[^\.]*")
1467
1468 # Convert underscores to dashes and vice versa in argument names
1469 - processed_args = []
1469 + processed_args = list[str]()
1470 for arg in args:
1471 if arg.startswith('--'):
1472 if '=' in arg:
@@ -1483,7 +1483,7 @@ class FlexibleArgumentParser(ArgumentParser):
1483 else:
1484 processed_args.append(arg)
1485
1486 - def create_nested_dict(keys: list[str], value: str):
1486 + def create_nested_dict(keys: list[str], value: str) -> dict[str, Any]:
1487 """Creates a nested dictionary from a list of keys and a value.
1488
1489 For example, `keys = ["a", "b", "c"]` and `value = 1` will create:
@@ -1494,7 +1494,10 @@ class FlexibleArgumentParser(ArgumentParser):
1494 nested_dict = {key: nested_dict}
1495 return nested_dict
1496
1497 - def recursive_dict_update(original: dict, update: dict):
1497 + def recursive_dict_update(
1498 + original: dict[str, Any],
1499 + update: dict[str, Any],
1500 + ):
1501 """Recursively updates a dictionary with another dictionary."""
1502 for k, v in update.items():
1503 if isinstance(v, dict) and isinstance(original.get(k), dict):
@@ -1502,19 +1505,25 @@ class FlexibleArgumentParser(ArgumentParser):
1505 else:
1506 original[k] = v
1507
1505 - delete = set()
1506 - dict_args: dict[str, dict] = defaultdict(dict)
1508 + delete = set[int]()
1509 + dict_args = defaultdict[str, dict[str, Any]](dict)
1510 for i, processed_arg in enumerate(processed_args):
1511 if processed_arg.startswith("--") and "." in processed_arg:
1512 if "=" in processed_arg:
1510 - processed_arg, value = processed_arg.split("=", 1)
1513 + processed_arg, value_str = processed_arg.split("=", 1)
1514 if "." not in processed_arg:
1515 # False positive, . was only in the value
1516 continue
1517 else:
1515 - value = processed_args[i + 1]
1518 + value_str = processed_args[i + 1]
1519 delete.add(i + 1)
1520 +
1521 key, *keys = processed_arg.split(".")
1522 + try:
1523 + value = json.loads(value_str)
1524 + except json.decoder.JSONDecodeError:
1525 + value = value_str
1526 +
1527 # Merge all values with the same key into a single dict
1528 arg_dict = create_nested_dict(keys, value)
1529 recursive_dict_update(dict_args[key], arg_dict)