summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Mailman/app/rules.py4
-rw-r--r--Mailman/interfaces/rules.py21
-rw-r--r--Mailman/rules/__init__.py6
-rw-r--r--Mailman/rules/administrivia.py7
-rw-r--r--Mailman/rules/approved.py6
-rw-r--r--Mailman/rules/docs/administrivia.txt (renamed from Mailman/docs/administrivia.txt)0
-rw-r--r--Mailman/rules/docs/approve.txt (renamed from Mailman/docs/approve.txt)0
-rw-r--r--Mailman/rules/docs/implicit-dest.txt (renamed from Mailman/docs/implicit-dest.txt)0
-rw-r--r--Mailman/rules/docs/loop.txt (renamed from Mailman/docs/loop.txt)0
-rw-r--r--Mailman/rules/docs/max-size.txt (renamed from Mailman/docs/max-size.txt)0
-rw-r--r--Mailman/rules/docs/moderation.txt (renamed from Mailman/docs/moderation.txt)0
-rw-r--r--Mailman/rules/docs/news-moderation.txt (renamed from Mailman/docs/news-moderation.txt)0
-rw-r--r--Mailman/rules/docs/no-subject.txt (renamed from Mailman/docs/no-subject.txt)0
-rw-r--r--Mailman/rules/docs/recipients.txt (renamed from Mailman/docs/recipients.txt)0
-rw-r--r--Mailman/rules/docs/rules.txt (renamed from Mailman/docs/rules.txt)3
-rw-r--r--Mailman/rules/docs/suspicious.txt (renamed from Mailman/docs/suspicious.txt)0
-rw-r--r--Mailman/rules/emergency.py5
-rw-r--r--Mailman/rules/implicit_dest.py6
-rw-r--r--Mailman/rules/loop.py6
-rw-r--r--Mailman/rules/max_recipients.py6
-rw-r--r--Mailman/rules/max_size.py6
-rw-r--r--Mailman/rules/moderation.py9
-rw-r--r--Mailman/rules/news_moderation.py (renamed from Mailman/rules/new_moderation.py)6
-rw-r--r--Mailman/rules/no_subject.py6
-rw-r--r--Mailman/rules/suspicious.py6
-rw-r--r--Mailman/tests/test_documentation.py28
26 files changed, 57 insertions, 74 deletions
diff --git a/Mailman/app/rules.py b/Mailman/app/rules.py
index 37f5d9af4..e4c3c8c40 100644
--- a/Mailman/app/rules.py
+++ b/Mailman/app/rules.py
@@ -45,7 +45,7 @@ def process(mlist, msg, msgdata, rule_set=None):
# Now process all rules, returning the set of rules that match.
rule_matches = set()
for rule in rules:
- if rule.check(mlist, msg, msgdata):
+ if rule().check(mlist, msg, msgdata):
rule_matches.add(rule.name)
return rule_matches
@@ -60,5 +60,5 @@ def find_rule(rule_name):
for rule_set_class in get_plugins('mailman.rules'):
rule = rule_set_class().get(rule_name)
if rule is not None:
- return rule
+ return rule()
return None
diff --git a/Mailman/interfaces/rules.py b/Mailman/interfaces/rules.py
index 13edcf481..c023acf6b 100644
--- a/Mailman/interfaces/rules.py
+++ b/Mailman/interfaces/rules.py
@@ -17,10 +17,25 @@
"""Interface describing the basics of rules."""
+from munepy import Enum
from zope.interface import Interface, Attribute
+class ChainJump(Enum):
+ # Allow the next rule in the chain to be run.
+ defer = 0
+ # Jump to the 'accept' chain.
+ accept = 1
+ # Jump to the 'hold' chain.
+ hold = 2
+ # Jump to the 'reject' chain.
+ reject = 3
+ # Jump to the 'discard' chain.
+ discard = 4
+
+
+
class DuplicateRuleError(Exception):
"""A rule or rule name is added to a processor more than once."""
@@ -35,10 +50,14 @@ class IRule(Interface):
def check(mlist, msg, msgdata):
"""Run the rule.
+ The effects of running the rule can be as simple as appending the rule
+ name to `msgdata['rules']` when the rule matches. The rule is allowed
+ to do other things, such as modify the message or metadata.
+
:param mlist: The mailing list object.
:param msg: The message object.
:param msgdata: The message metadata.
- :return: A boolean specifying whether the rule was matched or not.
+ :return: A chain to jump to, i.e. an ChainJump enum.
"""
diff --git a/Mailman/rules/__init__.py b/Mailman/rules/__init__.py
index 2d2f5d0a8..2a1e2ec2b 100644
--- a/Mailman/rules/__init__.py
+++ b/Mailman/rules/__init__.py
@@ -44,11 +44,11 @@ class BuiltinRules:
if extension <> '.py':
continue
module_name = mypackage + '.' + basename
- __import__(module_name)
+ __import__(module_name, fromlist='*')
module = sys.modules[module_name]
- for name in dir(module):
+ for name in module.__all__:
rule = getattr(module, name)
- if IRule.providedBy(rule):
+ if IRule.implementedBy(rule):
if rule.name in self._rules or rule in rule_set:
raise DuplicateRuleError(rule.name)
self._rules[rule.name] = rule
diff --git a/Mailman/rules/administrivia.py b/Mailman/rules/administrivia.py
index 422503c71..589c4a56b 100644
--- a/Mailman/rules/administrivia.py
+++ b/Mailman/rules/administrivia.py
@@ -17,7 +17,7 @@
"""The administrivia rule."""
-__all__ = ['administrivia_rule']
+__all__ = ['Administrivia']
__metaclass__ = type
@@ -95,8 +95,3 @@ class Administrivia:
if minargs <= len(words) - 1 <= maxargs:
return True
return False
-
-
-
-administrivia_rule = Administrivia()
-
diff --git a/Mailman/rules/approved.py b/Mailman/rules/approved.py
index b9b041c2e..98b158dd9 100644
--- a/Mailman/rules/approved.py
+++ b/Mailman/rules/approved.py
@@ -17,7 +17,7 @@
"""Look for moderator pre-approval."""
-__all__ = ['approve_rule']
+__all__ = ['Approved']
__metaclass__ = type
@@ -114,7 +114,3 @@ def reset_payload(part, payload):
part.set_param('Format', format)
if delsp:
part.set_param('DelSp', delsp)
-
-
-
-approve_rule = Approved()
diff --git a/Mailman/docs/administrivia.txt b/Mailman/rules/docs/administrivia.txt
index 0e48fdd1b..0e48fdd1b 100644
--- a/Mailman/docs/administrivia.txt
+++ b/Mailman/rules/docs/administrivia.txt
diff --git a/Mailman/docs/approve.txt b/Mailman/rules/docs/approve.txt
index ea07058f8..ea07058f8 100644
--- a/Mailman/docs/approve.txt
+++ b/Mailman/rules/docs/approve.txt
diff --git a/Mailman/docs/implicit-dest.txt b/Mailman/rules/docs/implicit-dest.txt
index b6fed2769..b6fed2769 100644
--- a/Mailman/docs/implicit-dest.txt
+++ b/Mailman/rules/docs/implicit-dest.txt
diff --git a/Mailman/docs/loop.txt b/Mailman/rules/docs/loop.txt
index 3174805b9..3174805b9 100644
--- a/Mailman/docs/loop.txt
+++ b/Mailman/rules/docs/loop.txt
diff --git a/Mailman/docs/max-size.txt b/Mailman/rules/docs/max-size.txt
index b477ecd2b..b477ecd2b 100644
--- a/Mailman/docs/max-size.txt
+++ b/Mailman/rules/docs/max-size.txt
diff --git a/Mailman/docs/moderation.txt b/Mailman/rules/docs/moderation.txt
index 0ce6bee6e..0ce6bee6e 100644
--- a/Mailman/docs/moderation.txt
+++ b/Mailman/rules/docs/moderation.txt
diff --git a/Mailman/docs/news-moderation.txt b/Mailman/rules/docs/news-moderation.txt
index f69fbb33d..f69fbb33d 100644
--- a/Mailman/docs/news-moderation.txt
+++ b/Mailman/rules/docs/news-moderation.txt
diff --git a/Mailman/docs/no-subject.txt b/Mailman/rules/docs/no-subject.txt
index 3c6dc88bf..3c6dc88bf 100644
--- a/Mailman/docs/no-subject.txt
+++ b/Mailman/rules/docs/no-subject.txt
diff --git a/Mailman/docs/recipients.txt b/Mailman/rules/docs/recipients.txt
index 98176c8bb..98176c8bb 100644
--- a/Mailman/docs/recipients.txt
+++ b/Mailman/rules/docs/recipients.txt
diff --git a/Mailman/docs/rules.txt b/Mailman/rules/docs/rules.txt
index dbf009eeb..4e5db7012 100644
--- a/Mailman/docs/rules.txt
+++ b/Mailman/rules/docs/rules.txt
@@ -32,6 +32,7 @@ You can iterator over all the rules in a rule set.
>>> rule = None
>>> for rule in rule_set.rules:
... if rule.name == 'emergency':
+ ... rule = rule()
... break
>>> verifyObject(IRule, rule)
True
@@ -80,7 +81,7 @@ For example, the emergency rule just checks to see if the emergency flag is
set on the mailing list, and the message has not been pre-approved by the list
administrator.
- >>> rule = rule_set['emergency']
+ >>> rule = rule_set['emergency']()
>>> rule.name
'emergency'
>>> mlist.emergency = False
diff --git a/Mailman/docs/suspicious.txt b/Mailman/rules/docs/suspicious.txt
index 8646e1b81..8646e1b81 100644
--- a/Mailman/docs/suspicious.txt
+++ b/Mailman/rules/docs/suspicious.txt
diff --git a/Mailman/rules/emergency.py b/Mailman/rules/emergency.py
index 989e4fff7..e51612940 100644
--- a/Mailman/rules/emergency.py
+++ b/Mailman/rules/emergency.py
@@ -17,7 +17,7 @@
"""The emergency hold rule."""
-__all__ = ['emergency_rule']
+__all__ = ['Emergency']
__metaclass__ = type
@@ -40,6 +40,3 @@ the list administrator.""")
def check(self, mlist, msg, msgdata):
"""See `IRule`."""
return mlist.emergency and not msgdata.get('adminapproved')
-
-
-emergency_rule = Emergency()
diff --git a/Mailman/rules/implicit_dest.py b/Mailman/rules/implicit_dest.py
index e056a2e9e..19a096aa5 100644
--- a/Mailman/rules/implicit_dest.py
+++ b/Mailman/rules/implicit_dest.py
@@ -17,7 +17,7 @@
"""The implicit destination rule."""
-__all__ = ['implicit_dest']
+__all__ = ['ImplicitDestination']
__metaclass__ = type
@@ -92,7 +92,3 @@ class ImplicitDestination:
pass
# Nothing matched.
return True
-
-
-
-implicit_dest = ImplicitDestination()
diff --git a/Mailman/rules/loop.py b/Mailman/rules/loop.py
index 77cedb0a6..a88858d6a 100644
--- a/Mailman/rules/loop.py
+++ b/Mailman/rules/loop.py
@@ -17,7 +17,7 @@
"""Look for a posting loop."""
-__all__ = ['loop_rule']
+__all__ = ['Loop']
__metaclass__ = type
@@ -41,7 +41,3 @@ class Loop:
been_theres = [value.strip().lower()
for value in msg.get_all('x-beenthere', [])]
return mlist.posting_address in been_theres
-
-
-
-loop_rule = Loop()
diff --git a/Mailman/rules/max_recipients.py b/Mailman/rules/max_recipients.py
index 6e3451e4e..dfa23f659 100644
--- a/Mailman/rules/max_recipients.py
+++ b/Mailman/rules/max_recipients.py
@@ -17,7 +17,7 @@
"""The maximum number of recipients rule."""
-__all__ = ['max_recipients_rule']
+__all__ = ['MaximumRecipients']
__metaclass__ = type
@@ -45,7 +45,3 @@ class MaximumRecipients:
recipients = getaddresses(msg.get_all('to', []) +
msg.get_all('cc', []))
return len(recipients) >= mlist.max_num_recipients
-
-
-
-max_recipients_rule = MaximumRecipients()
diff --git a/Mailman/rules/max_size.py b/Mailman/rules/max_size.py
index 1e62b2ad8..b723fbf07 100644
--- a/Mailman/rules/max_size.py
+++ b/Mailman/rules/max_size.py
@@ -17,7 +17,7 @@
"""The maximum message size rule."""
-__all__ = ['max_size']
+__all__ = ['MaximumSize']
__metaclass__ = type
@@ -43,7 +43,3 @@ class MaximumSize:
'Message was not sized on initial parsing.')
# The maximum size is specified in 1024 bytes.
return msg.original_size / 1024.0 > mlist.max_message_size
-
-
-
-max_size = MaximumSize()
diff --git a/Mailman/rules/moderation.py b/Mailman/rules/moderation.py
index 5b0820426..9fa7cd34d 100644
--- a/Mailman/rules/moderation.py
+++ b/Mailman/rules/moderation.py
@@ -18,8 +18,8 @@
"""Membership related rules."""
__all__ = [
- 'moderation_rule',
- 'nonmember_rule',
+ 'Moderation',
+ 'NonMember',
]
__metaclass__ = type
@@ -62,8 +62,3 @@ class NonMember:
# The sender is a member of the mailing list.
return False
return True
-
-
-
-moderation_rule = Moderation()
-nonmember_rule = NonMember()
diff --git a/Mailman/rules/new_moderation.py b/Mailman/rules/news_moderation.py
index dc42dcbb7..9caf8fb4a 100644
--- a/Mailman/rules/new_moderation.py
+++ b/Mailman/rules/news_moderation.py
@@ -17,7 +17,7 @@
"""The news moderation rule."""
-__all__ = ['news_moderation']
+__all__ = ['ModeratedNewsgroup']
__metaclass__ = type
@@ -40,7 +40,3 @@ newsgroup.""")
def check(self, mlist, msg, msgdata):
"""See `IRule`."""
return mlist.news_moderation == NewsModeration.moderated
-
-
-
-news_moderation = ModeratedNewsgroup()
diff --git a/Mailman/rules/no_subject.py b/Mailman/rules/no_subject.py
index ca7cbd9d2..c36d742b8 100644
--- a/Mailman/rules/no_subject.py
+++ b/Mailman/rules/no_subject.py
@@ -17,7 +17,7 @@
"""The no-Subject header rule."""
-__all__ = ['no_subject_rule']
+__all__ = ['NoSubject']
__metaclass__ = type
@@ -39,7 +39,3 @@ class NoSubject:
"""See `IRule`."""
subject = msg.get('subject', '').strip()
return subject == ''
-
-
-
-no_subject_rule = NoSubject()
diff --git a/Mailman/rules/suspicious.py b/Mailman/rules/suspicious.py
index 6384f8b9e..0464a6336 100644
--- a/Mailman/rules/suspicious.py
+++ b/Mailman/rules/suspicious.py
@@ -17,7 +17,7 @@
"""The historical 'suspicious header' rule."""
-__all__ = ['suspicious_header']
+__all__ = ['SuspiciousHeader']
__metaclass__ = type
@@ -90,7 +90,3 @@ def has_matching_bounce_header(mlist, msg):
if cre.search(value):
return True
return False
-
-
-
-suspicious_header = SuspiciousHeader()
diff --git a/Mailman/tests/test_documentation.py b/Mailman/tests/test_documentation.py
index 36b3c7ecb..9faf1d588 100644
--- a/Mailman/tests/test_documentation.py
+++ b/Mailman/tests/test_documentation.py
@@ -31,6 +31,7 @@ from Mailman.app.styles import style_manager
from Mailman.configuration import config
+DOT = '.'
COMMASPACE = ', '
@@ -78,7 +79,12 @@ def cleaning_teardown(testobj):
def test_suite():
suite = unittest.TestSuite()
- docsdir = os.path.join(os.path.dirname(Mailman.__file__), 'docs')
+ topdir = os.path.dirname(Mailman.__file__)
+ packages = []
+ for dirpath, dirnames, filenames in os.walk(topdir):
+ if 'docs' in dirnames:
+ docsdir = os.path.join(dirpath, 'docs')[len(topdir)+1:]
+ packages.append(docsdir)
# Under higher verbosity settings, report all doctest errors, not just the
# first one.
flags = (doctest.ELLIPSIS |
@@ -86,13 +92,15 @@ def test_suite():
doctest.REPORT_NDIFF)
if config.opts.verbosity <= 2:
flags |= doctest.REPORT_ONLY_FIRST_FAILURE
- for filename in os.listdir(docsdir):
- if os.path.splitext(filename)[1] == '.txt':
- test = doctest.DocFileSuite(
- 'docs/' + filename,
- package=Mailman,
- optionflags=flags,
- setUp=setup,
- tearDown=cleaning_teardown)
- suite.addTest(test)
+ # Add all the doctests in all subpackages.
+ for docsdir in packages:
+ for filename in os.listdir(os.path.join('Mailman', docsdir)):
+ if os.path.splitext(filename)[1] == '.txt':
+ test = doctest.DocFileSuite(
+ os.path.join(docsdir, filename),
+ package='Mailman',
+ optionflags=flags,
+ setUp=setup,
+ tearDown=cleaning_teardown)
+ suite.addTest(test)
return suite