Package: eparams
eparamsSimpleandconfigurableparameters/configuration class. No manual schema needed!Use python3.6+ type hinting to declare the param type, or let eparams to infer it from the assignment, and keep you from assigning the wrong type down the line!At its core it is designed as a drop-in replacement fordataclass, but with added features to make life easier.Installation$pip install eparamsFeaturesAutomatically type-check parameters usingtypeguard.Auto typing - doesn'tforceyou to add type hints everywhere.Define a custom / use our default preprocess function to cast your input to the correct type.Use mutable types (listdictetc) at class definition with no worries and no awkward mandatory factory objects.Protect from typos that would normally lead to assigning undeclared parameters.Define custom constraints.freeze / unfreeze class.History tracking.Track assignment to the class to see which attributes were assigned and from what values.Added helper methods:_to_json()_to_yaml()_to_dict()_from_json()_from_yaml()_from_dict()copy()_freeze()_unfreeze()_history()__contains__()__eq__()__getitem__()__setitem__()All above features are fully configurable per parameter and globally.Built to be nested, withconf.sub_conf.some_valstructure, all methods work recursively. Plays well withdataclass.Helper functions:Recursive comparison: compare configs from different versions of your code / accross experimentsRegister partial-config functions in a dictionary for easy calls using cli and external configs.Example usage:Seesample_projectfor an example usage in a "complete" project which includes:cli integration withargparse.delta-config registration.constraints.frozen class.yaml/dict export.Basic usage:fromeparamsimportparams# Basic usage@paramsclassOptimizerParams:learning_rate=1e-2weight_decay=0.001batch_size=1024@paramsclassParams:name='default name'tags=['no','problem','with','list','here']optim=OptimizerParams()verbose=Falseconfig=Params(name='new name')config.optim.batch_size=2048# okconfig.optim.learning_rate='0.001'# ok, cast to floatconfig.optim.batch_size='32'# ok, cast to intconfig.verbose='True'# ok, cast to boolconfig['optim.weight_decay']=0# we can set nested attributes like this as-wellprint(config)# prints:# name='new name'# tags=['no', 'problem', 'with', 'list', 'here']# optim.learning_rate=0.001# optim.weight_decay=0# optim.batch_size=32# verbose=Trueconfig._to_yaml('/path/to/config.yaml')# save as yaml# The following lines will raise an exceptionconfig.optim.batch_size='string'# raises ValueError: invalid literal for int() with base 10: 'string'config.optim.batch_size=1.3# raises TypeError: type of batch_size must be int; got float insteadconfig.verrrbose=False# raises ValueError: Cannot assign <verrrbose> to class <<class '__main__.Params'>>, missing from class definition (allow_dynamic_attribute=False)Debug and compare configs from old/different runs:fromeparamsimportparams,params_compare# type_verify=False does not check for typing errors.# default_preprocessor=None removes the preprocessing step (a custom function is also valid here)# allow_dynamic_attribute=True allows the class to dynamically set new attributes.@params(type_verify=False,default_preprocessor=None,allow_dynamic_attribute=True)classParams:name='default name'my_int=0old_config=Params()._from_yaml('/path/to/old/config.yaml',strict=False)# load some old configprint(old_config._history())# show parameters that were loaded and their pre-loaded valueparams_not_in_old_yaml=[kfork,histinold_config._history(full=True).items()ifnothist]modified,added,removed=params_compare(old_config,Params())# compare two versions of configsPreprocessing example:importenumfrompathlibimportPathfromeparamsimportparams,VarclassMyEnum(enum.Enum):a='a'b='b'@paramsclassExample:num:int=3type=MyEnum.bpath:Path='/user/home'# cast to Pathsome_list=[1,2,3]# we copy the list before assignmentsome_string=Var('yo_yo',preprocess_fn=str.lower)# lower stringex=Example()ex.num='4'# cast to intex.type='a'# cast to MyEnumex.some_string='HELLO'# .lower()assertex.some_listisnotExample.some_listprint(ex)# prints:# num=4# type=<MyEnum.a: 'a'># path=PosixPath('/user/home')# some_list=[1, 2, 3]# some_string='hello'Other popular approaches/libraries to define parameters:Simply use adictSimply use adataclasspydanticattrs