Source code for zencfg.from_commandline

import sys
import warnings
from typing import Type, Union, Optional, Any
from pathlib import Path

from .from_dict import make_config_from_flat_dict
from .config import ConfigBase


[docs] def make_config(source: Union[Type[ConfigBase], ConfigBase, str, Path], name: Optional[str] = None, /, **overrides) -> ConfigBase: """Create a config instance from any source with overrides. Parameters ---------- source : Union[Type[ConfigBase], ConfigBase, str, Path] Source to create config from: - ConfigBase class: instantiate with overrides - ConfigBase instance: apply overrides to copy - str/Path: file path to load config from name : str, optional Required when source is a file path. Name of class/instance to load. **overrides Keyword arguments to override in the config Returns ------- ConfigBase Config instance with overrides applied Examples -------- >>> # From class >>> config = make_config(TrainingConfig, batch_size=32) >>> >>> # From file >>> config = make_config("configs.py", "TrainingConfig", epochs=100) >>> config = make_config(Path("configs.py"), "TrainingConfig", epochs=100) >>> >>> # From instance >>> base = TrainingConfig() >>> config = make_config(base, learning_rate=0.001) """ if isinstance(source, type) and issubclass(source, ConfigBase): # It's a class - instantiate with overrides return source(**overrides) elif isinstance(source, ConfigBase): # It's an instance - apply overrides if not overrides: return source # No changes needed current_dict = source.to_dict(flatten=True) current_dict.update({k: str(v) for k, v in overrides.items()}) # Convert to strings for make_config_from_flat_dict return make_config_from_flat_dict(source.__class__, current_dict) elif isinstance(source, (str, Path)): # It's a file path - load and handle if name is None: raise ValueError("name parameter is required when loading from file") from .from_file import load_config_from_file loaded_item = load_config_from_file(str(source), name) return make_config(loaded_item, **overrides) # Recursive call else: raise TypeError(f"Unsupported source type: {type(source)}. Expected ConfigBase class, instance, or file path.")
[docs] def make_config_from_cli(source: Union[Type[ConfigBase], ConfigBase, str, Path], name: Optional[str] = None, /, strict: bool = False) -> ConfigBase: """Create a config instance with command-line argument overrides. Parameters ---------- source : Union[Type[ConfigBase], ConfigBase, str, Path] Source to create config from (class, instance, or file path) name : str, optional Required when source is a file path. Name of class/instance to load. strict : bool, default=False If True, raises errors on type conversion failures Returns ------- ConfigBase Config instance with command-line overrides applied Examples -------- >>> # From class >>> config = make_config_from_cli(TrainingConfig) >>> >>> # From file >>> config = make_config_from_cli("configs.py", "TrainingConfig") >>> config = make_config_from_cli(Path("configs.py"), "TrainingConfig") """ args = sys.argv[1:] # Skip the script name if len(args) % 2 != 0: raise ValueError("Arguments must be in pairs like: --model._config_name MyModel --model.layers 24") # Build arg dict from command line arg_dict = {} for i in range(0, len(args), 2): key = args[i].lstrip('-') arg_dict[key] = args[i + 1] if isinstance(source, type) and issubclass(source, ConfigBase): # It's a class - create instance with CLI overrides return make_config_from_flat_dict(source, arg_dict, strict=strict) elif isinstance(source, ConfigBase): # It's an instance - merge CLI overrides with existing values current_dict = source.to_dict(flatten=True) current_dict.update(arg_dict) # CLI args override existing values return make_config_from_flat_dict(source.__class__, current_dict, strict=strict) elif isinstance(source, (str, Path)): # It's a file path - load and handle if name is None: raise ValueError("name parameter is required when loading from file") from .from_file import load_config_from_file loaded_item = load_config_from_file(str(source), name) return make_config_from_cli(loaded_item, strict=strict) # Recursive call else: raise TypeError(f"Unsupported source type: {type(source)}. Expected ConfigBase class, instance, or file path.")