Releases: JeanKossaifi/zencfg
Release 0.7.0
New features
-
instantiate(): Config objects can now create instances of their target class
directly viaconfig.instantiate(). Supports_target_classas a class reference
or a fully-qualified string (e.g."torch.nn.Linear"). Nested configs with
_target_classare instantiated recursively by default (setrecursive=Falseto 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(): Replacescfg_from_commandlinewith a cleaner API.
Supports classes, instances, and file paths with CLI argument overrides.
Improvements
- File loading rewritten:
load_config_from_filenow 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 containingConfigBaseare passed through without
crashing Pydantic'sTypeAdapter. - 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_commandlineis deprecated in favor ofmake_config_from_cli.
Full Changelog: 0.6.0...0.7.0
Release 0.6.0
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.001You 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 instanceThis 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.0001The function also maintains backward compatibility for direct class usage:
config = make_config_from_cli(MyConfigClass) # Pass class directlyThis allows flexible experimentation without modifying config files.
Bug Fixes
- Fixed
_latest_instancesincorrectly being passed to target constructors during instantiation - Fixed
_target_classattribute 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)andmake_config_from_cli(file_path, config_name="...")
Breaking Changes
load_config_from_filenow requires an explicitconfig_nameparameterload_config_from_filesignature 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
More robust instantiation of objects from config
Release 0.5.0
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
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
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
Simpler command line interface
Now, instead of passing the configuration names as
python script.py --config_category._name NAME --config_category.param valueyou can simply write:
python script.py --config_category.NAME --config_category.param valueI 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
Workflow: Missing part