Package: simple-copoco
OverviewEffortlessly transition from YAML configuration to Python object management with the Simple Config Powered Code package.Installationpipinstallsimple-copocoWhy don't you just use OmegaConf + Hydra?OmegaConf + Hydra duet is fantastic and great (also literally). So there are some reasons to search for alternatives:Simplicity: The simple-copoco utility is designed to be lightweight and easy to use. If you have a project with straightforward configuration needs, simple-copoco provides an intuitive and easy to learn way to manage objects via configuration without the need for additional complexity.Integration of  configuration with object registration: simple-copoco offers features for object registration, allowing you to register and manage classes dynamically. If your project involves dynamic class instantiation based on configuration, simple-copoco provides a convenient way to achieve this.Grid Configurations: simple-copoco includes a GridManager for handling grids of YAML configurations, which can be useful for scenarios where you need to explore multiple configuration combinations in you experiments (whatever you do).Getting StartedHandling YAML ConfigurationsConsider the following YAML configuration:berries:color:blueamount:5coconuts:amount:1In Python:fromsimple_copocoimportConfigManager# config pathconfig_path='~/path/to/config.yaml'config_template_path='~/path/to/template.yaml'# optional, possibly wide, general config with many defaults# Option 1: template will be updated with provided configcfg_manager=ConfigManager(config_path,config_template_path)# Option 2: template doesn't existcfg_manager=ConfigManager(config_path)my_config=cfg_manager.cfg# access config attributeshow_many_berries_to_buy=my_config.berries.amountwhat_color_of_berries_to_buy=my_config.berries.color# dump configcfg_manager.save_to_disk('~/where/to/save.yaml')Managing Grids of YAML ConfigurationsConsider the following YAML grid:berries:color:[red,green,yellow]amount:[5,10,15]coconuts:amount:[1,3]In Python:fromsimple_copocoimportGridManager# Specify pathsgrid_path='~/path/to/grid.yaml'config_path='~/path/to/config.yaml'config_template_path='~/path/to/template.yaml'# optional# Grid manager will create all possible combinations of settings from grid.yamlgrid_manager=GridManager(grid_path,config_path,config_template_path)# Grid manager is a generatorfirst_config_manager=grid_manager.next()second_config_manager=grid_manager.next()# Total number of config managerstotal_of_config_managers=len(grid_manager)first_config=first_config_manager.cfgObject Registrationfromtorchimportnnfromsimple_copocoimportRegister,register_as,RegistrableMixin@register_as('utility_layer')classCustomLayer(nn.Module):def__init__(self):super(CustomLayer,self).__init__()...register=Register(nn.Module,include_parent=False)# register.buit_ins -> Dictionary of all classes inheriting directly or indirectly from nn.Module# that weren't registered with @register_as.# register.utility_layer -> Dictionary of classes inheriting from nn.Module registered as "utility_layer"# another use case, when submodules of a package are not being imported# with their parent. It happens, when the package has complex directory tree# and uses blank __init__.py files.from..importcustom_layers# custom_modules has some submodulesregister=Register(nn.Module,custom_layers)@register_as('classifier_head')classCustomHead(nn.Module):def__init__(self):super(CustomHead,self).__init__()...# Update the register with the current namespaceregister.update_register()# register.classifier_head -> dict of all the classes in the namespace inheriting from nn.Module# registered as "classifier_head"# Add a class (that has been registered after Register initialisation) to the register manuallyregister.extend(CustomHead)classAnyClass:...defsome_func():...# Register anythingregister.extend('other_classes','AnyClass',AnyClass)register.extend('functions','some_function',some_func)# name in the register doesn't need to the same# Register hint :)register=Register(RegistrableMixin)# registers anything within the namespace that inherits from RegistrableMixin# because @register_as() injects RegistrableMixin as a parent class (but this inheritance will be ignored in children# if passes_on_children == False).Putting It All TogetherConsider the following configuration:core:use:OtherModuleparams:a:1b:2head:use:CustomHeadparams:x:1y:1In Python:fromtorch.nnimportModulefromsimple_copocoimportRegister,register_asfromsimple_copocoimportConfigManager@register_as('core',passes_on_children=True)classCustomModule(Module):...classOtherModule(CustomModule):...@register_as('head')classCustomHead(Module):...register=Register(Module)cfg_man=ConfigManager('path/to/some_config.yaml','path/to/config_template.yaml')cfg=cfg_man.cfg# Create dynamic code based on configuration.# Attributes are accessible by dot notation, but you can use ** to unpack them, just like with dictionaries.# It makes experimentation with different architectures and many sets of parameters a breeze.classMemesClassifier(Module):def__init__(self,cfg,register):self.model_core=register.core[cfg.core.type](**cfg.core.params)self.classifier_head=register.head[cfg.head.type](**cfg.head.params)...