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 9, 11:15 UTC
[UX] Enable nested configs in config yaml files (#33193)
Michael Goin committed
Jan 28, 2026 at 16:54 UTC
ca1969186dde5fc0f76d22f2124dc0e6e0c9b792
2 files changed
+70
-7
tests/utils_/test_argparse_utils.py
+44
@@ -379,6 +379,50 @@ def test_load_config_file(tmp_path):
379
os.remove(str(config_file_path))
380
381
382
+def test_load_config_file_nested(tmp_path):
383
+ """Test that nested dicts in YAML config are converted to JSON strings."""
384
+ config_data = {
385
+ "port": 8000,
386
+ "compilation-config": {
387
+ "pass_config": {"fuse_allreduce_rms": True},
388
+ },
389
+ }
390
+ config_file_path = tmp_path / "nested_config.yaml"
391
+ with open(config_file_path, "w") as f:
392
+ yaml.dump(config_data, f)
393
+
394
+ parser = FlexibleArgumentParser()
395
+ processed_args = parser.load_config_file(str(config_file_path))
396
+
397
+ assert processed_args[processed_args.index("--port") + 1] == "8000"
398
+ cc_value = json.loads(
399
+ processed_args[processed_args.index("--compilation-config") + 1]
400
+ )
401
+ assert cc_value == {"pass_config": {"fuse_allreduce_rms": True}}
402
+
403
+
404
+def test_nested_config_end_to_end(tmp_path):
405
+ """Test end-to-end parsing of nested configs in YAML files."""
406
+ config_data = {
407
+ "compilation-config": {
408
+ "mode": 3,
409
+ "pass_config": {"fuse_allreduce_rms": True},
410
+ },
411
+ }
412
+ config_file_path = tmp_path / "nested_config.yaml"
413
+ with open(config_file_path, "w") as f:
414
+ yaml.dump(config_data, f)
415
+
416
+ parser = FlexibleArgumentParser()
417
+ parser.add_argument("-cc", "--compilation-config", type=json.loads)
418
+ args = parser.parse_args(["--config", str(config_file_path)])
419
+
420
+ assert args.compilation_config == {
421
+ "mode": 3,
422
+ "pass_config": {"fuse_allreduce_rms": True},
423
+ }
424
+
425
+
426
def test_compilation_mode_string_values(parser):
427
"""Test that -cc.mode accepts both integer and string mode values."""
428
args = parser.parse_args(["-cc.mode", "0"])
vllm/utils/argparse_utils.py
+26
-7
@@ -444,16 +444,30 @@ class FlexibleArgumentParser(ArgumentParser):
444
445
def load_config_file(self, file_path: str) -> list[str]:
446
"""Loads a yaml file and returns the key value pairs as a
447
- flattened list with argparse like pattern
447
+ flattened list with argparse like pattern.
448
+
449
+ Supports both flat configs and nested YAML structures.
450
+
451
+ Flat config example:
452
```yaml
453
port: 12323
454
tensor-parallel-size: 4
455
```
456
returns:
453
- processed_args: list[str] = [
454
- '--port': '12323',
455
- '--tensor-parallel-size': '4'
456
- ]
457
+ ['--port', '12323', '--tensor-parallel-size', '4']
458
+
459
+ Nested config example:
460
+ ```yaml
461
+ compilation-config:
462
+ pass_config:
463
+ fuse_allreduce_rms: true
464
+ speculative-config:
465
+ model: "nvidia/gpt-oss-120b-Eagle3-v2"
466
+ num_speculative_tokens: 3
467
+ ```
468
+ returns:
469
+ ['--compilation-config', '{"pass_config": {"fuse_allreduce_rms": true}}',
470
+ '--speculative-config', '{"model": "nvidia/gpt-oss-120b-Eagle3-v2", ...}']
471
"""
472
extension: str = file_path.split(".")[-1]
473
if extension not in ("yaml", "yml"):
@@ -461,10 +475,10 @@ class FlexibleArgumentParser(ArgumentParser):
475
f"Config file must be of a yaml/yml type. {extension} supplied"
476
)
477
464
- # only expecting a flat dictionary of atomic types
478
+ # Supports both flat configs and nested dicts
479
processed_args: list[str] = []
480
467
- config: dict[str, int | str] = {}
481
+ config: dict[str, Any] = {}
482
try:
483
with open(file_path) as config_file:
484
config = yaml.safe_load(config_file)
@@ -484,6 +498,11 @@ class FlexibleArgumentParser(ArgumentParser):
498
processed_args.append("--" + key)
499
for item in value:
500
processed_args.append(str(item))
501
+ elif isinstance(value, dict):
502
+ # Convert nested dicts to JSON strings so they can be parsed
503
+ # by the existing JSON argument parsing machinery.
504
+ processed_args.append("--" + key)
505
+ processed_args.append(json.dumps(value))
506
else:
507
processed_args.append("--" + key)
508
processed_args.append(str(value))