Utilities for loading configuration from a YAML file.
Last active
December 18, 2015 14:09
-
-
Save theorm/5794795 to your computer and use it in GitHub Desktop.
Load configuration from a YAML file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| foo: | |
| bar: 1 | |
| baz: | |
| - baz0 | |
| - baz1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # -*- 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' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # -*- 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