Skip to content

Releases: JeanKossaifi/zencfg

Release 0.7.0

27 Feb 00:43
df0f475

Choose a tag to compare

New features

  • instantiate(): Config objects can now create instances of their target class
    directly via config.instantiate(). Supports _target_class as a class reference
    or a fully-qualified string (e.g. "torch.nn.Linear"). Nested configs with
    _target_class are instantiated recursively by default (set recursive=False to turn it off).

  • make_config(): New unified entry point that creates a config from a class,
    instance, or file path with optional keyword overrides.

  • make_config_from_cli(): Replaces cfg_from_commandline with a cleaner API.
    Supports classes, instances, and file paths with CLI argument overrides.

Improvements

  • File loading rewritten: load_config_from_file now takes (config_path, config_file, config_name)
    and properly supports relative imports within config packages via a temporary namespace.
  • Generic container passthrough: Dict[str, MyConfig], Tuple[MyConfig, ...]
    and other generic types containing ConfigBase are passed through without
    crashing Pydantic's TypeAdapter.
  • Cleaner error messages: Type validation errors now show the expected type
    and clear readable message.

Breaking changes

  • load_config_from_file(file_path, config_name) signature changed to
    load_config_from_file(config_path, config_file, config_name).
  • cfg_from_commandline is deprecated in favor of make_config_from_cli.

Full Changelog: 0.6.0...0.7.0

Release 0.6.0

11 Sep 14:57

Choose a tag to compare

Migration

Previous usage:

Config = load_config_from_file("configs/experiment.py")

New usage:

Config = load_config_from_file(
    config_path="configs/",
    config_file="experiment.py",
    config_name="ExperimentConfig"
)

The explicit API eliminates ambiguity about package boundaries, making the behavior predictable and debuggable. In particular, it allows for more intuitive imports in the configs directly, more on that below.

Enhanced instantiate() Method

The instantiate() method now accepts additional positional and keyword arguments, enabling integration with frameworks that require runtime objects:

class OptimizerConfig(ConfigBase):
    _target_class = "torch.optim.Adam"
    lr: float = 0.001
    weight_decay: float = 0.0

# Pass model.parameters() as first argument
optimizer = config.optimizer.instantiate(model.parameters())

# Override config values at instantiation
optimizer = config.optimizer.instantiate(model.parameters(), lr=0.01)

This change addresses a common pattern in machine learning frameworks where constructors require runtime objects (such as the optimizer needing the model parameters) that cannot be determined at configuration time.

Improved File Loading API

The load_config_from_file function has been redesigned with an explicit API that properly handles Python package structures:

Config = load_config_from_file(
    config_path="configs/",              # Package root directory
    config_file="experiments/bert.py",   # Path relative to config_path
    config_name="BertConfig"             # Class or instance name to load
)

Key improvements:

  • Full support for relative imports within config files
  • Proper handling of nested directory structures
  • Isolated module loading prevents namespace conflicts
  • Clear separation between package root and module path

Example: Config Files with Relative Imports

Given this structure:

configs/
├── models/
│   ├── base.py       # Contains base model config
│   ├── unet.py       # Contains U-Net config
│   └── dit.py        # Contains DiT config
└── experiments/
    └── main_config.py   # Contains overall config

Your config files can now use relative imports.
Your configs/experiments/main_config.py file could look like this:

from zencfg import ConfigBase
from ..models.base import ModelConfig
from ..models.dit import DiTConfig

class MainConfig(ConfigBase):
    model: ModelConfig = DiTConfig()
    batch_size: int = 32
    learning_rate: float = 0.001

You can then load it from your main Python script to run experiments like this:

MainConfig = load_config_from_file(
    config_path="configs/",
    config_file="experiments/main_config.py",
    config_name="MainConfig"
)
config = MainConfig()  # Create an instance

This enables proper code organization with shared base configurations and modular component configs.

CLI Override Support

The make_config_from_cli function now supports the same explicit API as load_config_from_file. In your main experiment script, you can have:

from zencfg import make_config_from_cli

if __name__ == "__main__":
    # Load config from file with CLI overrides in one step
    config = make_config_from_cli(
        "configs/",                        # config_path
        "experiments/main_config.py",      # config_file  
        "MainConfig"                       # config_name
    )
    
    # Config values are overridden via CLI arguments
    print(f"Model hidden size: {config.model.hidden_size}")
    print(f"Batch size: {config.batch_size}")
    print(f"Learning rate: {config.learning_rate}")

Command-line usage:

python main.py \
    --model.hidden_size 2048 \
    --model.num_layers 32 \
    --batch_size 64 \
    --learning_rate 0.0001

The function also maintains backward compatibility for direct class usage:

config = make_config_from_cli(MyConfigClass)  # Pass class directly

This allows flexible experimentation without modifying config files.

Bug Fixes

  • Fixed _latest_instances incorrectly being passed to target constructors during instantiation
  • Fixed _target_class attribute loss during CLI-based configuration parsing
  • Improved internal attribute handling to prevent leakage into user configurations

API Updates

Enhanced make_config_from_cli

The function now supports the same explicit API as load_config_from_file while maintaining full backward compatibility:

  • New usage: make_config_from_cli(config_path, config_file, config_name)
  • Still works: make_config_from_cli(ConfigClass) and make_config_from_cli(file_path, config_name="...")

Breaking Changes

  • load_config_from_file now requires an explicit config_name parameter
  • load_config_from_file signature changed from (file_path, config_name=None) to (config_path, config_file, config_name)

Full Changelog: 0.5.1...0.6.0

Release 0.5.1

26 Aug 20:51

Choose a tag to compare

More robust instantiation of objects from config

Release 0.5.0

26 Aug 19:27
041a787

Choose a tag to compare

Better auto-instantiation from config, supports additional args and kwargs.
Improved tests and documentation.

Full Changelog: 0.4.0...0.5.0

Release 0.4.0

30 Jul 18:47
c0cba9c

Choose a tag to compare

Better API to create configurations (make_config*) and load them directly from file (load_config_from_file).
Types get correctly checked when instantiating a ConfigBase directly.
Added a proper documentation and website.
Error messages are now more helpful, with several improvements and code cleanups.
We now properly support arguments without type hints.
Added more unit-tests.

Full Changelog: 0.3.0...0.4.0

Release 0.3.0

22 May 04:06
847f96e

Choose a tag to compare

Brings in more improvement for an even more zen configuration experience!

Now properly supports things like Union[List[int], int] from the command line.
Also adds better support of default values (see gotcha) for cases like this:

class Config(ConfigBase):
    model: Model = SubModel()

In this case, if a user passes --model.param value, they would have previously gotten the default type (Model), instead of the expected SubModel. This is now fixed, see the Gotcha section in the README.

Release 0.2.0

28 Jan 22:24

Choose a tag to compare

Simpler command line interface

Now, instead of passing the configuration names as

python script.py --config_category._name NAME --config_category.param value

you can simply write:

python script.py --config_category.NAME --config_category.param value

I also renamed _name to _config_name for clarity, so the variable more clearly indicates its use.

More unit-tests

Added tests to verify new behavior

New example folder

Added an example folder with example script so you can directly try the configuration system

Release 0.1.0

27 Jan 21:04

Choose a tag to compare

Workflow: Missing part