------------------------------------------------------------
revno: 6534
committer: Barry Warsaw <[EMAIL PROTECTED]>
branch nick: entrypoints
timestamp: Tue 2007-07-24 18:45:25 -0400
message:
  Add setuptools plug-in entry point for defining different database backends.
  Now someone could distribute a setuptools package that provided say, a MySQL
  database implementation and very easily override the stock database.  How
  awesome is setuptools?
  
  Removed MANAGERS_INIT_FUNCTION since setuptools gives us a much more standard
  way of defining this plug-in entry point.  Remove other old crud from
  Defaults.py.
  
  Restructure our own 'stock' database backend to be a plugin so it's totally on
  par with any other package.  The only special case is that if more than one
  such entry point is defined, we filter out the 'stock' one (i.e. ours) under
  the assumption that the user is overriding it.  If we still have more than one
  plug-in, it's an error.
  
  Restructure the initialization subsystem to use the plug-in, doing all the
  proper assertions and what not.  The IDatabase interface defines what the
  database back-end plugin must provide.  I've no doubt this will eventually
  need a bit more fleshing out, but it gives all this stuff a principled hook
  point instead of something ad-hoc.
added:
  Mailman/interfaces/database.py
modified:
  Mailman/Defaults.py
  Mailman/database/__init__.py
  Mailman/initialize.py
  setup.py

