Skip to content

Instantly share code, notes, and snippets.

@Perlence
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Perlence/11204241 to your computer and use it in GitHub Desktop.
Save Perlence/11204241 to your computer and use it in GitHub Desktop.
Fancy config
"""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