Skip to content

Instantly share code, notes, and snippets.

@robin-thoni
Created September 12, 2020 09:49
Show Gist options
  • Save robin-thoni/b6a71d9c3739f0458f08ed2f47a3ae8f to your computer and use it in GitHub Desktop.
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
#! /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