summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2008-01-01 13:49:27 -0500
committerBarry Warsaw2008-01-01 13:49:27 -0500
commitadae635a4ca147937019fdd91aebd95a2769b9ca (patch)
tree7cdae81b4b7715781e889f32bbd0dbba80609367
parent5b4bb22feca4d520afef44d1c472807e020d17b5 (diff)
downloadmailman-adae635a4ca147937019fdd91aebd95a2769b9ca.tar.gz
mailman-adae635a4ca147937019fdd91aebd95a2769b9ca.tar.zst
mailman-adae635a4ca147937019fdd91aebd95a2769b9ca.zip
Extended test_documentation.py to be able to find doctests in subdirectories
called 'docs' anywhere under the Mailman package. Change the rule API to return rule classes not instances. Added the ChainJump enum, though this will likely change soon.
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