summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2008-02-19 21:22:20 -0500
committerBarry Warsaw2008-02-19 21:22:20 -0500
commitaab29f252ebefb1520714080a90bb42a25393f18 (patch)
treea5df0c60d606bd3fbe1455d9a6c95be5dd55e6f6
parent2bd332002f241ab7ca77f935a73692f6cbf41fe5 (diff)
downloadmailman-aab29f252ebefb1520714080a90bb42a25393f18.tar.gz
mailman-aab29f252ebefb1520714080a90bb42a25393f18.tar.zst
mailman-aab29f252ebefb1520714080a90bb42a25393f18.zip
-rw-r--r--Mailman/Errors.py54
-rw-r--r--Mailman/app/styles.py16
-rw-r--r--Mailman/bin/newlist.py4
-rw-r--r--Mailman/database/__init__.py3
-rw-r--r--Mailman/database/listmanager.py19
-rw-r--r--Mailman/database/user.py16
-rw-r--r--Mailman/database/usermanager.py5
-rw-r--r--Mailman/docs/listmanager.txt2
-rw-r--r--Mailman/interfaces/address.py20
-rw-r--r--Mailman/interfaces/database.py20
-rw-r--r--Mailman/interfaces/errors.py28
-rw-r--r--Mailman/interfaces/listmanager.py52
-rw-r--r--Mailman/interfaces/styles.py32
-rw-r--r--Mailman/interfaces/usermanager.py5
-rw-r--r--setup.py1
15 files changed, 176 insertions, 101 deletions
diff --git a/Mailman/Errors.py b/Mailman/Errors.py
index c0d5ced72..1c8b215c5 100644
--- a/Mailman/Errors.py
+++ b/Mailman/Errors.py
@@ -36,9 +36,6 @@ class MMUnknownListError(MMListError):
def __str__(self):
return self._listname
-class MMCorruptListDatabaseError(MMListError): pass
-class MMListNotReadyError(MMListError): pass
-class MMListAlreadyExistsError(MMListError): pass
# Membership exceptions
class MMMemberError(MailmanException): pass
@@ -189,22 +186,6 @@ class AlreadySubscribedError(SubscriptionError):
-# Database exceptions
-class DatabaseError(MailmanError):
- """A problem with the database occurred."""
-
-
-class SchemaVersionMismatchError(DatabaseError):
- def __init__(self, got):
- self._got = got
-
- def __str__(self):
- from Mailman.Version import DATABASE_SCHEMA_VERSION
- return 'Incompatible database schema version (got: %d, expected: %d)' \
- % (self._got, DATABASE_SCHEMA_VERSION)
-
-
-
class PasswordError(MailmanError):
"""A password related error."""
@@ -225,38 +206,3 @@ class BadPasswordSchemeError(PasswordError):
def __str__(self):
return 'A bad password scheme was given: %s' % self.scheme_name
-
-
-
-class UserError(MailmanError):
- """A general user-related error occurred."""
-
-
-class RosterError(UserError):
- """A roster-related error occurred."""
-
-
-class RosterExistsError(RosterError):
- """The named roster already exists."""
-
-
-
-class AddressError(MailmanError):
- """A general address-related error occurred."""
-
-
-class ExistingAddressError(AddressError):
- """The given email address already exists."""
-
-
-class AddressAlreadyLinkedError(AddressError):
- """The address is already linked to a user."""
-
-
-class AddressNotLinkedError(AddressError):
- """The address is not linked to the user."""
-
-
-
-class DuplicateStyleError(MailmanError):
- """A style with the same name is already registered."""
diff --git a/Mailman/app/styles.py b/Mailman/app/styles.py
index 92c8bd39b..5c7d2351b 100644
--- a/Mailman/app/styles.py
+++ b/Mailman/app/styles.py
@@ -30,22 +30,25 @@ from zope.interface import implements
from zope.interface.verify import verifyObject
from Mailman import Utils
-from Mailman.Errors import DuplicateStyleError
from Mailman.app.plugins import get_plugins
from Mailman.configuration import config
from Mailman.i18n import _
from Mailman.interfaces import (
- Action, IStyle, IStyleManager, NewsModeration, Personalization)
+ Action, DuplicateStyleError, IStyle, IStyleManager, NewsModeration,
+ Personalization)
class DefaultStyle:
+ """The defalt (i.e. legacy) style."""
+
implements(IStyle)
name = 'default'
priority = 0 # the lowest priority style
def apply(self, mailing_list):
+ """See `IStyle`."""
# For cut-n-paste convenience.
mlist = mailing_list
# Most of these were ripped from the old MailList.InitVars() method.
@@ -233,6 +236,7 @@ class DefaultStyle:
mlist.pipeline = u'built-in'
def match(self, mailing_list, styles):
+ """See `IStyle`."""
# If no other styles have matched, then the default style matches.
if len(styles) == 0:
styles.append(self)
@@ -240,9 +244,12 @@ class DefaultStyle:
class StyleManager:
+ """The built-in style manager."""
+
implements(IStyleManager)
def __init__(self):
+ """Install all styles from registered plugins, and install them."""
self._styles = {}
# Install all the styles provided by plugins.
for style_factory in get_plugins('mailman.styles'):
@@ -251,9 +258,11 @@ class StyleManager:
self.register(style)
def get(self, name):
+ """See `IStyleManager`."""
return self._styles.get(name)
def lookup(self, mailing_list):
+ """See `IStyleManager`."""
matched_styles = []
for style in self.styles:
style.match(mailing_list, matched_styles)
@@ -262,18 +271,21 @@ class StyleManager:
@property
def styles(self):
+ """See `IStyleManager`."""
for style in sorted(self._styles.values(),
key=attrgetter('priority'),
reverse=True):
yield style
def register(self, style):
+ """See `IStyleManager`."""
verifyObject(IStyle, style)
if style.name in self._styles:
raise DuplicateStyleError(style.name)
self._styles[style.name] = style
def unregister(self, style):
+ """See `IStyleManager`."""
# Let KeyErrors percolate up.
del self._styles[style.name]
diff --git a/Mailman/bin/newlist.py b/Mailman/bin/newlist.py
index f63e46724..45373510e 100644
--- a/Mailman/bin/newlist.py
+++ b/Mailman/bin/newlist.py
@@ -31,6 +31,8 @@ from Mailman import i18n
from Mailman.app.lifecycle import create_list
from Mailman.configuration import config
from Mailman.initialize import initialize
+from Mailman.interfaces import ListAlreadyExistsError
+
_ = i18n._
@@ -107,7 +109,7 @@ def main():
mlist.preferred_language = opts.language
except Errors.InvalidEmailAddress:
parser.error(_('Illegal list name: $fqdn_listname'))
- except Errors.MMListAlreadyExistsError:
+ except ListAlreadyExistsError:
parser.error(_('List already exists: $fqdn_listname'))
except Errors.BadDomainSpecificationError, domain:
parser.error(_('Undefined domain: $domain'))
diff --git a/Mailman/database/__init__.py b/Mailman/database/__init__.py
index f6fda8494..7ca60f145 100644
--- a/Mailman/database/__init__.py
+++ b/Mailman/database/__init__.py
@@ -31,7 +31,6 @@ from string import Template
from urlparse import urlparse
from zope.interface import implements
-from Mailman.Errors import SchemaVersionMismatchError
from Mailman.configuration import config
from Mailman.database.listmanager import ListManager
from Mailman.database.messagestore import MessageStore
@@ -39,7 +38,7 @@ from Mailman.database.pending import Pendings
from Mailman.database.requests import Requests
from Mailman.database.usermanager import UserManager
from Mailman.database.version import Version
-from Mailman.interfaces import IDatabase
+from Mailman.interfaces import IDatabase, SchemaVersionMismatchError
diff --git a/Mailman/database/listmanager.py b/Mailman/database/listmanager.py
index a79cbf565..7b02767c7 100644
--- a/Mailman/database/listmanager.py
+++ b/Mailman/database/listmanager.py
@@ -25,30 +25,31 @@ from Mailman import Errors
from Mailman.Utils import split_listname, fqdn_listname
from Mailman.configuration import config
from Mailman.database.mailinglist import MailingList
-from Mailman.interfaces import IListManager
+from Mailman.interfaces import IListManager, ListAlreadyExistsError
class ListManager(object):
+ """An implementation of the `IListManager` interface."""
+
implements(IListManager)
def create(self, fqdn_listname):
+ """See `IListManager`."""
listname, hostname = split_listname(fqdn_listname)
mlist = config.db.store.find(
MailingList,
MailingList.list_name == listname,
MailingList.host_name == hostname).one()
if mlist:
- raise Errors.MMListAlreadyExistsError(fqdn_listname)
+ raise ListAlreadyExistsError(fqdn_listname)
mlist = MailingList(fqdn_listname)
mlist.created_at = datetime.datetime.now()
config.db.store.add(mlist)
return mlist
- def delete(self, mlist):
- config.db.store.remove(mlist)
-
def get(self, fqdn_listname):
+ """See `IListManager`."""
listname, hostname = split_listname(fqdn_listname)
mlist = config.db.store.find(MailingList,
list_name=listname,
@@ -58,14 +59,18 @@ class ListManager(object):
mlist._restore()
return mlist
+ def delete(self, mlist):
+ """See `IListManager`."""
+ config.db.store.remove(mlist)
+
@property
def mailing_lists(self):
- # Don't forget, the MailingList objects that this class manages must
- # be wrapped in a MailList object as expected by this interface.
+ """See `IListManager`."""
for fqdn_listname in self.names:
yield self.get(fqdn_listname)
@property
def names(self):
+ """See `IListManager`."""
for mlist in config.db.store.find(MailingList):
yield fqdn_listname(mlist.list_name, mlist.host_name)
diff --git a/Mailman/database/user.py b/Mailman/database/user.py
index d9c87ada0..65a3c92f8 100644
--- a/Mailman/database/user.py
+++ b/Mailman/database/user.py
@@ -19,16 +19,18 @@ from email.utils import formataddr
from storm.locals import *
from zope.interface import implements
-from Mailman import Errors
from Mailman.configuration import config
from Mailman.database.model import Model
from Mailman.database.address import Address
from Mailman.database.preferences import Preferences
-from Mailman.interfaces import IUser
+from Mailman.interfaces import (
+ AddressAlreadyLinkedError, AddressNotLinkedError, IUser)
class User(Model):
+ """Mailman users."""
+
implements(IUser)
id = Int(primary=True)
@@ -43,16 +45,19 @@ class User(Model):
return '<User "%s" at %#x>' % (self.real_name, id(self))
def link(self, address):
+ """See `IUser`."""
if address.user is not None:
- raise Errors.AddressAlreadyLinkedError(address)
+ raise AddressAlreadyLinkedError(address)
address.user = self
def unlink(self, address):
+ """See `IUser`."""
if address.user is None:
- raise Errors.AddressNotLinkedError(address)
+ raise AddressNotLinkedError(address)
address.user = None
def controls(self, address):
+ """See `IUser`."""
found = config.db.store.find(Address, address=address)
if found.count() == 0:
return False
@@ -60,6 +65,7 @@ class User(Model):
return found[0].user is self
def register(self, address, real_name=None):
+ """See `IUser`."""
# First, see if the address already exists
addrobj = config.db.store.find(Address, address=address).one()
if addrobj is None:
@@ -69,6 +75,6 @@ class User(Model):
addrobj.preferences = Preferences()
# Link the address to the user if it is not already linked.
if addrobj.user is not None:
- raise Errors.AddressAlreadyLinkedError(addrobj)
+ raise AddressAlreadyLinkedError(addrobj)
addrobj.user = self
return addrobj
diff --git a/Mailman/database/usermanager.py b/Mailman/database/usermanager.py
index d5b7003dc..315e362d7 100644
--- a/Mailman/database/usermanager.py
+++ b/Mailman/database/usermanager.py
@@ -23,12 +23,11 @@ import os
from zope.interface import implements
-from Mailman import Errors
from Mailman.configuration import config
from Mailman.database.address import Address
from Mailman.database.preferences import Preferences
from Mailman.database.user import User
-from Mailman.interfaces import IUserManager
+from Mailman.interfaces import ExistingAddressError, IUserManager
@@ -67,7 +66,7 @@ class UserManager(object):
addresses = config.db.store.find(Address, address=address.lower())
if addresses.count() == 1:
found = addresses[0]
- raise Errors.ExistingAddressError(found.original_address)
+ raise ExistingAddressError(found.original_address)
assert addresses.count() == 0, 'Unexpected results'
if real_name is None:
real_name = u''
diff --git a/Mailman/docs/listmanager.txt b/Mailman/docs/listmanager.txt
index 832100aca..7a5c78df9 100644
--- a/Mailman/docs/listmanager.txt
+++ b/Mailman/docs/listmanager.txt
@@ -40,7 +40,7 @@ you will get an exception.
>>> mlist_dup = listmgr.create(u'_xtest@example.com')
Traceback (most recent call last):
...
- MMListAlreadyExistsError: _xtest@example.com
+ ListAlreadyExistsError: _xtest@example.com
Deleting a mailing list
diff --git a/Mailman/interfaces/address.py b/Mailman/interfaces/address.py
index c843ce4eb..bbc291a64 100644
--- a/Mailman/interfaces/address.py
+++ b/Mailman/interfaces/address.py
@@ -19,6 +19,26 @@
from zope.interface import Interface, Attribute
+from Mailman.interfaces.errors import MailmanError
+
+
+
+class AddressError(MailmanError):
+ """A general address-related error occurred."""
+
+
+class ExistingAddressError(AddressError):
+ """The given email address already exists."""
+
+
+class AddressAlreadyLinkedError(AddressError):
+ """The address is already linked to a user."""
+
+
+class AddressNotLinkedError(AddressError):
+ """The address is not linked to the user."""
+
+
class IAddress(Interface):
diff --git a/Mailman/interfaces/database.py b/Mailman/interfaces/database.py
index 8770839af..c969e9ff5 100644
--- a/Mailman/interfaces/database.py
+++ b/Mailman/interfaces/database.py
@@ -25,6 +25,26 @@ Mailman's back end.
from zope.interface import Interface, Attribute
+from Mailman.Version import DATABASE_SCHEMA_VERSION
+from Mailman.interfaces.errors import MailmanError
+
+
+
+class DatabaseError(MailmanError):
+ """A problem with the database occurred."""
+
+
+class SchemaVersionMismatchError(DatabaseError):
+ """The database schema version number did not match what was expected."""
+
+ def __init__(self, got):
+ self._got = got
+
+ def __str__(self):
+ return (
+ 'Incompatible database schema version (got: %d, expected: %d)'
+ % (self._got, DATABASE_SCHEMA_VERSION))
+
class IDatabase(Interface):
diff --git a/Mailman/interfaces/errors.py b/Mailman/interfaces/errors.py
new file mode 100644
index 000000000..81f03d1ea
--- /dev/null
+++ b/Mailman/interfaces/errors.py
@@ -0,0 +1,28 @@
+# Copyright (C) 1998-2008 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.
+
+"""Base Mailman exceptions.
+
+The exceptions in this module are those that are commonly shared among many
+components. More specific exceptions will be located in the relevant
+interfaces.
+"""
+
+
+
+class MailmanError(Exception):
+ """Base class for all Mailman exceptions."""
diff --git a/Mailman/interfaces/listmanager.py b/Mailman/interfaces/listmanager.py
index 0a3b7043e..38321f3ba 100644
--- a/Mailman/interfaces/listmanager.py
+++ b/Mailman/interfaces/listmanager.py
@@ -17,44 +17,64 @@
"""Interface for list storage, deleting, and finding."""
+__metaclass__ = type
+__all__ = [
+ 'IListManager',
+ 'ListAlreadyExistsError',
+ ]
+
+
from zope.interface import Interface, Attribute
+from Mailman.interfaces.errors import MailmanError
+
+
+
+class ListAlreadyExistsError(MailmanError):
+ """Attempted to create a mailing list that already exists.
+
+ Mailing list objects must be uniquely named by their fully qualified list
+ name.
+ """
class IListManager(Interface):
"""The interface of the global list manager.
- The list manager manages IMailingList objects. You can add and remove
- IMailingList objects from the list manager, and you can retrieve them
- from the manager via their fully qualified list name
- (e.g. 'mylist@example.com').
+ The list manager manages `IMailingList` objects. You can add and remove
+ `IMailingList` objects from the list manager, and you can retrieve them
+ from the manager via their fully qualified list name, e.g.:
+ `mylist@example.com`.
"""
def create(fqdn_listname):
- """Create an IMailingList with the given fully qualified list name.
+ """Create a mailing list with the given name.
- Raises MMListAlreadyExistsError if the named list already exists.
+ :type fqdn_listname: Unicode
+ :param fqdn_listname: The fully qualified name of the mailing list,
+ e.g. `mylist@example.com`.
+ :return: The newly created `IMailingList`.
+ :raise `ListAlreadyExistsError` if the named list already exists.
"""
def get(fqdn_listname):
- """Return the IMailingList with the given fully qualified list name.
+ """Return the mailing list with the given name, if it exists.
- Raises MMUnknownListError if the names list does not exist.
+ :type fqdn_listname: Unicode.
+ :param fqdn_listname: The fully qualified name of the mailing list.
+ :return: the matching `IMailingList` or None if the named list does
+ not exist.
"""
def delete(mlist):
- """Remove the IMailingList from the backend storage."""
-
- def get(fqdn_listname):
- """Find the IMailingList with the matching fully qualified list name.
+ """Remove the mailing list from the database.
- :param fqdn_listname: Fully qualified list name to get.
- :return: The matching IMailingList or None if there was no such
- matching mailing list.
+ :type mlist: `IMailingList`
+ :param mlist: The mailing list to delete.
"""
mailing_lists = Attribute(
- """An iterator over all the IMailingList objects managed by this list
+ """An iterator over all the mailing list objects managed by this list
manager.""")
names = Attribute(
diff --git a/Mailman/interfaces/styles.py b/Mailman/interfaces/styles.py
index 49084ecbf..aaa88e330 100644
--- a/Mailman/interfaces/styles.py
+++ b/Mailman/interfaces/styles.py
@@ -17,7 +17,21 @@
"""Interfaces for list styles."""
+__metaclass__ = type
+__all__ = [
+ 'DuplicateStyleError',
+ 'IStyle',
+ 'IStyleManager',
+ ]
+
+
from zope.interface import Interface, Attribute
+from Mailman.interfaces.errors import MailmanError
+
+
+
+class DuplicateStyleError(MailmanError):
+ """A style with the same name is already registered."""
@@ -33,7 +47,8 @@ class IStyle(Interface):
def apply(mailing_list):
"""Apply the style to the mailing list.
- :param mailing_list: an IMailingList.
+ :type mailing_list: `IMailingList`.
+ :param mailing_list: the mailing list to apply the style to.
"""
def match(mailing_list, styles):
@@ -43,8 +58,9 @@ class IStyle(Interface):
the style may append itself to the `styles` list. This list will be
ordered when returned from `IStyleManager.lookup()`.
- :param mailing_list: an IMailingList.
- :param styles: ordered list of IStyles matched so far.
+ :type mailing_list: `IMailingList`.
+ :param mailing_list: the mailing list object.
+ :param styles: ordered list of `IStyles` matched so far.
"""
@@ -55,20 +71,22 @@ class IStyleManager(Interface):
def get(name):
"""Return the named style or None.
+ :type name: Unicode
:param name: A style name.
- :return: an IStyle or None.
+ :return: the named `IStyle` or None if the style doesn't exist.
"""
def lookup(mailing_list):
"""Return a list of styles for the given mailing list.
- Use various registered rules to find an IStyle for the given mailing
+ Use various registered rules to find an `IStyle` for the given mailing
list. The returned styles are ordered by their priority.
Style matches can be registered and reordered by plugins.
- :param mailing_list: An IMailingList.
- :return: ordered list of IStyles. Zero is the lowest priority.
+ :type mailing_list: `IMailingList`.
+ :param mailing_list: The mailing list object to find a style for.
+ :return: ordered list of `IStyles`. Zero is the lowest priority.
"""
styles = Attribute(
diff --git a/Mailman/interfaces/usermanager.py b/Mailman/interfaces/usermanager.py
index a2f912e60..702370593 100644
--- a/Mailman/interfaces/usermanager.py
+++ b/Mailman/interfaces/usermanager.py
@@ -38,8 +38,9 @@ class IUserManager(Interface):
When address is given, an IAddress is also created and linked to the
new IUser object. If the address already exists, an
- ExistingAddressError is raised. If the address exists but is already
- linked to another user, an AddressAlreadyLinkedError is raised.
+ `ExistingAddressError` is raised. If the address exists but is
+ already linked to another user, an AddressAlreadyLinkedError is
+ raised.
When real_name is given, the IUser's real_name is set to this string.
If an IAddress is also created and linked, its real_name is set to the
diff --git a/setup.py b/setup.py
index 8d6bd88c6..9cb6370b1 100644
--- a/setup.py
+++ b/setup.py
@@ -92,7 +92,6 @@ Any other spelling is incorrect.""",
'mailman.rules' : 'default = Mailman.rules:initialize',
'mailman.handlers' : 'default = Mailman.pipeline:initialize',
},
- # Third-party requirements.
install_requires = [
'locknix',
'munepy',