Profile photo

from miller import blake

Hello, I'm a Seattle-based site reliabililty engineering manager, I get paid to do what I love, I like Python, I'm in an abusive relationship with JavaScript, I'm a fan of good design, and I don't think things always have to be so stupid.
You can follow me @bltmiller, subscribe via RSS, and email me.

How to Provide Simple and Clean Global Configuration Variables in Python with YAML

I really despise software that keeps its configuration in the syntax of the language in which the software is written - I’m looking at you, Drupal. Users should not need to know PHP, Python, or Ruby in order to customize settings. That’s why storing settings as YAML is vastly superior since it’s easy for humans to parse at a casual glance. So, what’s the best and most Pythonic way to provide settings globally across a project?

In Python projects, I always ran into a messy problem when trying to share keys and values from YAML across different modules.

An example settings.yaml:

jenkins:
  host: http://jenkins.example.com
  user: donny
  token: I@m7h3W4lrU$
db:
  host: http://mysql.example.com
  user: lebowski
repo: /path/to/directory
require:
- ldap
- php
- zip

Together with that YAML dictionary, my first attempt ended up looking something like:

config = os.path.join(os.path.dirname(__file__), "settings.yaml")

with open(config, "r") as f:
    settings = yaml.load(f)

some_function(name="foo", expire=False, config=settings)

some_other_function(depth=2, path=settings["repo"], pkg=settings["require"]["ldap"])

So each time some function needed some values from settings, I ended up passing either multiple arguments or the entire dictionary. This added extra arguments to every function in my code and it was quite ugly. Let’s keep it simple. So, I came up with a much, much cleaner and more Pythonic solution that retains the simplicity of YAML while also honoring The Zen of Python.

Create a file named config.py and place in it:

#!/usr/bin/env python

import yaml

with open("settings.yaml", "r") as f:
    settings = yaml.load(f)

Now, everywhere else in your project you can simply import settings like:

from config import settings

That’s it - now your settings can be used anywhere without passing it around as an extra argument.


comments powered by Disqus

Copyright © 2020, Blake Miller. All rights reserved. | Sitemap · RSS