Laco — Lazy Configuration for Reproducible ML
LAzy COnfiguration (Laco) is a Python-first configuration system that gives you type-checked, IDE-navigable configs with zero magic strings. It is compatible with Hydra and a drop-in alternative to hydra-zen.
Key ideas
| Construct | Static type | What you get |
|---|---|---|
L.call(T)(**kw) |
T |
lazy _target_: node |
L.partial(T)(**kw) |
functools.partial[T] |
lazy _partial_: true node |
L.just(obj) |
type(obj) |
identity-instantiated node |
L.required[T]() |
T |
MISSING sentinel |
class G(L.Group[T]) |
typed group | registers in Hydra ConfigStore |
@L.config class S |
dataclass schema | structured-config target |
@L.task |
task wrapper | auto-instantiates config fields |
@laco.main(config_name=…) |
Hydra app | composes config + runs task |
L.trace(lambda: …) |
R |
records a config tree from Python |
30-second example
import laco
import laco.language as L
from torch import nn, optim
# --- Groups: swappable variants ---
class OptimGroup(L.Group[optim.Optimizer]):
sgd = L.partial(optim.SGD)(lr=L.required[float](), momentum=0.9)
adam = L.partial(optim.Adam)(lr=1e-3)
# --- Schema: typed config ---
@L.config
class TrainSchema:
epochs: int = 10
optimizer: optim.Optimizer = L.slot(OptimGroup)
# --- Model ---
model_cfg = L.call(nn.Linear)(in_features=784, out_features=10)
# --- Task: runs with a composed config ---
@laco.main(config_name="train")
@L.task
def run(model: nn.Module, optimizer: optim.Optimizer, epochs: int = 10):
opt = optimizer(model.parameters())
# ... training loop ...
if __name__ == "__main__":
run()
Override from the CLI:
python train.py optimizer=adam epochs=20
python train.py -m optimizer=sgd,adam optimizer.lr=1e-2,1e-3 # multirun
Tracing
@L.configurable
class Encoder:
def __init__(self, depth: int) -> None: ...
# Records a config tree — no constructors run:
cfg = L.trace(lambda: Encoder(depth=24))
# Reproduce the object:
enc = laco.instantiate(cfg)
Examples
The sources/laco/examples/ directory contains a curriculum of examples:
| Tier | Files | What it demonstrates |
|---|---|---|
| 0–1 | mlp.py, linear_regression.py, cnn_classifier.py, text_classifier.py |
Basics: L.call, L.params, L.required |
| 2 | blocks/residual.py, blocks/transformer.py, blocks/decoder.py |
Building blocks |
| 3–4 | models/ |
Vision & language model configs |
| 5 | integrations/ |
Lightning, Transformers, TensorDict |
| 6 | pipelines/mnist_train.py, pipelines/clm_finetune.py |
End-to-end training pipelines with @L.task |
Typed-group variants live in examples/typed/ (same models, @L.config + L.Group API).
CLI
laco compose configs/train.py # load & dump YAML
laco compose configs/train.py lr=1e-3 # with overrides
laco show configs/train.py --groups # list registered groups
laco run configs/train.py # run the @L.task entry point
laco diff configs/a.py configs/b.py # diff two config files
laco app my-project train --lr 1e-4 # run a laco.apps entry point
laco app — simple argparse CLI for published configs
Researchers and collaborators can reproduce experiments without knowing Hydra:
laco app my-project train --help # show all available flags
laco app my-project train --lr 1e-4 # override a hyperparameter
laco app my-project train --dry-run # preview resolved config as YAML
laco app my-project train --save-dir out/ # save config.yaml before running
Flags are derived from @L.params blocks and L.param() declarations in
the config file. Authors register the entry point in pyproject.toml:
[project.entry-points."laco.apps"]
train = "my_project.train:run"
See docs/how-to/laco-app.md for the full author and user guide.
Migration from 0.x
Add import laco.compat once at startup to enable deprecation warnings
for legacy _target_: laco.ops.partial configs. Run laco fix <dir> to
rewrite them in-place.
Linting
Two lint passes run in CI and are available locally:
nix run .#lint— ruff oversources/andtests/.nix run .#lie-lint(orlaco-lint sources/) — LACO001, a heuristic AST check for attribute access on lie-typed Laco nodes. Suppress with# noqa: LACO001.
Metadata
Release files for laco 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| laco-1.0.0.tar.gz | 412.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| laco-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 517.5 kB
Release files / laco-1.0.0.tar.gz
| Download URL | laco-1.0.0.tar.gz |
|---|---|
| Size | 412.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
345d4d456d94bee7c2a882b998d7d0609e5a3bbe3a7bc8b8e6964771a786ea18
|
|
BLAKE2b-256 checksum How to use checksums |
e091daf63ceb7495b278c880be8cafa68e0666465379dc6a785b7288ca0ec78e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.11","id":"zokor","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / laco-1.0.0-py3-none-any.whl
| Download URL | laco-1.0.0-py3-none-any.whl |
|---|---|
| Size | 104.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c6889acf731c416349a7b50e7925df38ce804c06344ecaa4e3a81e9ea6a09d8c
|
|
BLAKE2b-256 checksum How to use checksums |
59b91b5e2d237ccc6200177834a12920b7e7c6750f4903b2b42a184dc3377b32
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.11","id":"zokor","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|