VMM/ext/Postconf: Reworked class Postconf. Added method edit(). v0.6.x
authorPascal Volk <neverseen@users.sourceforge.net>
Sun, 25 Jul 2010 03:31:32 +0000
branchv0.6.x
changeset 311 a0a10100aee5
parent 310 644e2cc4a441
child 312 6f39a1e56f4a
VMM/ext/Postconf: Reworked class Postconf. Added method edit().
VirtualMailManager/ext/Postconf.py
--- a/VirtualMailManager/ext/Postconf.py	Fri Jul 23 19:07:30 2010 +0000
+++ b/VirtualMailManager/ext/Postconf.py	Sun Jul 25 03:31:32 2010 +0000
@@ -1,84 +1,127 @@
 # -*- coding: UTF-8 -*-
 # Copyright (c) 2008 - 2010, Pascal Volk
 # See COPYING for distribution information.
+"""
+    VirtualMailManager.ext.Postconf
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-"""A small - r/o - wrapper class for Postfix' postconf."""
+    Wrapper class for Postfix's postconf.
+    Postconf instances can be used to read actual values of configuration
+    parameters or edit the value of a configuration parameter.
+
+    postconf.read(parameter) -> value
+    postconf.edit(parameter, value)
+"""
 
 import re
 from subprocess import Popen, PIPE
 
-import VirtualMailManager.constants.ERROR as ERR
 from VirtualMailManager.errors import VMMError
+from VirtualMailManager.constants.ERROR import VMM_ERROR
 
-RE_PC_PARAMS = """^\w+$"""
-RE_PC_VARIABLES = r"""\$\b\w+\b"""
+_ = lambda msg: msg
+
 
 class Postconf(object):
-    __slots__ = ('__bin', '__val', '__varFinder')
+    """Wrapper class for Postfix's postconf."""
+    __slots__ = ('_bin', '_val')
+    _parameter_re = re.compile(r'^\w+$')
+    _variables_re = re.compile(r'\$\b\w+\b')
+
     def __init__(self, postconf_bin):
         """Creates a new Postconf instance.
 
-        Keyword arguments:
-        postconf_bin -- absolute path to the Postfix postconf binary (str)
+        Argument:
+
+        `postconf_bin` : str
+          absolute path to the Postfix postconf binary.
         """
-        self.__bin = postconf_bin
-        self.__val = ''
-        self.__varFinder = re.compile(RE_PC_VARIABLES)
+        self._bin = postconf_bin
+        self._val = ''
+
+    def edit(self, parameter, value):
+        """Set the `parameter`'s value to `value`.
+
+        Arguments:
+
+        `parameter` : str
+          the name of a Postfix configuration parameter
+        `value` : str
+          the parameter's new value.
+        """
+        self._check_parameter(parameter)
+        stdout, stderr = Popen((self._bin, '-e', parameter + '=' + str(value)),
+                               stderr=PIPE).communicate()
+        if stderr:
+            raise VMMError(stderr.strip(), VMM_ERROR)
 
     def read(self, parameter, expand_vars=True):
         """Returns the parameters value.
 
         If expand_vars is True (default), all variables in the value will be
         expanded:
-        e.g. mydestination -> mail.example.com, localhost.example.com, localhost
+        e.g. mydestination: mail.example.com, localhost.example.com, localhost
         Otherwise the value may contain one or more variables.
-        e.g. mydestination -> $myhostname, localhost.$mydomain, localhost
+        e.g. mydestination: $myhostname, localhost.$mydomain, localhost
+
+        Arguments:
 
-        Keyword arguments:
-        parameter -- the name of a Postfix configuration parameter (str)
-        expand_vars -- default True (bool)
+        `parameter` : str
+          the name of a Postfix configuration parameter.
+        `expand_vars` : bool
+          indicates if variables should be expanded or not, default True
         """
-        if not re.match(RE_PC_PARAMS, parameter):
+        self._check_parameter(parameter)
+        self._val = self._read(parameter)
+        if expand_vars:
+            self._expand_vars()
+        return self._val
+
+    def _check_parameter(self, parameter):
+        """Check that the `parameter` looks like a configuration parameter.
+        If not, a VMMError will be raised."""
+        if not self.__class__._parameter_re.match(parameter):
             raise VMMError(_(u"The value '%s' doesn't look like a valid "
                              u"postfix configuration parameter name.") %
-                           parameter, ERR.VMM_ERROR)
-        self.__val = self.__read(parameter)
-        if expand_vars:
-            self.__expandVars()
-        return self.__val
+                           parameter, VMM_ERROR)
 
-    def __expandVars(self):
+    def _expand_vars(self):
+        """Expand the $variables in self._val to their values."""
         while True:
-            pvars = set(self.__varFinder.findall(self.__val))
-            pvars_len = len(pvars)
-            if pvars_len < 1:
+            pvars = set(self.__class__._variables_re.findall(self._val))
+            if not pvars:
                 break
-            if pvars_len > 1:
-                self.__expandMultiVars(self.__readMulti(pvars))
+            if len(pvars) > 1:
+                self._expand_multi_vars(self._read_multi(pvars))
                 continue
             pvars = pvars.pop()
-            self.__val = self.__val.replace(pvars, self.__read(pvars[1:]))
+            self._val = self._val.replace(pvars, self._read(pvars[1:]))
 
-    def __expandMultiVars(self, old_new):
-        for old, new in old_new.items():
-            self.__val = self.__val.replace('$'+old, new)
+    def _expand_multi_vars(self, old_new):
+        """Replace all $vars in self._val with their values."""
+        for old, new in old_new.iteritems():
+            self._val = self._val.replace('$' + old, new)
 
-    def __read(self, parameter):
-        out, err = Popen([self.__bin, '-h', parameter], stdout=PIPE,
-                stderr=PIPE).communicate()
-        if len(err):
-            raise VMMError(err.strip(), ERR.VMM_ERROR)
-        return out.strip()
+    def _read(self, parameter):
+        """Ask postconf for the value of a single configuration parameter."""
+        stdout, stderr = Popen([self._bin, '-h', parameter], stdout=PIPE,
+                               stderr=PIPE).communicate()
+        if stderr:
+            raise VMMError(stderr.strip(), VMM_ERROR)
+        return stdout.strip()
 
-    def __readMulti(self, parameters):
-        cmd = [self.__bin]
+    def _read_multi(self, parameters):
+        """Ask postconf for multiple configuration parameters. Returns a dict
+        parameter: value items."""
+        cmd = [self._bin]
         cmd.extend(parameter[1:] for parameter in parameters)
-        out, err = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
-        if len(err):
-            raise VMMError(err.strip(), ERR.VMM_ERROR)
+        stdout, stderr = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
+        if stderr:
+            raise VMMError(stderr.strip(), VMM_ERROR)
         par_val = {}
-        for line in out.splitlines():
+        for line in stdout.splitlines():
             par, val = line.split(' = ')
             par_val[par] = val
         return par_val
 
+del _