'Recursively creates dataclasses based in nested dictionary
I have a dataclass called Config that is created through the properties and values of a dictionary. Since this dictionary can have nested dictionaries, i would like to make nested dictionaries as Config objects. Here is an example:
## Dummy example of a config dict
data = {
  'a' : 1,
  'b' : [2,2,2],
  'c': {
    'c_1' : 3.1
  }
}
final_config = create_config(data)
# Expected result
Config(a=1, b=[2,2,2], c=Config(c_1=3.1) )
Here is what i've came up, using dataclasses.make_dataclass:
def _Config(params_dict):
  config = make_dataclass('Config', params_dict.keys())
  return config(**params_dict)
  
def get_inner_dict(d):
    for _, v in d.items():
        if isinstance(v, dict):
            return get_inner_dict(v) 
        else:
            return _Config(**d)
Unfortunately, this doesn't work because the recursion will try to create a dataclass object when it finds a single value. I feel like i'm in the right way, but couldn't figure out what needs to change.
Solution 1:[1]
It looks like you (technically) don't need to use dataclasses or make_dataclass in this scenario.
You can implement a custom class with a __dict__ update approach as mentioned by @Stef. Check out the following example:
from __future__ import annotations
## Dummy example of a config dict
data = {
    'a': 1,
    'b': [2, 2, 2],
    'c': {
        'c_1': 3.1
    },
    'd': [
        1,
        '2',
        {'k1': 'v1'}
    ]
}
_CONTAINER_TYPES = (dict, list)
class Config:
    def __init__(self, **kwargs):
        self.__dict__ = kwargs
    @classmethod
    def create(cls, data: dict | list) -> Config | list:
        if isinstance(data, list):
            return [cls.create(e) if isinstance(e, _CONTAINER_TYPES) else e
                    for e in data]
        new_data = {
            k: cls.create(v) if isinstance(v, _CONTAINER_TYPES) else v
            for k, v in data.items()
        }
        return cls(**new_data)
    def __repr__(self):
        return f"Config({', '.join([f'{name}={val!r}' for name, val in self.__dict__.items()])})"
final_config = Config.create(data)
print(final_config)
# Prints:
#   Config(a=1, b=[2, 2, 2], c=Config(c_1=3.1), d=[1, '2', Config(k1='v1')])
    					Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | 
