summaryrefslogtreecommitdiff
path: root/src/mailman/chains
diff options
context:
space:
mode:
authorBarry Warsaw2016-03-24 10:16:21 -0400
committerBarry Warsaw2016-03-24 10:16:21 -0400
commit8cc7e77b85f013d6f9ea4cda16ae18856fd6ccee (patch)
tree0ae6c01bf71492fe6b8e65e0576132a7a4986a71 /src/mailman/chains
parentce9370a537683e6e4e934b8018d0fe3f2aa7f9ac (diff)
downloadmailman-8cc7e77b85f013d6f9ea4cda16ae18856fd6ccee.tar.gz
mailman-8cc7e77b85f013d6f9ea4cda16ae18856fd6ccee.tar.zst
mailman-8cc7e77b85f013d6f9ea4cda16ae18856fd6ccee.zip
Diffstat (limited to 'src/mailman/chains')
-rw-r--r--src/mailman/chains/accept.py8
-rw-r--r--src/mailman/chains/base.py12
-rw-r--r--src/mailman/chains/builtin.py8
-rw-r--r--src/mailman/chains/discard.py8
-rw-r--r--src/mailman/chains/headers.py7
-rw-r--r--src/mailman/chains/hold.py25
-rw-r--r--src/mailman/chains/moderation.py8
-rw-r--r--src/mailman/chains/owner.py8
-rw-r--r--src/mailman/chains/reject.py12
-rw-r--r--src/mailman/chains/tests/test_accept.py8
-rw-r--r--src/mailman/chains/tests/test_base.py7
-rw-r--r--src/mailman/chains/tests/test_headers.py17
-rw-r--r--src/mailman/chains/tests/test_hold.py24
-rw-r--r--src/mailman/chains/tests/test_owner.py17
-rw-r--r--src/mailman/chains/tests/test_reject.py12
15 files changed, 50 insertions, 131 deletions
diff --git a/src/mailman/chains/accept.py b/src/mailman/chains/accept.py
index d533fba23..8b0a0507e 100644
--- a/src/mailman/chains/accept.py
+++ b/src/mailman/chains/accept.py
@@ -17,13 +17,9 @@
"""The terminal 'accept' chain."""
-__all__ = [
- 'AcceptChain',
- ]
-
-
import logging
+from mailman import public
from mailman.chains.base import TerminalChainBase
from mailman.config import config
from mailman.core.i18n import _
@@ -35,7 +31,7 @@ log = logging.getLogger('mailman.vette')
SEMISPACE = '; '
-
+@public
class AcceptChain(TerminalChainBase):
"""Accept the message for posting."""
diff --git a/src/mailman/chains/base.py b/src/mailman/chains/base.py
index f6c0db2f5..677ec501c 100644
--- a/src/mailman/chains/base.py
+++ b/src/mailman/chains/base.py
@@ -17,13 +17,7 @@
"""Base class for terminal chains."""
-__all__ = [
- 'Chain',
- 'Link',
- 'TerminalChainBase',
- ]
-
-
+from mailman import public
from mailman.config import config
from mailman.interfaces.chain import (
IChain, IChainIterator, IChainLink, IMutableChain, LinkAction)
@@ -31,6 +25,7 @@ from mailman.interfaces.rules import IRule
from zope.interface import implementer
+@public
@implementer(IChainLink)
class Link:
"""A chain link."""
@@ -59,6 +54,7 @@ class Link:
return message.format(self)
+@public
@implementer(IChain, IChainIterator)
class TerminalChainBase:
"""A base chain that always matches and executes a method.
@@ -88,6 +84,7 @@ class TerminalChainBase:
yield Link('truth', LinkAction.stop)
+@public
@implementer(IMutableChain)
class Chain:
"""Generic chain base class."""
@@ -118,6 +115,7 @@ class Chain:
yield from self._links
+@public
@implementer(IChainIterator)
class ChainIterator:
"""Generic chain iterator."""
diff --git a/src/mailman/chains/builtin.py b/src/mailman/chains/builtin.py
index 375d83fa4..f3ff501be 100644
--- a/src/mailman/chains/builtin.py
+++ b/src/mailman/chains/builtin.py
@@ -17,13 +17,9 @@
"""The default built-in starting chain."""
-__all__ = [
- 'BuiltInChain',
- ]
-
-
import logging
+from mailman import public
from mailman.chains.base import Link
from mailman.core.i18n import _
from mailman.interfaces.chain import IChain, LinkAction
@@ -33,7 +29,7 @@ from zope.interface import implementer
log = logging.getLogger('mailman.vette')
-
+@public
@implementer(IChain)
class BuiltInChain:
"""Default built-in chain."""
diff --git a/src/mailman/chains/discard.py b/src/mailman/chains/discard.py
index 5ce73c60e..f77c7eb0f 100644
--- a/src/mailman/chains/discard.py
+++ b/src/mailman/chains/discard.py
@@ -17,13 +17,9 @@
"""The terminal 'discard' chain."""
-__all__ = [
- 'DiscardChain',
- ]
-
-
import logging
+from mailman import public
from mailman.chains.base import TerminalChainBase
from mailman.core.i18n import _
from mailman.interfaces.chain import DiscardEvent
@@ -33,7 +29,7 @@ from zope.event import notify
log = logging.getLogger('mailman.vette')
-
+@public
class DiscardChain(TerminalChainBase):
"""Discard a message."""
diff --git a/src/mailman/chains/headers.py b/src/mailman/chains/headers.py
index f14ec754f..3e6d4bfaa 100644
--- a/src/mailman/chains/headers.py
+++ b/src/mailman/chains/headers.py
@@ -17,14 +17,10 @@
"""The header-matching chain."""
-__all__ = [
- 'HeaderMatchChain',
- ]
-
-
import re
import logging
+from mailman import public
from mailman.chains.base import Chain, Link
from mailman.config import config
from mailman.core.i18n import _
@@ -94,6 +90,7 @@ class HeaderMatchRule:
return False
+@public
class HeaderMatchChain(Chain):
"""Default header matching chain.
diff --git a/src/mailman/chains/hold.py b/src/mailman/chains/hold.py
index d83d3571b..329bbc71b 100644
--- a/src/mailman/chains/hold.py
+++ b/src/mailman/chains/hold.py
@@ -17,16 +17,12 @@
"""The terminal 'hold' chain."""
-__all__ = [
- 'HoldChain',
- ]
-
-
import logging
from email.mime.message import MIMEMessage
from email.mime.text import MIMEText
from email.utils import formatdate, make_msgid
+from mailman import public
from mailman.app.moderator import hold_message
from mailman.app.replybot import can_acknowledge
from mailman.chains.base import TerminalChainBase
@@ -52,13 +48,11 @@ NL = '\n'
log = logging.getLogger('mailman.vette')
-
@implementer(IPendable)
class HeldMessagePendable(dict):
PEND_TYPE = 'held message'
-
def _compose_reasons(msgdata, column=66):
# Rules can add reasons to the metadata.
reasons = msgdata.get('moderation_reasons', [_('N/A')])
@@ -67,7 +61,6 @@ def _compose_reasons(msgdata, column=66):
for reason in reasons])
-
def autorespond_to_sender(mlist, sender, language=None):
"""Should Mailman automatically respond to this sender?
@@ -127,7 +120,7 @@ def autorespond_to_sender(mlist, sender, language=None):
return False
-
+@public
class HoldChain(TerminalChainBase):
"""Hold a message."""
@@ -170,10 +163,10 @@ class HoldChain(TerminalChainBase):
bytes_subject = oneline_subject.encode(charset, 'replace')
original_subject = bytes_subject.decode(charset)
substitutions = dict(
- listname = mlist.fqdn_listname,
- subject = original_subject,
- sender = msg.sender,
- reasons = _compose_reasons(msgdata),
+ listname = mlist.fqdn_listname, # flake8: noqa
+ subject = original_subject, # flake8: noqa
+ sender = msg.sender, # flake8: noqa
+ reasons = _compose_reasons(msgdata), # flake8: noqa
)
# At this point the message is held, but now we have to craft at least
# two responses. The first will go to the original author of the
@@ -190,9 +183,9 @@ class HoldChain(TerminalChainBase):
# mailing list, or the author (if they are a member) have been
# configured to not send such responses.
if (not msgdata.get('fromusenet') and
- can_acknowledge(msg) and
- mlist.respond_to_post_requests and
- autorespond_to_sender(mlist, msg.sender, language)):
+ can_acknowledge(msg) and
+ mlist.respond_to_post_requests and
+ autorespond_to_sender(mlist, msg.sender, language)):
# We can respond to the sender with a message indicating their
# posting was held.
subject = _(
diff --git a/src/mailman/chains/moderation.py b/src/mailman/chains/moderation.py
index fd0bbcfcd..9bb4bf0d5 100644
--- a/src/mailman/chains/moderation.py
+++ b/src/mailman/chains/moderation.py
@@ -34,11 +34,7 @@ made as to the disposition of the message. `defer` is the default for
members, while `hold` is the default for nonmembers.
"""
-__all__ = [
- 'ModerationChain',
- ]
-
-
+from mailman import public
from mailman.chains.base import Link
from mailman.core.i18n import _
from mailman.interfaces.action import Action
@@ -46,7 +42,7 @@ from mailman.interfaces.chain import IChain, LinkAction
from zope.interface import implementer
-
+@public
@implementer(IChain)
class ModerationChain:
"""Dynamically produce a link jumping to the appropriate terminal chain.
diff --git a/src/mailman/chains/owner.py b/src/mailman/chains/owner.py
index 8447a10ba..f7454435f 100644
--- a/src/mailman/chains/owner.py
+++ b/src/mailman/chains/owner.py
@@ -17,13 +17,9 @@
"""The standard -owner posting chain."""
-__all__ = [
- 'BuiltInOwnerChain',
- ]
-
-
import logging
+from mailman import public
from mailman.chains.base import TerminalChainBase
from mailman.config import config
from mailman.core.i18n import _
@@ -34,7 +30,7 @@ from zope.event import notify
log = logging.getLogger('mailman.vette')
-
+@public
class BuiltInOwnerChain(TerminalChainBase):
"""Default built-in -owner address chain."""
diff --git a/src/mailman/chains/reject.py b/src/mailman/chains/reject.py
index d6ebd0bde..657e788af 100644
--- a/src/mailman/chains/reject.py
+++ b/src/mailman/chains/reject.py
@@ -17,13 +17,9 @@
"""The terminal 'reject' chain."""
-__all__ = [
- 'RejectChain',
- ]
-
-
import logging
+from mailman import public
from mailman.app.bounces import bounce_message
from mailman.chains.base import TerminalChainBase
from mailman.core.errors import RejectMessage
@@ -38,7 +34,7 @@ NEWLINE = '\n'
SEMISPACE = '; '
-
+@public
class RejectChain(TerminalChainBase):
"""Reject/bounce a message."""
@@ -68,8 +64,8 @@ reasons:
The original message as received by Mailman is attached.
""").format(
- list_name=mlist.display_name,
- reasons=NEWLINE.join(reasons)
+ list_name=mlist.display_name, # flake8: noqa
+ reasons=NEWLINE.join(reasons) # flake8: noqa
))
bounce_message(mlist, msg, error)
log.info('REJECT: %s', msg.get('message-id', 'n/a'))
diff --git a/src/mailman/chains/tests/test_accept.py b/src/mailman/chains/tests/test_accept.py
index 62370021d..661ad2146 100644
--- a/src/mailman/chains/tests/test_accept.py
+++ b/src/mailman/chains/tests/test_accept.py
@@ -17,11 +17,6 @@
"""Test the accept chain."""
-__all__ = [
- 'TestAccept',
- ]
-
-
import unittest
from mailman.app.lifecycle import create_list
@@ -47,7 +42,6 @@ class MyChain:
yield Link('truth', LinkAction.jump, 'accept')
-
class TestAccept(unittest.TestCase):
"""Test the accept chain."""
@@ -66,7 +60,7 @@ Subject: Ignore
config.chains['mine'] = MyChain()
self.addCleanup(config.chains.pop, 'mine')
hits = None
- def handler(event):
+ def handler(event): # flake8: noqa
nonlocal hits
if isinstance(event, AcceptEvent):
hits = event.msg['x-mailman-rule-hits']
diff --git a/src/mailman/chains/tests/test_base.py b/src/mailman/chains/tests/test_base.py
index 86a09678d..a9c07c7ab 100644
--- a/src/mailman/chains/tests/test_base.py
+++ b/src/mailman/chains/tests/test_base.py
@@ -17,12 +17,6 @@
"""Test the base chain stuff."""
-__all__ = [
- 'TestMiscellaneous',
- 'TestTerminalChainBase',
- ]
-
-
import unittest
from mailman.chains.accept import AcceptChain
@@ -37,7 +31,6 @@ class SimpleChain(TerminalChainBase):
pass
-
class TestMiscellaneous(unittest.TestCase):
"""Reach additional code coverage."""
diff --git a/src/mailman/chains/tests/test_headers.py b/src/mailman/chains/tests/test_headers.py
index 11b00f7ba..b3ccdf675 100644
--- a/src/mailman/chains/tests/test_headers.py
+++ b/src/mailman/chains/tests/test_headers.py
@@ -17,11 +17,6 @@
"""Test the header chain."""
-__all__ = [
- 'TestHeaderChain',
- ]
-
-
import unittest
from mailman.app.lifecycle import create_list
@@ -173,7 +168,7 @@ class TestHeaderChain(unittest.TestCase):
[('foo', 'a+', LinkAction.jump, 'reject'),
('bar', 'b+', LinkAction.jump, 'discard'),
('baz', 'z+', LinkAction.jump, 'accept'),
- ])
+ ]) # flake8: noqa
@configuration('antispam', header_checks="""
Foo: foo
@@ -202,7 +197,7 @@ A message body.
self.assertEqual(len(events), 1)
event = events[0]
# Site-wide wants to hold the message, the list wants to accept it.
- self.assertTrue(isinstance(event, HoldEvent))
+ self.assertIsInstance(event, HoldEvent)
self.assertEqual(event.chain, config.chains['hold'])
def test_no_action_defaults_to_site_wide_action(self):
@@ -223,7 +218,7 @@ A message body.
# This event subscriber records the event that occurs when the message
# is processed by the owner chain, which holds its for approval.
events = []
- def record_holds(event):
+ def record_holds(event): # flake8: noqa
if not isinstance(event, HoldEvent):
return
events.append(event)
@@ -231,7 +226,7 @@ A message body.
# Set the site-wide antispam action to hold the message.
with configuration('antispam', header_checks="""
Spam: [*]{3,}
- """, jump_chain='hold'):
+ """, jump_chain='hold'): # flake8: noqa
process(self._mlist, msg, {}, start_chain='header-match')
self.assertEqual(len(events), 1)
event = events[0]
@@ -240,7 +235,7 @@ A message body.
self.assertEqual(event.mlist, self._mlist)
self.assertEqual(event.msg, msg)
events = []
- def record_discards(event):
+ def record_discards(event): # flake8: noqa
if not isinstance(event, DiscardEvent):
return
events.append(event)
@@ -249,7 +244,7 @@ A message body.
msg.replace_header('Message-Id', '<bee>')
with configuration('antispam', header_checks="""
Spam: [*]{3,}
- """, jump_chain='discard'):
+ """, jump_chain='discard'): # flake8: noqa
process(self._mlist, msg, {}, start_chain='header-match')
self.assertEqual(len(events), 1)
event = events[0]
diff --git a/src/mailman/chains/tests/test_hold.py b/src/mailman/chains/tests/test_hold.py
index c7b676f8b..0957fe880 100644
--- a/src/mailman/chains/tests/test_hold.py
+++ b/src/mailman/chains/tests/test_hold.py
@@ -17,12 +17,6 @@
"""Additional tests for the hold chain."""
-__all__ = [
- 'TestAutorespond',
- 'TestHoldChain',
- ]
-
-
import unittest
from email import message_from_bytes as mfb
@@ -40,16 +34,14 @@ from pkg_resources import resource_filename
from zope.component import getUtility
-
class TestAutorespond(unittest.TestCase):
"""Test autorespond_to_sender()"""
layer = ConfigLayer
+ maxDiff = None
def setUp(self):
self._mlist = create_list('test@example.com')
- # Let assertMultiLineEqual work without bounds.
- self.maxDiff = None
@configuration('mta', max_autoresponses_per_day=1)
def test_max_autoresponses_per_day(self):
@@ -70,9 +62,9 @@ class TestAutorespond(unittest.TestCase):
self.assertEqual(len(messages), 1)
# Remove the variable headers.
message = messages[0].msg
- self.assertTrue('message-id' in message)
+ self.assertIn('message-id', message)
del message['message-id']
- self.assertTrue('date' in message)
+ self.assertIn('date', message)
del message['date']
self.assertMultiLineEqual(messages[0].msg.as_string(), """\
MIME-Version: 1.0
@@ -95,7 +87,6 @@ If you believe this message is in error, or if you have any questions,
please contact the list owner at test-owner@example.com.""")
-
class TestHoldChain(unittest.TestCase):
"""Test the hold chain code."""
@@ -120,8 +111,7 @@ A message body.
])
logfile = LogFileMark('mailman.vette')
process_chain(self._mlist, msg, msgdata, start_chain='hold')
- messages = get_queue_messages('virgin')
- self.assertEqual(len(messages), 2)
+ messages = get_queue_messages('virgin', expected_count=2)
payloads = {}
for item in messages:
if item.msg['to'] == 'test-owner@example.com':
@@ -150,8 +140,7 @@ A message body.
process_chain(self._mlist, msg, {}, start_chain='hold')
# The postauth.txt message is now in the virgin queue awaiting
# delivery to the moderators.
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('virgin', expected_count=1)
msgdata = items[0].msgdata
self.assertTrue(msgdata['tomoderators'])
self.assertEqual(msgdata['recipients'], {'test-owner@example.com'})
@@ -180,11 +169,10 @@ A message body.
""")
process_chain(self._mlist, msg, {}, start_chain='hold')
process_chain(mlist2, msg, {}, start_chain='hold')
- items = get_queue_messages('virgin')
# There are four items in the virgin queue. Two of them are for the
# list owners who need to moderate the held message, and the other is
# for anne telling her that her message was held for approval.
- self.assertEqual(len(items), 4)
+ items = get_queue_messages('virgin', expected_count=4)
anne_froms = set()
owner_tos = set()
for item in items:
diff --git a/src/mailman/chains/tests/test_owner.py b/src/mailman/chains/tests/test_owner.py
index cf9c06f94..06ba10582 100644
--- a/src/mailman/chains/tests/test_owner.py
+++ b/src/mailman/chains/tests/test_owner.py
@@ -17,11 +17,6 @@
"""Test the owner chain."""
-__all__ = [
- 'TestOwnerChain',
- ]
-
-
import unittest
from mailman.app.lifecycle import create_list
@@ -34,7 +29,6 @@ from mailman.testing.helpers import (
from mailman.testing.layers import ConfigLayer
-
class TestOwnerChain(unittest.TestCase):
"""Test the owner chain."""
@@ -56,18 +50,17 @@ Message-ID: <ant>
# This event subscriber records the event that occurs when the message
# is processed by the owner chain.
events = []
- def catch_event(event):
+ def catch_event(event): # flake8: noqa
if isinstance(event, AcceptOwnerEvent):
events.append(event)
with event_subscribers(catch_event):
process(self._mlist, self._msg, {}, 'default-owner-chain')
self.assertEqual(len(events), 1)
event = events[0]
- self.assertTrue(isinstance(event, AcceptOwnerEvent))
+ self.assertIsInstance(event, AcceptOwnerEvent)
self.assertEqual(event.mlist, self._mlist)
self.assertEqual(event.msg['message-id'], '<ant>')
- self.assertTrue(isinstance(event.chain, BuiltInOwnerChain))
- messages = get_queue_messages('pipeline')
- self.assertEqual(len(messages), 1)
- message = messages[0].msg
+ self.assertIsInstance(event.chain, BuiltInOwnerChain)
+ items = get_queue_messages('pipeline', expected_count=1)
+ message = items[0].msg
self.assertEqual(message['message-id'], '<ant>')
diff --git a/src/mailman/chains/tests/test_reject.py b/src/mailman/chains/tests/test_reject.py
index ae83d63bf..a645a849c 100644
--- a/src/mailman/chains/tests/test_reject.py
+++ b/src/mailman/chains/tests/test_reject.py
@@ -17,11 +17,6 @@
"""Test the reject chain."""
-__all__ = [
- 'TestReject',
- ]
-
-
import unittest
from mailman.app.lifecycle import create_list
@@ -31,7 +26,6 @@ from mailman.testing.helpers import (
from mailman.testing.layers import ConfigLayer
-
class TestReject(unittest.TestCase):
"""Test the reject chain."""
@@ -53,8 +47,7 @@ Subject: Ignore
'TEST-REASON-2',
])
process_chain(self._mlist, self._msg, msgdata, start_chain='reject')
- bounces = get_queue_messages('virgin')
- self.assertEqual(len(bounces), 1)
+ bounces = get_queue_messages('virgin', expected_count=1)
payload = bounces[0].msg.get_payload(0).as_string()
self.assertIn('TEST-REASON-1', payload)
self.assertIn('TEST-REASON-2', payload)
@@ -62,7 +55,6 @@ Subject: Ignore
def test_no_reason(self):
# There may be no moderation reasons.
process_chain(self._mlist, self._msg, {}, start_chain='reject')
- bounces = get_queue_messages('virgin')
- self.assertEqual(len(bounces), 1)
+ bounces = get_queue_messages('virgin', expected_count=1)
payload = bounces[0].msg.get_payload(0).as_string()
self.assertIn('No bounce details are available', payload)