#!/usr/bin/env python3 """ For parsing and generating config files. """ from configparser import ConfigParser class Config(): def __init__(self, filename): """ The bot's configuration. The given filename will be associated with the configuration, and is the file which will be written if write() is called. If load is not given or True, the configuration object will load the attributes from the file at filename. A few default values will be set here if they are not defined in the config file, or a config file is not loaded. They are documented below. """ self.filename = filename """The config object's associated file, as noted above.""" self.parser = ConfigParser(allow_no_value=True, interpolation=None) self.parser.read(self.filename) @property def homedir(self): """An alias to config.core.homedir""" # Technically it's the other way around, so we can bootstrap filename # attributes in the core section, but whatever. configured = None if self.parser.has_option('core', 'homedir'): configured = self.parser.get('core', 'homedir') if configured: return configured else: return os.path.dirname(self.filename) def save(self): """Save all changes to the config file.""" with open(self.filename, 'w') as cfgfile: self.parser.write(cfgfile) def add_section(self, name): """ Add a section to the config file. Returns ``False`` if already exists. """ try: return self.parser.add_section(name) except ConfigParser.DuplicateSectionError: return False def __getattr__(self, name): """Allows sections to be called like class attributes.""" if name in self.parser.sections(): items = self.parser.items(name) section = ConfigSection(name, items, self) # Return a section setattr(self, name, section) return section else: raise AttributeError("%r object has no attribute %r" % (type(self).__name__, name)) class ConfigSection(object): """ Represents a section of the config file. Contains all keys in thesection as attributes. """ def __init__(self, name, items, parent): object.__setattr__(self, '_name', name) object.__setattr__(self, '_parent', parent) for item in items: value = item[1].strip() if not value.lower() == 'none': if value.lower() == 'false': value = False object.__setattr__(self, item[0], value) def __getattr__(self, name): return None def __setattr__(self, name, value): object.__setattr__(self, name, value) if type(value) is list: value = ','.join(value) self._parent.parser.set(self._name, name, value) def get_list(self, name): value = getattr(self, name) if not value: return [] if isinstance(value, str): value = value.split(',') # Keep the split value, so we don't have to keep doing this setattr(self, name, value) return value def readConfig(filename): """ Parses the provided filename and returns the config object. """ config = ConfigParser(allow_no_value=True, interpolation=None) config.read(filename) return config def generateConfig(filename): """ Generates a blank config file with minimal defaults. """ pass