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

Popular posts from this blog

javascript - Thinglink image not visible until browser resize -

firebird - Error "invalid transaction handle (expecting explicit transaction start)" executing script from Delphi -

mongodb - How to keep track of users making Stripe Payments -