Skip to content

Instantly share code, notes, and snippets.

@mtomwing
Created September 3, 2013 16:10
Show Gist options
  • Save mtomwing/6425988 to your computer and use it in GitHub Desktop.
Save mtomwing/6425988 to your computer and use it in GitHub Desktop.
import ConfigParser
from ..core import ConfigManager
class ConfigParserManager(ConfigManager):
def __init__(self, manager, filename):
super(ConfigParserManager, self).__init__(manager, filename)
self.parser = ConfigParser.ConfigParser()
self.parser.read([self.filepath])
def load(self, config_class, section):
config_instance = config_class()
for name, option in config_instance.options.iteritems():
if not self.parser.has_option(section, name):
continue
raw = self.parser.get(section, name)
clean = option.decode(raw)
config_instance.set_value(name, option, clean)
return config_instance
def store(self, config_instance, section):
# TODO: Should probably make sure there's a value for every
# option before irreversibly removing a section.
self.parser.remove_section(section)
self.parser.add_section(section)
for name, option in config_instance.options.iteritems():
raw = config_instance.get_value(name, option)
clean = option.encode(raw)
self.parser.set(section, name, clean)
def save(self):
with open(self.filepath, 'wc') as config_fd:
self.parser.write(config_fd)
import abc
import functools
import os
from .exceptions import (
InvalidOptionValueError,
OptionValueNotSetError,
)
class Option(object):
__metaclass__ = abc.ABCMeta
class NotSpecified(object):
pass
def __init__(self, default=NotSpecified):
self.default = default
def is_required(self):
return self.default == self.NotSpecified
def post_get(self, value):
pass
def post_set(self, value):
pass
# Override these!
@abc.abstractmethod
def is_valid(self, value):
pass
@abc.abstractmethod
def encode(self, value):
'''
Encodes value into a string.
Should raise something if unable to encode.
'''
pass
@abc.abstractmethod
def decode(self, value):
'''
Decodes value into a proper Option value.
Should raise something if unable to decode.
'''
pass
class ConfigBase(abc.ABCMeta):
def __new__(meta, name, bases, dct):
dct, options = meta.find_options(dct)
dct['options'] = options
cls = super(ConfigBase, meta).__new__(meta, name, bases, dct)
for opt_name, option in options.iteritems():
opt_get = functools.partial(cls.get_value, name=opt_name, option=option)
opt_set = functools.partial(cls._set_value, name=opt_name, option=option)
setattr(cls, opt_name, property(opt_get, opt_set))
return cls
@staticmethod
def find_options(dct):
new_dct = {}
options = {}
for name, attr in dct.iteritems():
if name.startswith('_') or not isinstance(attr, Option):
new_dct[name] = attr
else:
options[name] = attr
return new_dct, options
class Config(object):
__metaclass__ = ConfigBase
def __init__(self):
self.values = {}
self.set_defaults()
def _set_value(self, value, name, option):
self.set_value(name, option, value)
def set_defaults(self):
for name, option in self.options.iteritems():
if not option.is_required():
self.set_value(name, option, option.default)
# You probably will not need to override these:
def get_value(self, name, option):
if name in self.values:
value = self.values[name]
option.post_get(value)
return value
else:
raise OptionValueNotSetError(name, option)
def set_value(self, name, option, value):
if option.is_valid(value):
self.values[name] = value
option.post_set(value)
else:
raise InvalidOptionValueError(name, option)
class ProfileManager(object):
def __init__(self, folder, name):
self.name = name
self.folder = folder
self.full_path = os.path.join(folder, name)
if not os.path.exists(self.full_path):
os.makedirs(self.full_path)
def get_filepath(self, name):
return os.path.join(self.full_path, name)
class ConfigManager(object):
__metaclass__ = abc.ABCMeta
def __init__(self, manager, filename):
self.manager = manager
self.filename = filename
self.filepath = manager.get_filepath(filename)
# Override these!
@abc.abstractmethod
def load(self, config_class):
'''
Populates the Config from somewhere.
It should iterate over all options in self.options and determine the
value to store by using option.decode(..).
'''
pass
@abc.abstractmethod
def store(self, config_instance):
'''
Persists the Config to somewhere.
It should iterate over all options in self.options and determine the
value to persis by using option.encode(..).
'''
pass
@abc.abstractmethod
def save(self):
# TODO: Persist config somewhere
pass
from freeseer.framework.config.core import Config, ProfileManager
from freeseer.framework.config.persist import (
ConfigParserManager,
JSONConfigManager,
)
import freeseer.framework.config.options as options
class FreeseerConfig(Config):
videodir = options.FolderOption('/home/mtomwing/Videos', auto_create=True)
auto_hide = options.BooleanOption(True)
resolution = options.ChoiceOption([
'default',
'240p',
'360p',
'480p',
'720p',
'1080p',
], 'default')
if __name__ == '__main__':
profile = ProfileManager('/tmp/freeseer/profiles', 'mtomwing')
managers = [
[ConfigParserManager, '.conf'],
[JSONConfigManager, '.json'],
]
for Manager, ext in managers:
storage = Manager(profile, 'freeseer' + ext)
config = storage.load(FreeseerConfig, 'Global')
storage.store(config, 'Global')
config.auto_hide = False
storage.store(config, 'Something Else')
storage.save()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment