Migration Guide: v2 to v3¶
This guide will help you migrate from params-proto v2 to v3.
What Changed?¶
params-proto v3 is a complete redesign with a cleaner, more Pythonic API. The key changes are:
Aspect |
v2 |
v3 |
|---|---|---|
API Style |
Class inheritance ( |
Decorators ( |
Type Hints |
Optional |
Required |
Documentation |
Manual docstrings |
Inline comments |
Functions |
Not supported |
Full support |
Union Types |
Limited support |
Full support |
Prefixes |
Manual prefix string |
|
Quick Comparison¶
v2 Syntax¶
from params_proto import ParamsProto
class Args(ParamsProto):
"""Training arguments"""
lr = 0.001
batch_size = 32
epochs = 100
# CLI parsing
Args.parse_args()
v3 Syntax¶
from params_proto import proto
@proto
class Args:
"""Training arguments"""
lr: float = 0.001 # Learning rate
batch_size: int = 32 # Batch size
epochs: int = 100 # Number of epochs
Step-by-Step Migration¶
Step 1: Replace Inheritance with Decorator¶
v2:
from params_proto import ParamsProto
class Config(ParamsProto):
lr = 0.001
batch_size = 32
v3:
from params_proto import proto
@proto
class Params: lr: float = 0.001
batch_size: int = 32
Step 2: Add Type Hints¶
Type hints are required in v3. Add them to all your parameters:
v2:
class Config(ParamsProto):
lr = 0.001
batch_size = 32
model_name = "resnet50"
use_gpu = True
v3:
@proto
class Params: lr: float = 0.001
batch_size: int = 32
model_name: str = "resnet50"
use_gpu: bool = True
Step 3: Convert Documentation¶
Inline comments automatically become help text in v3:
v2:
class Config(ParamsProto):
"""
Training configuration.
Args:
lr: Learning rate for optimizer
batch_size: Size of training batches
"""
lr = 0.001
batch_size = 32
v3:
@proto
class Params: """Training configuration."""
lr: float = 0.001 # Learning rate for optimizer
batch_size: int = 32 # Size of training batches
Step 4: Update Prefixed Configs¶
The prefix system is much simpler in v3:
v2:
from params_proto import Proto
@Proto(prefix="Model")
class ModelConfig:
name = "resnet50"
pretrained = True
@Proto(prefix="Training")
class TrainingConfig:
lr = 0.001
epochs = 100
v3:
from params_proto import proto
@proto.prefix
class Model:
name: str = "resnet50"
pretrained: bool = True
@proto.prefix
class Training:
lr: float = 0.001
epochs: int = 100
Step 5: CLI Entry Points¶
v2:
class Args(ParamsProto):
lr = 0.001
batch_size = 32
Args.parse_args()
def main():
print(f"LR: {Args.lr}")
if __name__ == "__main__":
main()
v3:
@proto.cli
def main(
lr: float = 0.001,
batch_size: int = 32,
):
"""Main entry point."""
print(f"LR: {lr}")
if __name__ == "__main__":
main()
Or with classes:
@proto
class Args:
lr: float = 0.001
batch_size: int = 32
# Access directly
print(f"LR: {Args.lr}")
Step 6: Parameter Overrides¶
Override syntax is similar but more flexible:
v2:
Args.lr = 0.01
Args.batch_size = 64
v3 (same plus more options):
# Option 1: Direct assignment
Args.lr = 0.01
# Option 2: Function kwargs
main(lr=0.01, batch_size=64)
# Option 3: Context manager
with proto.bind(lr=0.01, batch_size=64):
main()
# Option 4: Prefixed overrides
proto.bind(**{"Training.lr": 0.01, "Model.name": "vit"})
Feature Mapping¶
Environment Variables¶
v2:
class Config(ParamsProto):
data_path = Proto(env="DATA_PATH", default="./data")
v3:
import os
@proto
class Params: data_path: str = os.getenv("DATA_PATH", "./data")
Flags (Boolean Arguments)¶
v2:
from params_proto import Flag
class Config(ParamsProto):
debug = Flag()
use_cuda = Flag()
v3:
@proto
class Params: debug: bool = False
use_cuda: bool = False
Nested Configs¶
v2:
class ModelConfig(ParamsProto):
name = "resnet50"
class Config(ParamsProto):
model = ModelConfig()
lr = 0.001
v3:
@proto.prefix
class Model:
name: str = "resnet50"
@proto
class Params: lr: float = 0.001
# Access as Model.name from CLI or code
Common Patterns¶
Pattern 1: ML Training Script¶
v2:
class Args(ParamsProto):
model = "resnet50"
lr = 0.001
epochs = 100
Args.parse_args()
def train():
model = load_model(Args.model)
optimizer = Adam(lr=Args.lr)
for epoch in range(Args.epochs):
# ...
v3:
@proto.cli
def train(
model: str = "resnet50",
lr: float = 0.001,
epochs: int = 100,
):
"""Train a model."""
model_obj = load_model(model)
optimizer = Adam(lr=lr)
for epoch in range(epochs):
# ...
if __name__ == "__main__":
train()
Pattern 2: Experiment Sweeps¶
v2:
from params_proto.hyper import Sweep
with Sweep(Args) as sweep:
Args.lr = [0.001, 0.01, 0.1]
Args.batch_size = [32, 64, 128]
for config in sweep:
train()
v3:
for lr in [0.001, 0.01, 0.1]:
for batch_size in [32, 64, 128]:
with proto.bind(lr=lr, batch_size=batch_size):
train()
Breaking Changes¶
1. No More parse_args()¶
v2 required calling Args.parse_args(). v3 handles this automatically with @proto.cli.
2. Type Hints Required¶
All parameters must have type annotations in v3.
3. Different Import Path¶
# v2
from params_proto import ParamsProto, Proto, Flag
# v3
from params_proto import proto
4. Prefix Syntax Changed¶
# v2
@Proto(prefix="Model")
class ModelConfig:
pass
# v3
@proto.prefix
class Model:
pass
Gradual Migration Strategy¶
You can migrate gradually:
Add v3 alongside v2: Keep v2 code, add new configs with v3
Migrate module by module: Convert one module at a time
Update tests: Ensure tests pass after each module migration
Remove v2 dependencies: Once fully migrated, remove v2 imports
Need Help?¶
Check the User Guide for detailed v3 documentation
See Examples for real-world v3 patterns
Open an issue on GitHub
v2 Documentation¶
The v2 documentation is archived at params-proto-v2.