I have this code:
from abc import ABC
class ConfigProto(ABC):
def __init__(self, config_dict):
self._config_dict = config_dict
def parse(self, cfg_store: dict) -> None:
# do something with the config dict and the cfg_store and setup attributes
...
class ConfigurableComponent(ABC):
class Config(ConfigProto):
...
def __init__(self, parsed_config: Config):
for key, value in parsed_config.__dict__.items():
setattr(self, key, value)
def __init_subclass__(cls, **kwargs):
"""
Adds relevant attributes from the member Config class to itself.
This is done for all subclasses of ConfigurableComponent, so that the attributes are not required to be
specified in two places (in the Config class and the component class).
If there are significant differences between the Config attributes and the component attributes, they can be
also specified in the component class, and then they will not be overwritten by the Config attributes.
"""
super().__init_subclass__(**kwargs)
config = getattr(cls, 'Config', None)
if config:
# copy non-callable, non-protected, non-private attributes from config to component class
conf_class_attributes = [attr_ for attr_ in dir(config)
if not attr_.startswith('_')
and not callable(getattr(config, attr_))]
for attr_name in conf_class_attributes:
# ignore private attributes, methods, and members already defined in the class
if not attr_name.startswith('_') \
and not callable(getattr(config, attr_name)) \
and not hasattr(cls, attr_name):
setattr(cls, attr_name, getattr(config, attr_name))
class ExampleComponent(ConfigurableComponent):
class Config(ConfigProto):
param1: int
param2: str
def parse(self, cfg_store: dict) -> None:
...
example_component = ExampleComponent(ExampleComponent.Config(config_dict={'param1': 1, 'param2': 'test'}))
assert hasattr(example_component, 'param1')
It does not work. When subclassing the parent class ConfigurableComponent(ABC)
, the __init_subclass__
is called, but the config
class variable does not contain the attributes defined in ExampleComponent.Config
despite it showing it is the correct type.
I expect the __init_subclass__
method to be called after the subclass is defined (including its members). Still, even though the members are here (there is a member named "Config" in the ExampleComponent class), they are not initialised - the Config
class seems to be empty.
So far I think the reason is that the member class gets fully initialised only after the owner class gets instantiated into an object, but I am not sure and can't seem to find the details in the documentation.
Does anybody have an idea how to make this code work so that I can:
define attributes in the member class Config
and get them added to the owning class automatically when subclassing the ConfigurableComponent
class?