VirtualMailManager/Config.py
branchv0.6.x
changeset 209 c705a9e38962
parent 207 95be8f62bc0c
child 211 0b129678cfe1
equal deleted inserted replaced
208:efa1327b721f 209:c705a9e38962
     4 
     4 
     5 """
     5 """
     6     VirtualMailManager.Config
     6     VirtualMailManager.Config
     7 
     7 
     8     VMM's configuration module for simplified configuration access.
     8     VMM's configuration module for simplified configuration access.
     9 
       
    10 This module defines a few classes:
       
    11 
       
    12 ``LazyConfig``
       
    13     This class provides the following additonal methods
       
    14 
       
    15     * `LazyConfig.pget()`
       
    16         polymorphic getter which returns the value with the appropriate
       
    17         type.
       
    18     * `LazyConfig.dget()`
       
    19         like *pget()*, but checks additonal for default values in
       
    20         `LazyConfig._cfg`.
       
    21     * `LazyConfig.set()`
       
    22         like `RawConfigParser.set()`, but converts the new value to the
       
    23         appropriate type/class and optional validates the new value.
       
    24     * `LazyConfig.bool_new()`
       
    25         converts data from raw_input into boolean values.
       
    26     * `LazyConfig.get_boolean()`
       
    27         like `RawConfigParser.getboolean()`, but doesn't fail on real
       
    28         `bool` values.
       
    29 
       
    30 ``Config``
       
    31     The Config class used by vmm.
       
    32 
       
    33 ``LazyConfigOption``
       
    34     The class for the configuration objects in the ``Config`` class'
       
    35     ``_cfg`` dictionary.
       
    36 """
     9 """
    37 
    10 
    38 
    11 
    39 from ConfigParser import \
    12 from ConfigParser import \
    40      Error, MissingSectionHeaderError, NoOptionError, NoSectionError, \
    13      Error, MissingSectionHeaderError, NoOptionError, NoSectionError, \
    67 class LazyConfig(RawConfigParser):
    40 class LazyConfig(RawConfigParser):
    68     """The **lazy** derivate of the `RawConfigParser`.
    41     """The **lazy** derivate of the `RawConfigParser`.
    69 
    42 
    70     There are two additional getters:
    43     There are two additional getters:
    71 
    44 
    72     `LazyConfig.pget()`
    45     `pget()`
    73         The polymorphic getter, which returns a option's value with the
    46       The polymorphic getter, which returns a option's value with the
    74         appropriate type.
    47       appropriate type.
    75     `LazyConfig.dget()`
    48     `dget()`
    76         Like `LazyConfig.pget()`, but returns the option's default, from
    49       Like `LazyConfig.pget()`, but returns the option's default, from
    77         `LazyConfig._cfg['sectionname']['optionname'].default`, if the
    50       `LazyConfig._cfg['sectionname']['optionname'].default`, if the
    78         option is not configured in a ini-like configuration file.
    51       option is not configured in a ini-like configuration file.
    79 
    52 
    80 
    53     `set()` differs from `RawConfigParser`'s `set()` method. `set()` takes
    81     `LazyConfig.set()` differs from ``RawConfigParser``'s ``set()`` method.
    54     the `section` and `option` arguments combined to a single string in the
    82     ``LazyConfig.set()`` takes the ``section`` and ``option`` arguments
    55     form "section.option".
    83     combined to a single string in the form
       
    84     "``section``\ **.**\ ``option``".
       
    85     """
    56     """
    86 
    57 
    87     def __init__(self):
    58     def __init__(self):
    88         RawConfigParser.__init__(self)
    59         RawConfigParser.__init__(self)
    89         self._modified = False
    60         self._modified = False
    95         """sample _cfg dictionary. Create your own in your derived class."""
    66         """sample _cfg dictionary. Create your own in your derived class."""
    96 
    67 
    97     def bool_new(self, value):
    68     def bool_new(self, value):
    98         """Converts the string `value` into a `bool` and returns it.
    69         """Converts the string `value` into a `bool` and returns it.
    99 
    70 
   100         | '1', 'on', 'yes' and 'true' will become ``True``
    71         | '1', 'on', 'yes' and 'true' will become `True`
   101         | '0', 'off', 'no' and 'false' will become ``False``
    72         | '0', 'off', 'no' and 'false' will become `False`
   102 
    73 
   103         Throws a `ConfigValueError` for all other values, except ``bool``\ s.
    74         Throws a `ConfigValueError` for all other values, except bools.
   104         """
    75         """
   105         if isinstance(value, bool):
    76         if isinstance(value, bool):
   106             return value
    77             return value
   107         if value.lower() in self._boolean_states:
    78         if value.lower() in self._boolean_states:
   108             return self._boolean_states[value.lower()]
    79             return self._boolean_states[value.lower()]
   198         """Returns the value of the `option`."""
   169         """Returns the value of the `option`."""
   199         section, option = self._get_section_option(option)
   170         section, option = self._get_section_option(option)
   200         return self._cfg[section][option].getter(section, option)
   171         return self._cfg[section][option].getter(section, option)
   201 
   172 
   202     def set(self, option, value):
   173     def set(self, option, value):
   203         """Set the value of an option.
   174         """Set the `value` of the `option`.
   204 
   175 
   205         Throws a ``ValueError`` if `value` couldn't be converted to
   176         Throws a `ValueError` if `value` couldn't be converted using
   206         ``LazyConfigOption.cls``"""
   177         `LazyConfigOption.cls`"""
   207         section, option = self._get_section_option(option)
   178         section, option = self._get_section_option(option)
   208         val = self._cfg[section][option].cls(value)
   179         val = self._cfg[section][option].cls(value)
   209         if self._cfg[section][option].validate:
   180         if self._cfg[section][option].validate:
   210             val = self._cfg[section][option].validate(val)
   181             val = self._cfg[section][option].validate(val)
   211         if not RawConfigParser.has_section(self, section):
   182         if not RawConfigParser.has_section(self, section):
   212             self.add_section(section)
   183             self.add_section(section)
   213         RawConfigParser.set(self, section, option, val)
   184         RawConfigParser.set(self, section, option, val)
   214         self._modified = True
   185         self._modified = True
   215 
   186 
   216     def has_section(self, section):
   187     def has_section(self, section):
   217         """Checks if ``section`` is a known configuration section."""
   188         """Checks if `section` is a known configuration section."""
   218         return section.lower() in self._cfg
   189         return section.lower() in self._cfg
   219 
   190 
   220     def has_option(self, option):
   191     def has_option(self, option):
   221         """Checks if the option (section\ **.**\ option) is a known
   192         """Checks if the option (section.option) is a known configuration
   222         configuration option."""
   193         option."""
   223         try:
   194         try:
   224             self._get_section_option(option)
   195             self._get_section_option(option)
   225             return True
   196             return True
   226         except(BadOptionError, NoSectionError, NoOptionError):
   197         except(BadOptionError, NoSectionError, NoOptionError):
   227             return False
   198             return False
   232 
   203 
   233 
   204 
   234 class LazyConfigOption(object):
   205 class LazyConfigOption(object):
   235     """A simple container class for configuration settings.
   206     """A simple container class for configuration settings.
   236 
   207 
   237    ``LazyConfigOption`` instances are required by `LazyConfig` instances,
   208     `LazyConfigOption` instances are required by `LazyConfig` instances,
   238    and instances of classes derived from ``LazyConfig``, like the
   209     and instances of classes derived from `LazyConfig`, like the
   239    `Config` class.
   210     `Config` class.
   240     """
   211     """
   241     __slots__ = ('__cls', '__default', '__getter', '__validate')
   212     __slots__ = ('__cls', '__default', '__getter', '__validate')
   242 
   213 
   243     def __init__(self, cls, default, getter, validate=None):
   214     def __init__(self, cls, default, getter, validate=None):
   244         """Creates a new ``LazyConfigOption`` instance.
   215         """Creates a new `LazyConfigOption` instance.
   245 
   216 
   246         Arguments:
   217         Arguments:
   247 
   218 
   248         ``cls`` : type
   219         `cls` : type
   249             The class/type of the option's value
   220           The class/type of the option's value
   250         ``default``
   221         `default`
   251             Default value of the option. Use ``None`` if the option should
   222           Default value of the option. Use ``None`` if the option should not
   252             not have a default value.
   223           have a default value.
   253         ``getter`` : callable
   224         `getter` : callable
   254             A method's name of `RawConfigParser` and derived classes, to
   225           A method's name of `RawConfigParser` and derived classes, to get a
   255             get a option's value, e.g. `self.getint`.
   226           option's value, e.g. `self.getint`.
   256         ``validate`` : NoneType or a callable
   227         `validate` : NoneType or a callable
   257             None or any method, that takes one argument, in order to check
   228           None or any method, that takes one argument, in order to check the
   258             the value, when `LazyConfig.set()` is called.
   229           value, when `LazyConfig.set()` is called.
   259         """
   230         """
   260         self.__cls = cls
   231         self.__cls = cls
   261         if not default is None:# enforce the type of the default value
   232         if not default is None:# enforce the type of the default value
   262             self.__default = self.__cls(default)
   233             self.__default = self.__cls(default)
   263         else:
   234         else:
   276         """The class of the option's value e.g. `str`, `unicode` or `bool`"""
   247         """The class of the option's value e.g. `str`, `unicode` or `bool`"""
   277         return self.__cls
   248         return self.__cls
   278 
   249 
   279     @property
   250     @property
   280     def default(self):
   251     def default(self):
   281         """The option's default value, may be ``None``"""
   252         """The option's default value, may be `None`"""
   282         return self.__default
   253         return self.__default
   283 
   254 
   284     @property
   255     @property
   285     def getter(self):
   256     def getter(self):
   286         """The getter method or function to get the option's value"""
   257         """The getter method or function to get the option's value"""
   298     def __init__(self, filename):
   269     def __init__(self, filename):
   299         """Creates a new Config instance
   270         """Creates a new Config instance
   300 
   271 
   301         Arguments:
   272         Arguments:
   302 
   273 
   303         ``filename``
   274         `filename` : str
   304             path to the configuration file
   275           path to the configuration file
   305         """
   276         """
   306         LazyConfig.__init__(self)
   277         LazyConfig.__init__(self)
   307         self._cfgFileName = filename
   278         self._cfgFileName = filename
   308         self._cfgFile = None
   279         self._cfgFile = None
   309         self.__missing = {}
   280         self.__missing = {}
   387                 for option in options:
   358                 for option in options:
   388                     errmsg.write((u'    %s\n') % option)
   359                     errmsg.write((u'    %s\n') % option)
   389             raise VMMConfigException(errmsg.getvalue(), CONF_ERROR)
   360             raise VMMConfigException(errmsg.getvalue(), CONF_ERROR)
   390 
   361 
   391     def known_scheme(self, scheme):
   362     def known_scheme(self, scheme):
   392         """Converts ``scheme`` to upper case and checks if is known by
   363         """Converts `scheme` to upper case and checks if is known by
   393         Dovecot (listed in VirtualMailManager.SCHEMES).
   364         Dovecot (listed in VirtualMailManager.SCHEMES).
   394 
   365 
   395         Throws a `ConfigValueError` if the scheme is not listed in
   366         Throws a `ConfigValueError` if the scheme is not listed in
   396         VirtualMailManager.SCHEMES.
   367         VirtualMailManager.SCHEMES.
   397         """
   368         """
   398         scheme = scheme.upper()
   369         scheme = scheme.upper()
   399         # TODO: VMM.SCHEMES
   370         # TODO: VMM.SCHEMES
   400 
   371 
   401     def unicode(self, section, option):
   372     def unicode(self, section, option):
   402         """Returns the value of the ``option`` from ``section``, converted
   373         """Returns the value of the `option` from `section`, converted to
   403         to Unicode.
   374         Unicode."""
   404         """
       
   405         return get_unicode(self.get(section, option))
   375         return get_unicode(self.get(section, option))
   406 
   376 
   407     def __chkCfg(self):
   377     def __chkCfg(self):
   408         """Checks all section's options for settings w/o a default value.
   378         """Checks all section's options for settings w/o a default value.
   409 
   379 
   410         Returns ``True`` if everything is fine, else ``False``."""
   380         Returns `True` if everything is fine, else `False`."""
   411         errors = False
   381         errors = False
   412         for section in self._cfg.iterkeys():
   382         for section in self._cfg.iterkeys():
   413             missing = []
   383             missing = []
   414             for option, value in self._cfg[section].iteritems():
   384             for option, value in self._cfg[section].iteritems():
   415                 if (value.default is None and
   385                 if (value.default is None and