------------------------------------------------------------
revno: 6729
committer: Barry Warsaw <[email protected]>
branch nick: 3.0
timestamp: Fri 2009-05-15 18:37:29 -0400
message:
  Add initialization pre- and post- hooks, configurable in the config file.
  This lets you run a bit of Python at various stages of the initialization
  process.
  
  Move the warnings filters to the top mailman package __init__.py so you always
  get it.  lazr.restful is too chatty.
  
  The environment variable $MAILMAN_CONFIG_FILE now overrides -C.  Hmm, I think
  we really want it the original way.
added:
  src/mailman/docs/hooks.txt
modified:
  src/mailman/__init__.py
  src/mailman/config/config.py
  src/mailman/config/schema.cfg
  src/mailman/core/initialize.py
  src/mailman/options.py
  src/mailman/rest/webservice.py

=== modified file 'src/mailman/__init__.py'
--- src/mailman/__init__.py     2009-03-30 01:20:57 +0000
+++ src/mailman/__init__.py     2009-05-15 22:37:29 +0000
@@ -0,0 +1,31 @@
+# Copyright (C) 2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman.  If not, see <http://www.gnu.org/licenses/>.
+
+"""The `mailman` package."""
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+    ]
+
+
+# lazr.restful uses the sha module, but that's deprecated in Python 2.6 in
+# favor of the hashlib module.
+import warnings
+warnings.filterwarnings(
+    'ignore', category=DeprecationWarning, module='lazr.restful._resource')

=== modified file 'src/mailman/config/config.py'
--- src/mailman/config/config.py        2009-05-10 20:13:02 +0000
+++ src/mailman/config/config.py        2009-05-15 22:37:29 +0000
@@ -40,7 +40,6 @@
 from mailman.styles.manager import StyleManager
 from mailman.utilities.filesystem import makedirs
 
-
 SPACE = ' '
 
 

=== modified file 'src/mailman/config/schema.cfg'
--- src/mailman/config/schema.cfg       2009-05-03 19:35:29 +0000
+++ src/mailman/config/schema.cfg       2009-05-15 22:37:29 +0000
@@ -54,6 +54,14 @@
 # the pending database.
 pending_request_life: 3d
 
+# A callable to run with no arguments early in the initialization process.
+# This runs before database initialization.
+pre_hook:
+
+# A callable to run with no arguments late in the initialization process.
+# This runs after adapters are initialized.
+post_hook:
+
 
 [passwords]
 # When Mailman generates them, this is the default length of member passwords.

