API Reference#
Core Classes#
ConfigBase#
The main configuration class that provides inheritance, type validation, serialization, and auto-discovery capabilities.
- class zencfg.ConfigBase(**kwargs)[source]#
Bases:
object
Base class for all config objects, instanciates a new ConfigBase object.
Class creation We manually enable inheritance of class-level attributes (see notes for detail). You can specify which configuration (sub)-class you actually want to create by passing a “_config_name” key in kwargs. The subclass with that _config_name will be instantiated instead of the BaseConfig.
Class hierarchy Each direct descendent from ConfigBase will have a _registry attribute and track their children. In other words, for each main configuration category, create one subclass. Each config instance in this category should inherit from that subclass.
Auto-discovery ConfigBase automatically tracks the latest instance of each config type. Use AutoConfig() as a default value to automatically populate fields with the latest instance.
Notes
AutoConfig best practices: For reliable auto-discovery, define config classes in importable modules (not in main scripts). Content modules creating instances must be imported to execute their code and register instances.
- Recommended structure:
Define classes in:
models/config.py
or similar importable modulesCreate instances in:
content/*.py
or configuration modulesImport content modules in:
main.py
or package__init__.py
Avoid defining config classes directly in main scripts (causes class identity issues)
Attribute inheritance: Note that by default, attributes are not inherited since they are class-level attributes, not actual constructor parameters. By default, Python does not automatically copy class attributes into instance attributes at
__init__
time.To fix this, we manually collect the defaults:
- gather_defaults(cls):
walk the entire Method Resolution Order (MRO), from the root (object) up to the child class, collecting all fields that are not private or callable.
Because we do
for base in reversed(cls.__mro__):
, we effectively start from the oldest parent (like Checkpoint) and end at the child (CheckpointSubclass), so the child can override any fields if it redefines them.
- __init__:
We call gather_defaults(type(self)) to get all inherited fields.
Check for any missing required fields (not in defaults).
Assign defaults to self.
Then override with any passed-in kwargs, including name.
- instantiate(*args, **kwargs) Any [source]#
Instantiate the target class with config parameters and optional additional arguments.
This method creates an instance of the class specified in _target_class using the configuration parameters as constructor arguments, along with any additional positional or keyword arguments provided.
Only the current config is instantiated - nested ConfigBase objects are passed as-is (not recursively instantiated).
- Parameters:
- Returns:
An instance of the target class
- Return type:
Any
- Raises:
NotImplementedError – If _target_class is not set and this method is not overridden
ImportError – If the target class cannot be imported
TypeError – If the target class cannot be instantiated with the given parameters
Examples
You can specify the target class as a class directly or as a string:
>>> class LinearConfig(ConfigBase): ... _target_class = "torch.nn.Linear" ... in_features: int = 784 ... out_features: int = 10 >>> config = LinearConfig() >>> model = config.instantiate() # Creates torch.nn.Linear(in_features=784, out_features=10)
With additional arguments (e.g., for optimizers):
>>> class OptimizerConfig(ConfigBase): ... _target_class = "torch.optim.Adam" ... lr: float = 0.001 ... betas: tuple = (0.9, 0.999) >>> config = OptimizerConfig() >>> optimizer = config.instantiate(model.parameters()) # Pass model.parameters() as first arg
Override config parameters with kwargs:
>>> config = LinearConfig(out_features=10) >>> model = config.instantiate(out_features=20) # kwargs override config values >>> # Creates torch.nn.Linear(in_features=784, out_features=20)
Alternatively, you can customize the instantiate method:
>>> class CustomConfig(ConfigBase): ... param1: int = 42 ... def instantiate(self, *args, **kwargs): ... return MyCustomClass(self.param1, *args, **kwargs) >>> config = CustomConfig() >>> obj = config.instantiate(additional_param="test")
AutoConfig#
A sentinel class for automatic instance discovery. When used as a default value, the field will be automatically populated with the latest instance of its type.
Bunch#
A dictionary-like object that exposes its keys as attributes, with special handling for nested updates.
This is what we return when we use the config.to_dict()
method.
- class zencfg.bunch.Bunch(init={})[source]#
Bases:
dict
A dict exposing its keys as attributes
Warning
We override the default update function. The new one updates each nested dict individually. This may be a surprising behaviour.
Notes
At init, we explicitly go through each key, value pair to make sure that a nested dict becomes a nested Bunch.
We override the update to make sure that a nested Bunch is updated correctly. This may be a surprising behaviour.
Examples
>>> test = {'a': {'b': 3, 'c': 4}, 'd': 5} >>> bunch = Bunch(test)
# Check what happens if we update an element with another dict: >>> bunch.update(dict(a=dict(b=5))) {‘a’: {‘b’: 5, ‘c’: 4}, ‘d’: 5}
# Compare this with what happens if we update a regular dict: >>> test.update(dict(a=dict(b=5))) {‘a’: {‘b’: 5}, ‘d’: 5}
Loading and Instantiating Configurations#
make_config#
Create a config instance from any source: - ConfigBase class: instantiate with optional overrides - ConfigBase instance: apply overrides to a copy of instance - File path (str or Path): load a configuration class or instance from a file
- zencfg.make_config(source: Type[ConfigBase] | ConfigBase | str | Path, name: str | None = None, /, **overrides) ConfigBase [source]#
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 (auto-detects class if name not provided)
name (str, optional) – Name of class/instance to load from file. If None, auto-detects ConfigBase subclass.
**overrides – Keyword arguments to override in the config
- Returns:
Config instance with overrides applied
- Return type:
Examples
>>> # From class >>> config = make_config(TrainingConfig, batch_size=32) >>> >>> # From file - name is now optional! >>> config = make_config("configs/experiment.py", epochs=100) # Auto-detects >>> config = make_config("configs.py", "TrainingConfig", epochs=100) # Explicit >>> >>> # From instance >>> base = TrainingConfig() >>> config = make_config(base, learning_rate=0.001)
make_config_from_cli#
Override any parameters of a configuration via the command-line argument. The configuration to load can be given as class, instance, or file.
- zencfg.make_config_from_cli(config_or_path: Type[ConfigBase] | ConfigBase | str | Path, config_file: str | Path | None = None, config_name: str | None = None, *, strict: bool = False) ConfigBase [source]#
Create a config instance with command-line argument overrides.
This function supports two usage patterns:
Pass a ConfigBase class or instance directly
Load from a file using the same API as load_config_from_file
- Parameters:
config_or_path (Union[Type[ConfigBase], ConfigBase, str, Path]) – Either: - A ConfigBase class or instance to apply CLI overrides to - A config_path (when config_file is also provided) - A single file path (when config_file is None, for backward compatibility)
config_file (Union[str, Path], optional) – If provided, config_or_path is treated as config_path and this specifies the file relative to config_path (matching load_config_from_file API)
config_name (str, optional) – Name of class/instance to load from file. Required when loading from file.
strict (bool, default=False) – If True, raises errors on type conversion failures
- Returns:
Config instance with command-line overrides applied
- Return type:
Examples
>>> # From class >>> config = make_config_from_cli(TrainingConfig) >>> >>> # From file - new explicit API (recommended) >>> config = make_config_from_cli( ... config_path="configs/", ... config_file="experiments/main.py", ... config_name="MainConfig" ... ) >>> >>> # From file - backward compatible single path >>> config = make_config_from_cli("configs/experiment.py", config_name="TrainingConfig")
make_config_from_flat_dict#
Create a configuration instance from a flat dictionary (with dot notation to signify nested keys).
- zencfg.make_config_from_flat_dict(config_cls: Any, flat_dict: Dict[str, Any], strict: bool = False) Any [source]#
Instantiates a config class from a flat dictionary.
- Parameters:
config_cls (ConfigBase) – The config class to instantiate.
flat_dict (Dict[str, Any]) – “Flat” dict of the form {“key1”: value1, “key2”: value2, “key1.subkey”: “value”, …} It’s a single level dict (no nesting). Instead, the keys are nested using dots.
strict (bool) – If True, raise a TypeError on parsing errors. Otherwise, log a warning.
- Returns:
An instance of ‘config_cls’ with values from ‘flat_dict’ with the loaded values.
- Return type:
make_config_from_nested_dict#
Create a configuration instance from a nested dictionary structure.
- zencfg.make_config_from_nested_dict(config_cls: Any, nested_dict: Dict[str, Any], strict: bool, path: str = '') Any [source]#
Build a config instance from a nested dictionary with inheritance support.
Creates an instance of config_cls (or its appropriate subclass) using values from nested_dict. Handles nested ConfigBase fields recursively.
For ConfigBase fields, values are resolved with the following precedence: 1. Class defaults (from parent and child classes) 2. _config_name (preserved from default instance if not overridden) 3. User-provided values
- Parameters:
config_cls (type) – The config class to instantiate (must be a ConfigBase subclass for inheritance)
nested_dict (dict) – Nested dictionary of values. For ConfigBase fields, can contain either: - str: treated as _config_name to select subclass (e.g. {config_cls: CLASS_NAME_STR}) - dict: values to override in the instance (e.g. {config_cls: {param1: value1, param2: value2}})
strict (bool) – If True, raises on type conversion errors and missing required fields. If False, keeps original values and sets missing fields to None.
path (str, optional) – Current path in the config hierarchy, used for error messages.
- Return type:
Instance of config_cls (or selected subclass) with applied values
- Raises:
TypeError – If invalid value type provided for a ConfigBase field
ValueError – If unknown config keys or missing required fields (in strict mode)
load_config_from_file#
Load a configuration class or instance from a Python file.
- zencfg.load_config_from_file(config_path: str | Path, config_file: str | Path, config_name: str) Type[ConfigBase] | ConfigBase [source]#
Load a configuration from a Python file with full relative import support.
This function loads configurations from Python files, properly handling relative imports within the config package structure. The config module is loaded in a temporary namespace to avoid conflicts with existing modules.
- Parameters:
config_path (Union[str, Path]) – Root directory of your config package. This is where relative imports are resolved from. Use “.” for configs in the current directory.
config_file (Union[str, Path]) – Path to the config file relative to config_path. Can be a simple name (“config.py”) or nested path (“models/bert.py”).
config_name (str) – Name of the ConfigBase class or instance to load from the file.
- Returns:
The loaded configuration class or instance.
- Return type:
Union[Type[ConfigBase], ConfigBase]
- Raises:
FileNotFoundError – If config_path/config_file doesn’t exist
ImportError – If the file cannot be imported (e.g., syntax error, import error)
AttributeError – If config_name is not found in the file
TypeError – If config_name is not a ConfigBase class or instance
ValueError – If config_file is an absolute path
Examples
>>> # Simple config in current directory >>> config = load_config_from_file(".", "config.py", "MyConfig") >>> >>> # Config in subdirectory >>> config = load_config_from_file("configs/", "base.py", "BaseConfig") >>> >>> # Nested config with relative imports >>> config = load_config_from_file( ... config_path="configs/", ... config_file="experiments/nlp/transformer.py", ... config_name="TransformerConfig" ... ) >>> # This file can use: from ...base import BaseConfig >>> >>> # Using Path objects >>> from pathlib import Path >>> config = load_config_from_file( ... config_path=Path("project/configs"), ... config_file=Path("models") / "bert.py", ... config_name="BertConfig" ... )
Notes
The config file is executed as Python code. Only load configs from trusted sources. Module-level code in the config will execute with full permissions. The module namespace is temporary and will be cleaned up, but any side effects (file I/O, environment changes) will persist.
Implementation Details:
The function creates a temporary package structure in sys.modules using a unique namespace (_zencfg_temp_<uuid>). This approach ensures:
Relative imports are resolved correctly based on the package structure
No permanent modifications to sys.path or sys.modules
Complete cleanup after config loading
No conflicts with existing modules in the application
Deprecated Functions#
Warning
The following functions are deprecated and will be removed in a future version.
cfg_from_commandline#
Deprecated since version 1.0.0: Use make_config_from_cli()
instead.
Parse command-line arguments and create a configuration instance.
- zencfg.cfg_from_commandline(config_class: Type[ConfigBase], strict: bool = False) ConfigBase [source]#
Takes a Config class and returns an instance of it, with values updated from command line.
Deprecated since version 1.0.0: Use
make_config_from_cli()
instead.