Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Accessing YAML values using "dot notation"

I'm using a YAML configuration file. So this is the code to load my config in Python:

import os
import yaml
with open('./config.yml') as file:
    config = yaml.safe_load(file)

This code actually creates a dictionary. Now the problem is that in order to access the values I need to use tons of brackets.

YAML:

mysql:
    user:
        pass: secret

Python:

import os
import yaml
with open('./config.yml') as file:
    config = yaml.safe_load(file)
print(config['mysql']['user']['pass']) # <--

I'd prefer something like that (dot notation):

config('mysql.user.pass')

So, my idea is to utilize the PyStache render() interface.

import os
import yaml
with open('./config.yml') as 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 that be a "good" solution? If not, what would be a better alternative?

Additional question [Solved]

I've decided to use Ilja Everilä's solution. But now I've got an additional question: How would you create a wrapper Config class around DotConf?

The following code doesn't work but I hope you get the idea what I'm trying to do:

class Config( DotDict ):
    def __init__( self ):
        with open('./config.yml') as file:
            DotDict.__init__(yaml.safe_load(file))

config = Config()
print(config.django.admin.user)

Error:

AttributeError: 'super' object has no attribute '__getattr__'

Solution

You just need to pass self to the constructor of the super class.

DotDict.__init__(self, yaml.safe_load(file))

Even better soltution (Ilja Everilä)

super().__init__(yaml.safe_load(file))
like image 308
Lugaxx Avatar asked Sep 13 '16 06:09

Lugaxx


2 Answers

It's quite old question, but I came here hunting for the answer, but looking for more simpler solution. Finally, came up with my own solution using easydict library; installed using pip install easydict

  def yaml_load(fileName):
    import yaml
    from easydict import EasyDict as edict
    fc = None
    with open(fileName, 'r') as f:
      fc = edict(yaml.load(f))
      ## or use safe_load
      ## fc = edict(yaml.safe_load(f))

    return fc

Now, simply call yaml_load with the valid yaml filename:

config = yaml_load('./config.yml')

## assuming: config["mysql"]["user"]["pass"] is a valid key in config.yml
print("{}".format(config.mysql.user.pass))
like image 180
mangalbhaskar Avatar answered Sep 25 '22 02:09

mangalbhaskar


I ended up using python-box. This package provides multiple ways to read config files (yaml, csv, json, ...). And not only that, it allows you to pass dict or strings directly:

from box import Box
import yaml # Only required for different loaders

# Pass dict directly
movie_box = Box({ "Robin Hood: Men in Tights": { "imdb stars": 6.7, "length": 104 } })

# Load from yaml file
# Here it is also possible to use PyYAML arguments, 
# for example to specify different loaders e.g. SafeLoader or FullLoader
conf = Box.from_yaml(filename="./config.yaml", Loader=yaml.FullLoader) 

conf.mysql.user.pass

A lot more examples, are available in the Wiki.

like image 45
evolved Avatar answered Sep 25 '22 02:09

evolved