Source code for metatools.config
"""Tools for easy persistance of configuration and user preferences for tools.
Configurations are split into sections and keys; sections are conceptually for
each tool (or other grouping of settings), and keys are for individual settings
within that tool/section. In the current implementation, individual sections
are saved within YAML files as a mapping.
Basic usage::
# Creating the config object; give it a unique name. Slashes will be
# used directly to specify sub-directories.
config = metatools.config.Config('your_company/' + __name__)
# Use a value within the config; treat it like a dict.
dialog = setup_gui(width=config.get('width', 800))
# Save the values later.
config['width'] = dialog.width()
config.save() # Only if there were changes to the values.
Quick use::
width = metatools.config.get('your_company/' + __name__, 'width')
metatools.config.set('your_company/' + __name__, 'width', width)
"""
import os
import yaml
[docs]class Config(dict):
"""Mapping which persists to disk via YAML serialization.
Use like a dictionary.
"""
def __init__(self, name):
self.name = name
if os.path.isabs(name):
self.path = name
else:
self.path = os.path.expanduser('~/.%s.yml' % name)
self.revert()
[docs] def revert(self):
"""Revert to saved state."""
if not os.path.exists(self.path):
self.clear()
else:
saved = yaml.load(open(self.path).read())
self.clear()
self.update(saved)
self.dirty = False
[docs] def save(self, force=False):
"""Persist the current contents.
:param bool force: Always write, even if there were no changes.
"""
if not force and not self.dirty:
return
if self:
encoded = yaml.dump(dict(self),
indent=4,
default_flow_style=False,
)
directory = os.path.dirname(self.path)
if not os.path.exists(directory):
os.makedirs(directory)
with open(self.path, 'wb') as fh:
fh.write(encoded)
elif os.path.exists(self.path):
os.unlink(self.path)
[docs] def delete(self):
"""Clear and delete; same as clear() and save()."""
self.clear()
if os.path.exists(self.path):
os.unlink(self.path)
def __setitem__(self, key, value):
super(Config, self).__setitem__(key, value)
self.dirty = True
[docs] def update(self, *args, **kwargs):
super(Config, self).update(*args, **kwargs)
self.dirty = True
def __delitem__(self, key):
super(Config, self).__delitem__(key)
self.dirty = True
def __enter__(self):
return self
def __exit__(self, type_, value, tb):
if not type_:
self.save()
[docs]def get(section, name, *args):
config = Config(section)
try:
return config[name]
except KeyError:
if args:
return args[0]
else:
raise
[docs]def set(section, name, value):
config = Config(section)
config[name] = value
config.save()
[docs]def main():
import ast
from optparse import OptionParser
optparser = OptionParser('%prog [options] section name [value]')
opts, args = optparser.parse_args()
# Basic get.
if len(args) == 2:
print get(*args)
# Basic set.
elif len(args) == 3:
section, name, raw_value = args
try:
value = ast.literal_eval(raw_value)
except SyntaxError:
value = raw_value
set(section, name, value)
else:
optparser.print_usage()
exit(1)
if __name__ == '__main__':
main()