=== added file 'Mailman/interfaces/database.py'
--- a/Mailman/interfaces/database.py    1970-01-01 00:00:00 +0000
+++ b/Mailman/interfaces/database.py    2007-07-24 22:45:25 +0000
@@ -0,0 +1,48 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# This program 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 2
+# of the License, or (at your option) any later version.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Interfaces for database interaction.
+
+By providing an object with this interface and declaring it in a package
+setup.py file as an entry point in the 'mailman.database' group with the name
+'initializer', you can distribute entirely different database layers for
+Mailman's back end.
+"""
+
+from zope.interface import Interface, Attribute
+
+
+
+class IDatabase(Interface):
+    """Database layer interface."""
+
+    def initialize():
+        """Initialize the database layer, using whatever means necessary."""
+
+    def flush():
+        """Flush current database changes."""
+
+    # XXX Eventually we probably need to support a transaction manager
+    # interface, e.g. begin(), commit(), abort().  We will probably also need
+    # to support a shutdown() method for cleanly disconnecting from the
+    # database.sy
+
+    list_manager = Attribute(
+        """The IListManager instance provided by the database layer.""")
+
+    user_manager = Attribute(
+        """The IUserManager instance provided by the database layer.""")

=== modified file 'Mailman/Defaults.py'
--- a/Mailman/Defaults.py       2007-07-17 03:55:49 +0000
+++ b/Mailman/Defaults.py       2007-07-24 22:45:25 +0000
@@ -1,5 +1,3 @@
-# -*- python -*-
-
 # Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
 #
 # This program is free software; you can redistribute it and/or
@@ -19,11 +17,6 @@
 
 """Distributed default settings for significant Mailman config variables."""
 
-# NEVER make site configuration changes to this file.  ALWAYS make them in
-# mm_cfg.py instead, in the designated area.  See the comments in that file
-# for details.
-
-
 import os
 
 from munepy import Enum
@@ -110,11 +103,6 @@
 # Database options
 #####
 
-# Initialization function for creating the IListManager, IUserManager, and
-# IMessageManager objects, as a Python dotted name.  This function must take
-# zero arguments.
-MANAGERS_INIT_FUNCTION = 'Mailman.database.initialize'
-
 # Use this to set the SQLAlchemy database engine URL.  You generally have one
 # primary database connection for all of Mailman.  List data and most rosters
 # will store their data in this database, although external rosters may access

=== modified file 'Mailman/database/__init__.py'
--- a/Mailman/database/__init__.py      2007-05-28 20:21:41 +0000
+++ b/Mailman/database/__init__.py      2007-07-24 22:45:25 +0000
@@ -20,30 +20,45 @@
 import os
 
 from elixir import objectstore
+from zope.interface import implements
 
+from Mailman.interfaces import IDatabase
 from Mailman.database.listmanager import ListManager
 from Mailman.database.usermanager import UserManager
 
+__metaclass__ = type
 __all__ = [
-    'initialize',
-    'flush',
+    'StockDatabase',
+    'flush', # for test convenience
     ]
 
+flush = None
+
 
 
-def initialize():
-    from Mailman.LockFile import LockFile
-    from Mailman.configuration import config
-    from Mailman.database import model
-    # Serialize this so we don't get multiple processes trying to create the
-    # database at the same time.
-    lockfile = os.path.join(config.LOCK_DIR, '<dbcreatelock>')
-    with LockFile(lockfile):
-        model.initialize()
-    config.list_manager = ListManager()
-    config.user_manager = UserManager()
-    flush()
-
-
-def flush():
-    objectstore.flush()
+class StockDatabase:
+    implements(IDatabase)
+
+    def __init__(self):
+        # Expose the flush() method for test case convenience using the stock
+        # database.
+        global flush
+        flush = self.flush
+        self.list_manager = None
+        self.user_manager = None
+
+    def initialize(self):
+        from Mailman.LockFile import LockFile
+        from Mailman.configuration import config
+        from Mailman.database import model
+        # Serialize this so we don't get multiple processes trying to create 
the
+        # database at the same time.
+        lockfile = os.path.join(config.LOCK_DIR, '<dbcreatelock>')
+        with LockFile(lockfile):
+            model.initialize()
+        self.list_manager = ListManager()
+        self.user_manager = UserManager()
+        self.flush()
+
+    def flush(self):
+        objectstore.flush()

=== modified file 'Mailman/initialize.py'
--- a/Mailman/initialize.py     2007-06-27 21:33:42 +0000
+++ b/Mailman/initialize.py     2007-07-24 22:45:25 +0000
@@ -26,12 +26,16 @@
 
 import os
 import sys
+import pkg_resources
+
+from zope.interface.verify import verifyObject
 
 import Mailman.configuration
-import Mailman.database
 import Mailman.ext
 import Mailman.loginit
 
+from Mailman.interfaces import IDatabase, IListManager, IUserManager
+
 DOT = '.'
 
 
@@ -55,17 +59,44 @@
     Mailman.loginit.initialize(propagate_logs)
     # Set up site extensions directory
     Mailman.ext.__path__.append(Mailman.configuration.config.EXT_DIR)
-    # Initialize the IListManager, IMemberManager, and IMessageManager
-    modparts = Mailman.configuration.config.MANAGERS_INIT_FUNCTION.split(DOT)
-    funcname = modparts.pop()
-    modname  = DOT.join(modparts)
-    __import__(modname)
-    initfunc = getattr(sys.modules[modname], funcname)
-    initfunc()
 
 
 def initialize_2():
-    Mailman.database.initialize()
+    # Find all declared entry points in the mailman.database group.  There
+    # must be exactly one or two such entry points defined.  If there are two,
+    # then we remove the one called 'stock' since that's the one that we
+    # distribute and it's obviously being overridden.  If we're still left
+    # with more than one after we filter out the stock one, it is an error.
+    entrypoints = list(pkg_resources.iter_entry_points('mailman.database'))
+    if len(entrypoints) == 0:
+        raise RuntimeError('No database entry points found')
+    elif len(entrypoints) == 1:
+        # Okay, this is the one to use.
+        entrypoint = entrypoints[0]
+    elif len(database) == 2:
+        # Find the one /not/ named 'stock'.
+        entrypoints = [ep for ep in entrypoints if ep.name <> 'stock']
+        if len(entrypoints) == 0:
+            raise RuntimeError('No database entry points found')
+        elif len(entrypoints) == 2:
+            raise RuntimeError('Too many database entry points defined')
+        else:
+            assert len(entrypoints) == 1, 'Insanity'
+            entrypoint = entrypoint[0]
+    else:
+        raise RuntimeError('Too many database entry points defined')
+    # Instantiate the database entry point, ensure that it's of the right
+    # type, and initialize it.  Then stash the object on our configuration
+    # object.
+    ep_object = entrypoint.load()
+    db = ep_object()
+    verifyObject(IDatabase, db)
+    db.initialize()
+    Mailman.configuration.config.db = db
+    verifyObject(IListManager, db.list_manager)
+    Mailman.configuration.config.list_manager = db.list_manager
+    verifyObject(IUserManager, db.user_manager)
+    Mailman.configuration.config.user_manager = db.user_manager
 
 
 def initialize(config=None, propagate_logs=False):

=== modified file 'setup.py'
--- a/setup.py  2007-07-21 14:04:17 +0000
+++ b/setup.py  2007-07-24 22:45:25 +0000
@@ -82,9 +82,9 @@
     include_package_data = True,
     entry_points    = {
         'console_scripts': list(scripts),
-        'setuptools.file_finders': [
-            'bzr = setuptoolsbzr:find_files_for_bzr',
-            ],
+        'setuptools.file_finders': 'bzr = setuptoolsbzr:find_files_for_bzr',
+        # Entry point for plugging in different database backends.
+        'mailman.database': 'stock = Mailman.database:StockDatabase',
         },
     # Third-party requirements.
     install_requires = [



--
(no title)
https://code.launchpad.net/~mailman-coders/mailman/3.0

You are receiving this branch notification because you are subscribed to it.
To unsubscribe from this branch go to 
https://code.launchpad.net/~mailman-coders/mailman/3.0/+subscription/mailman-checkins.
_______________________________________________
Mailman-checkins mailing list
Mailman-checkins@python.org
Unsubscribe: 
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org

Reply via email to