summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2007-08-05 07:30:30 -0400
committerBarry Warsaw2007-08-05 07:30:30 -0400
commit2999c404a486cb0c7bd76407501e0a6b775c148a (patch)
tree83645fed9d0e69654d5852067ec6ee02ab80fe31
parent959f34a62e0ec3cbe73da3d43640ccb6791cf3a0 (diff)
downloadmailman-2999c404a486cb0c7bd76407501e0a6b775c148a.tar.gz
mailman-2999c404a486cb0c7bd76407501e0a6b775c148a.tar.zst
mailman-2999c404a486cb0c7bd76407501e0a6b775c148a.zip
Added a doctest for styles.
-rw-r--r--Mailman/app/styles.py8
-rw-r--r--Mailman/docs/styles.txt142
2 files changed, 148 insertions, 2 deletions
diff --git a/Mailman/app/styles.py b/Mailman/app/styles.py
index 55d8aa690..e0bf58cde 100644
--- a/Mailman/app/styles.py
+++ b/Mailman/app/styles.py
@@ -45,6 +45,8 @@ class DefaultStyle:
priority = 0 # the lowest priority style
def apply(self, mailing_list):
+ # For cut-n-paste convenience.
+ mlist = mailing_list
# Most of these were ripped from the old MailList.InitVars() method.
mlist.volume = 1
mlist.post_id = 1
@@ -248,12 +250,14 @@ class StyleManager:
matched_styles = []
for style in self.styles:
style.match(mailing_list, matched_styles)
- for style in sorted(matched_styles, key=attrgetter('priority')):
+ for style in matched_styles:
yield style
@property
def styles(self):
- for style in sorted(self._styles.values(), key=attrgetter('priority')):
+ for style in sorted(self._styles.values(),
+ key=attrgetter('priority'),
+ reverse=True):
yield style
def register(self, style):
diff --git a/Mailman/docs/styles.txt b/Mailman/docs/styles.txt
new file mode 100644
index 000000000..f5d9a807b
--- /dev/null
+++ b/Mailman/docs/styles.txt
@@ -0,0 +1,142 @@
+List styles
+===========
+
+List styles are a way to name and apply a canned collection of attribute
+settings. Every style has a name, which must be unique within the context of
+a specific style manager. There is usually only one global style manager.
+
+Styles also have a priority, which allows you to specify the order in which
+multiple styles will be applied. A style has a `match` function which is used
+to determine whether the style should be applied to a particular mailing list
+or not. And finally, application of a style to a mailing list can really
+modify the mailing list any way it wants.
+
+Let's start with a vanilla mailing list and a default style manager.
+
+ >>> from Mailman.configuration import config
+ >>> from Mailman.database import flush
+ >>> mlist = config.db.list_manager.create('_xtest@example.com')
+ >>> from Mailman.app.styles import style_manager
+
+
+The default style
+-----------------
+
+There is a default style which implements the legacy application of list
+defaults from Defaults.py. This style only matching a mailing list when no
+other styles match, and it has the lowest priority. The low priority means
+that it is matched last and if it matches, it is applied last.
+
+ >>> default_style = style_manager.get('default')
+ >>> default_style.name
+ 'default'
+ >>> default_style.priority
+ 0
+ >>> sorted(style.name for style in style_manager.styles)
+ ['default']
+
+Given a mailing list, you can ask the style manager to find all the styles
+that match the list. The registered styles will be sorted by decreasing
+priority and each style's `match()` method will be called in turn. The sorted
+list of matching styles will be returned -- but not applied -- by the style
+manager's `lookup()` method.
+
+ >>> [style.name for style in style_manager.lookup(mlist)]
+ ['default']
+
+If the site administrator modified their mailman.cfg file, the default style
+would pick this up and apply it to the mailing list.
+
+ >>> print mlist.msg_footer
+ None
+ >>> config.DEFAULT_MSG_FOOTER = u'default footer'
+ >>> default_style.apply(mlist)
+ >>> flush()
+ >>> mlist.msg_footer
+ u'default footer'
+
+
+Registering styles
+------------------
+
+New styles must implement the IStyle interface.
+
+ >>> from zope.interface import implements
+ >>> from Mailman.interfaces import IStyle
+ >>> class TestStyle(object):
+ ... name = 'test'
+ ... priority = 10
+ ... def apply(self, mailing_list):
+ ... # Just does something very simple.
+ ... mailing_list.msg_footer = u'test footer'
+ ... def match(self, mailing_list, styles):
+ ... # Applies to any test list
+ ... if 'test' in mailing_list.fqdn_listname:
+ ... styles.append(self)
+
+You can register a new style with the style manager.
+
+ >>> style_manager.register(TestStyle())
+
+And now if you lookup matching styles, you should find only the new test
+style. This is because the default style only gets applied when no other
+styles match the mailing list.
+
+ >>> sorted(style.name for style in style_manager.lookup(mlist))
+ ['test']
+ >>> for style in style_manager.lookup(mlist):
+ ... style.apply(mlist)
+ >>> flush()
+ >>> mlist.msg_footer
+ u'test footer'
+
+
+Style priority
+--------------
+
+When multiple styles match a particular mailing list, they are applied in
+descending order of priority. In other words, a priority zero style would be
+applied last.
+
+ >>> class AnotherTestStyle(TestStyle):
+ ... name = 'another'
+ ... priority = 5
+ ... # Use the base class's match() method.
+ ... def apply(self, mailing_list):
+ ... mailing_list.msg_footer = u'another footer'
+
+ >>> mlist.msg_footer = u''
+ >>> flush()
+ >>> mlist.msg_footer
+ u''
+ >>> style_manager.register(AnotherTestStyle())
+ >>> for style in style_manager.lookup(mlist):
+ ... style.apply(mlist)
+ >>> flush()
+ >>> mlist.msg_footer
+ u'another footer'
+
+You can change the priority of a style, and if you reapply the styles, they
+will take effect in the new priority order.
+
+ >>> style_1 = style_manager.get('test')
+ >>> style_1.priority = 5
+ >>> style_2 = style_manager.get('another')
+ >>> style_2.priority = 10
+ >>> for style in style_manager.lookup(mlist):
+ ... style.apply(mlist)
+ >>> flush()
+ >>> mlist.msg_footer
+ u'test footer'
+
+
+Corner cases
+------------
+
+If you register a style with the same name as an already registered style, you
+get an exception.
+
+ >>> style_manager.register(AnotherTestStyle())
+ Traceback (most recent call last):
+ ...
+ DuplicateStyleError: another