=== modified file 'src/mailman/core/initialize.py'
--- src/mailman/core/initialize.py      2009-03-06 02:30:14 +0000
+++ src/mailman/core/initialize.py      2009-05-15 22:37:29 +0000
@@ -89,15 +89,21 @@
     :param debug: Should the database layer be put in debug mode?
     :type debug: boolean
     """
+    # Run the pre-hook if there is one.
+    config = mailman.config.config
+    if config.mailman.pre_hook:
+        package, dot, function = config.mailman.pre_hook.rpartition('.')
+        __import__(package)
+        getattr(sys.modules[package], function)()
     # Instantiate the database class, ensure that it's of the right type, and
     # initialize it.  Then stash the object on our configuration object.
-    database_class = mailman.config.config.database['class']
-    module_name, class_name = database_class.rsplit('.', 1)
-    __import__(module_name)
-    database = getattr(sys.modules[module_name], class_name)()
+    database_class = config.database['class']
+    package, dot, class_name = database_class.rpartition('.')
+    __import__(package)
+    database = getattr(sys.modules[package], class_name)()
     verifyObject(IDatabase, database)
     database.initialize(debug)
-    mailman.config.config.db = database
+    config.db = database
     # Initialize the rules and chains.  Do the imports here so as to avoid
     # circular imports.
     from mailman.app.commands import initialize as initialize_commands
@@ -123,6 +129,12 @@
     from mailman.database.mailinglist import (
         adapt_mailing_list_to_acceptable_alias_set)
     adapter_hooks.append(adapt_mailing_list_to_acceptable_alias_set)
+    # Run the post-hook if there is one.
+    config = mailman.config.config
+    if config.mailman.post_hook:
+        package, dot, function = config.mailman.post_hook.rpartition('.')
+        __import__(package)
+        getattr(sys.modules[package], function)()
 
 
 

=== added file 'src/mailman/docs/hooks.txt'
--- src/mailman/docs/hooks.txt  1970-01-01 00:00:00 +0000
+++ src/mailman/docs/hooks.txt  2009-05-15 22:37:29 +0000
@@ -0,0 +1,111 @@
+=====
+Hooks
+=====
+
+Mailman defines two initialization hooks, one which is run early in the
+initialization process and the other run late in the initialization process.
+Hooks name an importable callable so it must be accessible on sys.path.
+
+    >>> import os, sys
+    >>> from mailman.config import config
+    >>> config_directory = os.path.dirname(config.filename)
+    >>> sys.path.insert(0, config_directory)
+
+    >>> hook_path = os.path.join(config_directory, 'hooks.py')
+    >>> with open(hook_path, 'w') as fp:
+    ...     print >> fp, """\
+    ... counter = 1
+    ... def pre_hook():
+    ...     global counter
+    ...     print 'pre-hook:', counter
+    ...     counter += 1
+    ...
+    ... def post_hook():
+    ...     global counter
+    ...     print 'post-hook:', counter
+    ...     counter += 1
+    ... """
+    >>> fp.close()
+
+
+Pre-hook
+========
+
+We can set the pre-hook in the configuration file.
+
+    >>> config_path = os.path.join(config_directory, 'hooks.cfg')
+    >>> with open(config_path, 'w') as fp:
+    ...     print >> fp, """\
+    ... [meta]
+    ... extends: test.cfg
+    ...
+    ... [mailman]
+    ... pre_hook: hooks.pre_hook
+    ... """
+
+The hooks are run in the second and third steps of initialization.  However,
+we can't run those initialization steps in process, so call `bin/version` to
+force the hooks to run.
+
+    >>> import subprocess
+    >>> def call():
+    ...     proc = subprocess.Popen(
+    ...         'bin/version',
+    ...         cwd='../..',  # testrunner runs from ./parts/test
+    ...         env=dict(MAILMAN_CONFIG_FILE=config_path,
+    ...                  PYTHONPATH=config_directory),
+    ...         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    ...     stdout, stderr = proc.communicate()
+    ...     assert proc.returncode == 0, stderr
+    ...     print stdout
+
+    >>> call()
+    pre-hook: 1
+    Using GNU Mailman 3...
+    <BLANKLINE>
+
+    >>> os.remove(config_path)
+
+
+Post-hook
+=========
+
+We can set the post-hook in the configuration file.
+
+    >>> with open(config_path, 'w') as fp:
+    ...     print >> fp, """\
+    ... [meta]
+    ... extends: test.cfg
+    ...
+    ... [mailman]
+    ... post_hook: hooks.post_hook
+    ... """
+
+    >>> call()
+    post-hook: 1
+    Using GNU Mailman 3...
+    <BLANKLINE>
+
+    >>> os.remove(config_path)
+
+
+Running both hooks
+==================
+
+We can set the pre- and post-hooks in the configuration file.
+
+    >>> with open(config_path, 'w') as fp:
+    ...     print >> fp, """\
+    ... [meta]
+    ... extends: test.cfg
+    ...
+    ... [mailman]
+    ... pre_hook: hooks.pre_hook
+    ... post_hook: hooks.post_hook
+    ... """
+
+    >>> call()
+    pre-hook: 1
+    post-hook: 2
+    Using GNU Mailman 3...
+    <BLANKLINE>

=== modified file 'src/mailman/options.py'
--- src/mailman/options.py      2009-02-05 04:35:49 +0000
+++ src/mailman/options.py      2009-05-15 22:37:29 +0000
@@ -137,10 +137,8 @@
             from the configuration files.
         :type propagate_logs: bool or None.
         """
-        # Fall back to using the environment variable if -C is not given.
-        config_file = (os.getenv('MAILMAN_CONFIG_FILE')
-                       if self.options.config is None
-                       else self.options.config)
+        # The environment variable overrides the -C option.
+        config_file = os.getenv('MAILMAN_CONFIG_FILE', self.options.config)
         initialize(config_file, propagate_logs=propagate_logs)
         self.sanity_check()
 

=== modified file 'src/mailman/rest/webservice.py'
--- src/mailman/rest/webservice.py      2009-05-07 02:07:35 +0000
+++ src/mailman/rest/webservice.py      2009-05-15 22:37:29 +0000
@@ -28,13 +28,6 @@
 
 
 import logging
-import warnings
-
-# lazr.restful uses the sha module, but that's deprecated in Python 2.6 in
-# favor of the hashlib module.
-warnings.filterwarnings(
-    'ignore', category=DeprecationWarning, module='lazr.restful._resource')
-
 
 # Don't use wsgiref.simple_server.make_server() because we need to override
 # BaseHTTPRequestHandler.log_message() so that logging output will go to the



--
Primary development focus
https://code.launchpad.net/~mailman-coders/mailman/3.0

Your team Mailman Checkins is subscribed to branch lp:mailman.
To unsubscribe from this branch go to 
https://code.launchpad.net/~mailman-coders/mailman/3.0/+edit-subscription.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe: 
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org

Reply via email to