Class MasterConfig
Synopsis
class MasterConfig(ABC)
Description
Defines functions that goes into every config class
Inheritance
Ancestors: ABC
Methods
__init__ | Empty init by default | |
__setattr__ | ||
__str__ | ||
allowed_cli_args | Returns the attribute names that can be be overwritten from command line input | |
build | Instantiates target object connected to config class | |
cli_help | ||
frozen | Freeze/unfreeze the config | |
get_parameters | Returns the config attributes | |
post_init | A function that is called after overwriting from command line input | |
pretty | Pretty string representation of the config |
Source
Lines 12-135 in anyfig/config_functions.py.
class MasterConfig(ABC):
"""
Defines functions that goes into every config class
"""
def __init__(self):
"""
Empty init by default
"""
pass
def allowed_cli_args(self):
''' Returns the attribute names that can be be overwritten from command line input '''
return self.get_parameters()
def post_init(self):
''' A function that is called after overwriting from command line input '''
pass
def cli_help(self):
return print_utils.cli_help(self)
def frozen(self, freeze=True):
"""
Freeze/unfreeze the config. Frozen configs are unmutable
Args:
freeze (bool, optional): Freeze config. Defaults to True.
Returns:
ConfigClass: Config instance
"""
self._frozen = freeze
for _, val in self.get_parameters(copy=False).items():
if figutils.is_config_class(val):
val.frozen(freeze)
return self
def get_parameters(self, copy=True):
''' Returns the config attributes. Doesn't include Anyfig built-ins '''
default_attrs = figutils.default_config_attributes()
params = {k: v for k, v in vars(self).items() if k not in default_attrs}
if copy:
return deepcopy(params)
return params
def __str__(self):
return self.pretty()
def pretty(self):
''' Pretty string representation of the config '''
lines = [f'{type(self).__name__}:']
for key, val in self.get_parameters(copy=False).items():
val_str = str(val)
if figutils.is_config_class(val): # Remove class name info
val_str = val_str.replace(f'{type(val).__name__}:', '')
lines += f'{key} ({type(val).__name__}): {val_str}'.split('\n')
return '\n '.join(lines)
def __setattr__(self, name, value):
config_class = type(self).__name__
# Handle interface values
old_value = getattr(self, name, None)
if isinstance(old_value, InterfaceField):
value = old_value.update_value(name, value, config_class)
# Raise error if frozen unless we're trying to unfreeze the config
if getattr(self, '_frozen', False) and name != '_frozen':
err_msg = f"Can't set attribute '{name}'. Config object is frozen. Unfreeze the config to make it mutable"
raise FrozenInstanceError(err_msg)
# Check for reserved names
name_taken_msg = (
f"The attribute '{name}' can't be assigned to config '{config_class}' since it already has a method by that name"
)
methods = inspect.getmembers(self, predicate=inspect.ismethod)
for method in methods:
assert name != method[0], name_taken_msg
object.__setattr__(self, name, value)
def build(self, external_args=None):
''' Instantiates target object connected to config class '''
if external_args is None:
external_args = dict()
config_name = type(self).__name__
assert self._build_target is not None, f"Config class '{config_name}' isn't connected to a target"
err_msg = f"Expected 'external_args' to be dict like object, was type '{type(external_args)}'"
assert isinstance(external_args, Mapping), err_msg
config_attrs = self.get_parameters()
common_keys = set(config_attrs).intersection(set(external_args))
err_msg = f"Arguments '{', '.join(common_keys)}' aren't allowed as they are already defined in '{config_name}'"
assert common_keys == set(), err_msg
build_args = {**external_args, **config_attrs}
err_msg_base = f'when building {self._build_target} for config {config_name}'
target = self._build_target
# If target is a class and not implemented in C-code
if inspect.isclass(target) and target.__init__ != object.__init__:
target = target.__init__
# Validate inspected arguments
try:
all_args, required_args = figutils.find_arguments(target)
err_msg = f"Unexpected arguments {set(build_args) - set(all_args)} {err_msg_base}"
assert set(build_args) <= set(all_args), err_msg
err_msg = f"Missing required arguments {set(required_args) - set(build_args)} {err_msg_base}"
assert set(required_args) <= set(build_args), err_msg
# C-code (CPython) can't be inspected so arguments can't be validated
except ValueError:
try:
return self._build_target(**build_args)
except Exception as e:
# Add to error message if instantiation didn't succeed
raise type(e)(f"{e} {err_msg_base}") from None
return self._build_target(**build_args)