Skip to content

Instantly share code, notes, and snippets.

@theorm
Last active December 18, 2015 14:09
Show Gist options
  • Select an option

  • Save theorm/5794795 to your computer and use it in GitHub Desktop.

Select an option

Save theorm/5794795 to your computer and use it in GitHub Desktop.
Load configuration from a YAML file.

Utilities for loading configuration from a YAML file.

foo:
bar: 1
baz:
- baz0
- baz1
# -*- coding: utf-8 -*-
import unittest
from yaml_config import Configuration
class YamlConfigTestCase(unittest.TestCase):
def test_load_config_errors(self):
with self.assertRaises(IOError):
Configuration()
with self.assertRaises(IOError):
Configuration(location='/foo')
def test_can_load_config(self):
configuration = Configuration(location='test.yaml')
self.assertTrue('foo' in configuration)
self.assertFalse('foo1' in configuration)
self.assertEquals(configuration.foo.baz[0], 'baz0')
def test_config_is_immutable(self):
configuration = Configuration(location='test.yaml')
with self.assertRaises(TypeError):
configuration.foo = 1
with self.assertRaises(TypeError):
configuration['foo'] = 1
with self.assertRaises(TypeError):
del configuration['foo']
with self.assertRaises(TypeError):
configuration.foo.baz[0] = 'baz3'
# -*- coding: utf-8 -*-
'''
Reads YAML config file.
Requires pyyaml:
```
pip install pyyaml>=3.10
```
'''
import os.path
# import bunch
import yaml
try:
from yaml import CLoader as Loader
except ImportError:
from yaml import Loader
from itertools import repeat
import collections
def is_immutable(self):
raise TypeError('%r objects are immutable' % self.__class__.__name__)
class ImmutableDotedDict(dict):
"""Immutable dict.
From
https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/datastructures.py
"""
_hash_cache = None
@classmethod
def fromkeys(cls, keys, value=None):
instance = super(cls, cls).__new__(cls)
instance.__init__(zip(keys, repeat(value)))
return instance
def __reduce_ex__(self, protocol):
return type(self), (dict(self),)
def _iter_hashitems(self):
return self.iteritems()
def __hash__(self):
if self._hash_cache is not None:
return self._hash_cache
rv = self._hash_cache = hash(frozenset(self._iter_hashitems()))
return rv
def setdefault(self, key, default=None):
is_immutable(self)
def update(self, *args, **kwargs):
is_immutable(self)
def pop(self, key, default=None):
is_immutable(self)
def popitem(self):
is_immutable(self)
def __setitem__(self, key, value):
is_immutable(self)
def __delitem__(self, key):
is_immutable(self)
def clear(self):
is_immutable(self)
def __setattr__(self, key, value):
if not key.startswith('_{}__'.format(self.__class__.__name__)):
is_immutable(self)
else:
super(ImmutableDotedDict, self).__setattr__(key, value)
def __delattr__(self, key):
is_immutable(self)
def __getattr__(self, key):
try:
# Throws exception if not in prototype chain
return object.__getattribute__(self, key)
except AttributeError:
try:
return self[key]
except KeyError:
raise AttributeError(key)
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
if isinstance(value, collections.Mapping):
value = ImmutableDotedDict(**value)
elif isinstance(value, list):
value = tuple(value)
dict.__setitem__(self, key, value)
class Configuration(ImmutableDotedDict):
'''Configuration loader.
- Assumes config file is located in '~/localmeasure.yaml'.
- Location can be overridden in `location` constructor parameter.
- Instance is immutable.
'''
def __init__(self, filename='localmeasure.yaml', location=None):
self.__location = location or os.path.join(
os.path.expanduser('~'),
filename
)
with open(self.__location, 'r') as f:
data = yaml.load(f.read(), Loader=Loader)
super(Configuration, self).__init__(**data)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment