Last active
August 29, 2015 14:00
-
-
Save Perlence/11204241 to your computer and use it in GitHub Desktop.
Fancy config
This file contains 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
"""Fancy config. | |
This module reads data from ``default.cfg`` and ``config.cfg`` using | |
:class:`RawConfigParser` and stores sections in the module's namespace. | |
Let's take the following ``config.cfg`` for example:: | |
[section1] | |
key1 = 1 | |
key2 = 2 | |
[server] | |
host = 127.0.0.1 | |
port = 8000 | |
Let's read it:: | |
>>> import config | |
Getting values from config have never been easier:: | |
>>> config.section1.key1 | |
'1' | |
>>> config.server.host | |
'127.0.0.1' | |
>>> config.section1['key2'] | |
'2' | |
Setting values will automatically write changes to ``config.cfg``:: | |
>>> config.section1.key2 = 'change' | |
>>> config.server['port'] = '8001' | |
>>> print open('config.cfg').read() | |
[section1] | |
key1 = 1 | |
key2 = change | |
[server] | |
host = 127.0.0.1 | |
port = 8001 | |
At this point we can manually change some values in the ``config.cfg`` using | |
text editor. To refresh our ``config`` object:: | |
>>> reload(config) | |
Moreover, :class:`Section` is partly a mapping (via implementing | |
:meth:`Section.keys`) so it can be passed to a function after ``**``:: | |
>>> def connect(host, port): | |
... print '%s:%s' % (host, port) | |
... | |
>>> connect(**config.server) | |
127.0.0.1:8001 | |
In contrast to mappings, :class:`Section` iterates over values, not keys:: | |
>>> connect(*config.server) | |
127.0.0.1:8001 | |
Some methods from :class:`ConfigParser` that take section name as first | |
argument were added to :class:`Section` with underscore prefix. One useful | |
example is :meth:`Section._items`:: | |
>>> config.section1._items() | |
[('key1', '1'), ('key2', 'change')] | |
Full list of methods: | |
- :meth:`Section._set` | |
- :meth:`Section._write` | |
- :meth:`Section._options` | |
- :meth:`Section._values` | |
- :meth:`Section._dict` | |
- :meth:`Section._items` | |
- :meth:`Section._get` | |
""" | |
class Section(object): | |
def __init__(self, section_name, path): | |
object.__setattr__(self, '_section', section_name) | |
object.__setattr__(self, '_path', path) | |
for option, value in _config.items(section_name): | |
object.__setattr__(self, option, value) | |
def __len__(self): | |
return len(self._options()) | |
def __iter__(self): | |
return iter(self._values()) | |
def __contains__(self, key): | |
return key in self._options() | |
def __getitem__(self, key): | |
return self._get(key) | |
def __setitem__(self, key, value): | |
self._set(key, value) | |
def __setattr__(self, key, value): | |
self._set(key, value) | |
object.__setattr__(self, key, value) | |
def _set(self, key, value=None): | |
_config.set(self._section, key, value=value) | |
self._write() | |
def _write(self): | |
with open(self._path, 'w') as fp: | |
_config.write(fp) | |
def _options(self): | |
return _config.options(self._section) | |
def _values(self): | |
return zip(*self._items())[1] | |
keys = _options | |
def _dict(self): | |
return dict(self._items()) | |
def _items(self): | |
return _config.items(self._section) | |
def _get(self, key): | |
return _config.get(self._section, key) | |
def _setup(): | |
from os.path import join, dirname | |
from ConfigParser import RawConfigParser | |
DEFAULTPATH = join(dirname(__file__), 'default.cfg') | |
CONFIGPATH = join(dirname(__file__), 'config.cfg') | |
global _config | |
_config = RawConfigParser() | |
_config.read((DEFAULTPATH, CONFIGPATH)) | |
sections = {section_name: Section(section_name, CONFIGPATH) | |
for section_name in _config.sections()} | |
globals().update(sections) | |
_config = None | |
_setup() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment