Python: Accessing YAML values using "dot notation" -
i'm using yaml configuration file. code load config in python:
import os import yaml open('./config.yml') file: config = yaml.safe_load(file)
this code creates dictionary. problem in order access values need use tons of brackets.
yaml:
mysql: user: pass: secret
python:
import os import yaml open('./config.yml') file: config = yaml.safe_load(file) print(config['mysql']['user']['pass']) # <--
i'd prefer (dot notation):
config('mysql.user.pass')
so, idea utilize pystache render() interface.
import os import yaml open('./config.yml') file: config = yaml.safe_load(file) import pystache def get_config_value( yml_path, config ): return pystache.render('{{' + yml_path + '}}', config) get_config_value('mysql.user.pass', config)
would "good" solution? if not, better alternative?
additional question [solved]
i've decided use ilja everilä's solution. i've got additional question: how create wrapper config class around dotconf?
the following code doesn't work hope idea i'm trying do:
class config( dotdict ): def __init__( self ): open('./config.yml') file: dotdict.__init__(yaml.safe_load(file)) config = config() print(config.django.admin.user)
error:
attributeerror: 'super' object has no attribute '__getattr__'
solution
you need pass self
constructor of super class.
dotdict.__init__(self, yaml.safe_load(file))
even better soltution (ilja everilä)
super().__init__(yaml.safe_load(file))
the simple
you use reduce
extract value config:
in [41]: config = {'asdf': {'asdf': {'qwer': 1}}} in [42]: functools import reduce ...: ...: def get_config_value(key, cfg): ...: return reduce(lambda c, k: c[k], key.split('.'), cfg) ...: in [43]: get_config_value('asdf.asdf.qwer', config) out[43]: 1
this solution easy maintain , has few new edge cases, if yaml uses limited subset of language.
the correct
use proper yaml parser , tools, such in this answer.
the convoluted
on lighter note (not taken seriously), create wrapper allows using attribute access:
in [47]: class dotconfig: ...: ...: def __init__(self, cfg): ...: self._cfg = cfg ...: def __getattr__(self, k): ...: v = self._cfg[k] ...: if isinstance(v, dict): ...: return dotconfig(v) ...: return v ...: in [48]: dotconfig(config).asdf.asdf.qwer out[48]: 1
do note fails keywords, such "as", "pass", "if" , like.
finally, crazy (read: not idea) , customize dict
handle dotted string , tuple keys special case, attribute access items thrown in mix (with limitations):
in [58]: class dotdict(dict): ...: ...: # update, __setitem__ etc. omitted, required if ...: # 1 tries set items using dot notation. ...: # read-only view. ...: ...: def __getattr__(self, k): ...: try: ...: v = self[k] ...: except keyerror: ...: return super().__getattr__(k) ...: if isinstance(v, dict): ...: return dotdict(v) ...: return v ...: ...: def __getitem__(self, k): ...: if isinstance(k, str) , '.' in k: ...: k = k.split('.') ...: if isinstance(k, (list, tuple)): ...: return reduce(lambda d, kk: d[kk], k, self) ...: return super().__getitem__(k) ...: ...: def get(self, k, default=none): ...: if isinstance(k, str) , '.' in k: ...: try: ...: return self[k] ...: except keyerror: ...: return default ...: return super().get(k, default=default) ...: in [59]: dotconf = dotdict(config) in [60]: dotconf['asdf.asdf.qwer'] out[60]: 1 in [61]: dotconf['asdf', 'asdf', 'qwer'] out[61]: 1 in [62]: dotconf.asdf.asdf.qwer out[62]: 1 in [63]: dotconf.get('asdf.asdf.qwer') out[63]: 1 in [64]: dotconf.get('asdf.asdf.asdf') in [65]: dotconf.get('asdf.asdf.asdf', 'nope') out[65]: 'nope'
Comments
Post a Comment