Created
September 12, 2020 09:49
-
-
Save robin-thoni/b6a71d9c3739f0458f08ed2f47a3ae8f to your computer and use it in GitHub Desktop.
PoC for Python configuration loading, from dict to typed object. For reference only
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python3 | |
import sys | |
from inspect import signature | |
from typeguard import check_type | |
import jinja2 | |
import typing | |
g_config_loader_types = {} | |
class ConfigLoaderFunc: | |
def __init__(self, func): | |
self.func = func | |
def __call__(self, *args, **kwargs): | |
(s,) = args | |
name = self.func.__name__ | |
return s._data[name] if s._data and name in s._data else None | |
def config_loader(*args, **kwargs): | |
def inner(func): | |
func.__config_loader_args__ = args | |
func.__config_loader_kwargs__ = kwargs | |
return ConfigLoaderFunc(func) | |
return inner | |
def get_dict_attr(obj, attr): | |
for obj in [obj] + obj.__class__.mro(): | |
if attr in obj.__dict__: | |
return obj.__dict__[attr] | |
raise AttributeError | |
class ConfigBase: | |
def __init__(self): | |
self._data = None | |
def load(self, data: dict): | |
data_ = {} | |
for d in filter(lambda a: not a.startswith('_'), dir(self)): | |
func_prop = get_dict_attr(self, d) | |
if isinstance(func_prop, property): | |
func_loader = func_prop.fget | |
if isinstance(func_loader, ConfigLoaderFunc): | |
args = func_loader.func.__config_loader_args__ | |
kwargs = func_loader.func.__config_loader_kwargs__ | |
type_ = signature(func_loader.func).return_annotation | |
try: | |
check_type("", data[d], type_, None) | |
data_[d] = data[d] | |
except TypeError as e: | |
pass | |
pass | |
self._data = data_ | |
class MyConfig(ConfigBase): | |
@property | |
@config_loader(default="my_value") | |
def test(self) -> typing.Optional[str]: | |
raise ValueError | |
def main(argv): | |
config_data = { | |
'test': 'my value' | |
} | |
config = MyConfig() | |
config.load(config_data) | |
print(config.test) | |
return 0 | |
if __name__ == '__main__': | |
sys.exit(main(sys.argv)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment