I am trying to dynamically create a Python class from a configuration file (I use a dictionary in the example for simplicity). The attributes that I create I would like to be set as properties since I have validation functions that I would like to run when the attributes are set.
I have a code that is sort-of working, but it's having some unexpected results.
def func(x):
    """ Example validation function. """
    if x < 0:
        raise ValueError
    return
config = {
    "x": {
        "type": int,
        "default": 0,
        "validate": func
    },
    "y": {
        "type": int,
        "default": 10,
        "validate": func
    },
    "z": {
        "type": str,
        "default": "bar",
        "validate": None
    }
}
def get_property(prop, validate):
    key = f"_{prop}"
    def get_(self):
        return exec(f"self.{key}")
    def set_(self, value):
        if validate is not None:
            validate(value)
        exec(f"self.{key} = value")
    def del_(self):
        exec(f"del self.{key}")
    return property(get_, set_, del_)
def get_Foo(**kwargs):
    class Foo:
        def __init__(self, **_kwargs):
            for k_, v_ in _kwargs.items():
                setattr(self, "_" + k_, None)
                if v_["type"] == str:
                    exec(f"self.{k_} = '{v_['default']}'")
                else:
                    exec(f"self.{k_} = {v_['default']}")
    # Add properties to Foo class
    for k, v in kwargs.items():
        prop_ = get_property(k, v["validate"])
        setattr(Foo, k, prop_)
    # Create Foo class and set defaults
    return Foo(**kwargs)
foo = get_Foo(**config)
Now when testing it appears that 'setter' is working, but 'getter' is not and 'deleter' is partially working.
print(foo.x)  # prints None
print(foo._x) # prints 0
foo.x = 10
print(foo.x)  # prints None (getter not working)
print(foo._x) # prints 10  (setter works)
foo.x = -1    # raises error (validator in setter works)
del foo.x
print(foo.x)  # AttributeError: 'Foo' object has no attribute '_x' (del sort-of works?)
Could anyone explain the results?
 
    