summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mailman/__init__.py13
-rw-r--r--src/mailman/app/bounces.py24
-rw-r--r--src/mailman/app/commands.py8
-rw-r--r--src/mailman/app/digests.py14
-rw-r--r--src/mailman/app/domain.py8
-rw-r--r--src/mailman/app/events.py8
-rw-r--r--src/mailman/app/inject.py11
-rw-r--r--src/mailman/app/lifecycle.py16
-rw-r--r--src/mailman/app/membership.py14
-rw-r--r--src/mailman/app/moderator.py25
-rw-r--r--src/mailman/app/notifications.py18
-rw-r--r--src/mailman/app/registrar.py20
-rw-r--r--src/mailman/app/replybot.py15
-rw-r--r--src/mailman/app/subscriptions.py22
-rw-r--r--src/mailman/app/templates.py9
-rw-r--r--src/mailman/app/tests/test_bounces.py91
-rw-r--r--src/mailman/app/tests/test_digests.py23
-rw-r--r--src/mailman/app/tests/test_inject.py54
-rw-r--r--src/mailman/app/tests/test_lifecycle.py6
-rw-r--r--src/mailman/app/tests/test_membership.py8
-rw-r--r--src/mailman/app/tests/test_moderation.py24
-rw-r--r--src/mailman/app/tests/test_notifications.py61
-rw-r--r--src/mailman/app/tests/test_registrar.py20
-rw-r--r--src/mailman/app/tests/test_subscriptions.py41
-rw-r--r--src/mailman/app/tests/test_templates.py12
-rw-r--r--src/mailman/app/tests/test_workflow.py6
-rw-r--r--src/mailman/app/workflow.py8
-rw-r--r--src/mailman/archiving/mailarchive.py8
-rw-r--r--src/mailman/archiving/mhonarc.py8
-rw-r--r--src/mailman/archiving/prototype.py11
-rw-r--r--src/mailman/model/address.py11
-rw-r--r--src/mailman/model/autorespond.py16
-rw-r--r--src/mailman/model/bans.py11
-rw-r--r--src/mailman/model/bounce.py9
-rw-r--r--src/mailman/model/digests.py10
-rw-r--r--src/mailman/model/domain.py13
-rw-r--r--src/mailman/model/language.py10
-rw-r--r--src/mailman/model/listmanager.py10
-rw-r--r--src/mailman/model/mailinglist.py9
-rw-r--r--src/mailman/model/member.py11
-rw-r--r--src/mailman/rules/administrivia.py10
-rw-r--r--src/mailman/rules/any.py10
-rw-r--r--src/mailman/rules/approved.py11
-rw-r--r--src/mailman/rules/emergency.py10
-rw-r--r--src/mailman/rules/implicit_dest.py10
-rw-r--r--src/mailman/rules/loop.py10
-rw-r--r--src/mailman/rules/max_recipients.py10
-rw-r--r--src/mailman/rules/max_size.py10
-rw-r--r--src/mailman/rules/moderation.py17
-rw-r--r--src/mailman/rules/news_moderation.py10
-rw-r--r--src/mailman/rules/no_subject.py10
-rw-r--r--src/mailman/rules/suspicious.py11
-rw-r--r--src/mailman/rules/tests/test_approved.py14
-rw-r--r--src/mailman/rules/tests/test_moderation.py9
-rw-r--r--src/mailman/rules/truth.py10
-rw-r--r--src/mailman/version.py6
56 files changed, 305 insertions, 579 deletions
diff --git a/src/mailman/__init__.py b/src/mailman/__init__.py
index 15ce69608..445be2b0d 100644
--- a/src/mailman/__init__.py
+++ b/src/mailman/__init__.py
@@ -41,3 +41,16 @@ if 'build_sphinx' not in sys.argv: # pragma: no cover
else:
from mailman.core.i18n import initialize
initialize()
+
+
+# I hate myself: http://bugs.python.org/issue26632
+def public(thing):
+ if isinstance(thing, str):
+ mdict = sys._getframe(1).f_globals
+ name = thing
+ else:
+ mdict = sys.modules[thing.__module__].__dict__
+ name = thing.__name__
+ dunder_all = mdict.setdefault('__all__', [])
+ dunder_all.append(name)
+ return thing
diff --git a/src/mailman/app/bounces.py b/src/mailman/app/bounces.py
index acd1a740b..977b21038 100644
--- a/src/mailman/app/bounces.py
+++ b/src/mailman/app/bounces.py
@@ -17,15 +17,6 @@
"""Application level bounce handling."""
-__all__ = [
- 'ProbeVERP',
- 'StandardVERP',
- 'bounce_message',
- 'maybe_forward',
- 'send_probe',
- ]
-
-
import re
import uuid
import logging
@@ -33,6 +24,7 @@ import logging
from email.mime.message import MIMEMessage
from email.mime.text import MIMEText
from email.utils import parseaddr
+from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.email.message import OwnerNotification, UserNotification
@@ -55,7 +47,7 @@ blog = logging.getLogger('mailman.bounce')
DOT = '.'
-
+@public
def bounce_message(mlist, msg, error=None):
"""Bounce the message back to the original author.
@@ -91,7 +83,6 @@ def bounce_message(mlist, msg, error=None):
bmsg.send(mlist)
-
class _BaseVERPParser:
"""Base class for parsing VERP messages.
@@ -143,7 +134,7 @@ class _BaseVERPParser:
return verp_matches
-
+@public
class StandardVERP(_BaseVERPParser):
def __init__(self):
super().__init__(config.mta.verp_regexp)
@@ -152,6 +143,7 @@ class StandardVERP(_BaseVERPParser):
return '{0}@{1}'.format(*match_object.group('local', 'domain'))
+@public
class ProbeVERP(_BaseVERPParser):
def __init__(self):
super().__init__(config.mta.verp_probe_regexp)
@@ -172,13 +164,13 @@ class ProbeVERP(_BaseVERPParser):
return member.address.email
-
@implementer(IPendable)
class _ProbePendable(dict):
"""The pendable dictionary for probe messages."""
PEND_TYPE = 'probe'
+@public
def send_probe(member, msg):
"""Send a VERP probe to the member.
@@ -231,7 +223,7 @@ def send_probe(member, msg):
return token
-
+@public
def maybe_forward(mlist, msg):
"""Possibly forward bounce messages with no recognizable addresses.
@@ -249,7 +241,7 @@ def maybe_forward(mlist, msg):
# (owners and moderators), or to the site administrators. Most of the
# notification is exactly the same in either case.
adminurl = mlist.script_url('admin') + '/bounce'
- subject=_('Uncaught bounce notification')
+ subject = _('Uncaught bounce notification')
text = MIMEText(
make('unrecognized.txt', mlist, adminurl=adminurl),
_charset=mlist.preferred_language.charset)
@@ -258,7 +250,7 @@ def maybe_forward(mlist, msg):
is UnrecognizedBounceDisposition.administrators):
keywords = dict(roster=mlist.administrators)
elif (mlist.forward_unrecognized_bounces_to
- is UnrecognizedBounceDisposition.site_owner):
+ is UnrecognizedBounceDisposition.site_owner):
keywords = {}
else:
raise AssertionError('Invalid forwarding disposition: {0}'.format(
diff --git a/src/mailman/app/commands.py b/src/mailman/app/commands.py
index 35158da2a..4c484bc0b 100644
--- a/src/mailman/app/commands.py
+++ b/src/mailman/app/commands.py
@@ -17,18 +17,14 @@
"""Initialize the email commands."""
-__all__ = [
- 'initialize',
- ]
-
-
+from mailman import public
from mailman.config import config
from mailman.interfaces.command import IEmailCommand
from mailman.utilities.modules import find_components
from zope.interface.verify import verifyObject
-
+@public
def initialize():
"""Initialize the email commands."""
for command_class in find_components('mailman.commands', IEmailCommand):
diff --git a/src/mailman/app/digests.py b/src/mailman/app/digests.py
index fd708cb04..f8b217142 100644
--- a/src/mailman/app/digests.py
+++ b/src/mailman/app/digests.py
@@ -17,21 +17,16 @@
"""Digest functions."""
-__all__ = [
- 'bump_digest_number_and_volume',
- 'maybe_send_digest_now',
- ]
-
-
import os
+from mailman import public
from mailman.config import config
from mailman.email.message import Message
from mailman.interfaces.digests import DigestFrequency
from mailman.utilities.datetime import now as right_now
-
+@public
def bump_digest_number_and_volume(mlist):
"""Bump the digest number and volume."""
now = right_now()
@@ -72,7 +67,7 @@ def bump_digest_number_and_volume(mlist):
mlist.digest_last_sent_at = now
-
+@public
def maybe_send_digest_now(mlist, *, force=False):
"""Send this mailing list's digest now.
@@ -97,8 +92,7 @@ def maybe_send_digest_now(mlist, *, force=False):
size = os.path.getsize(mailbox_path)
except FileNotFoundError:
size = 0
- if (size >= mlist.digest_size_threshold * 1024.0 or
- (force and size > 0)):
+ if (size >= mlist.digest_size_threshold * 1024.0 or (force and size > 0)):
# Send the digest. Because we don't want to hold up this process
# with crafting the digest, we're going to move the digest file to
# a safe place, then craft a fake message for the DigestRunner as
diff --git a/src/mailman/app/domain.py b/src/mailman/app/domain.py
index 72c4e69ff..66abf9c3e 100644
--- a/src/mailman/app/domain.py
+++ b/src/mailman/app/domain.py
@@ -17,17 +17,13 @@
"""Application level domain support."""
-__all__ = [
- 'handle_DomainDeletingEvent',
- ]
-
-
+from mailman import public
from mailman.interfaces.domain import DomainDeletingEvent
from mailman.interfaces.listmanager import IListManager
from zope.component import getUtility
-
+@public
def handle_DomainDeletingEvent(event):
"""Delete all mailing lists in a domain when the domain is deleted."""
diff --git a/src/mailman/app/events.py b/src/mailman/app/events.py
index 6a170ad04..8b95bd4be 100644
--- a/src/mailman/app/events.py
+++ b/src/mailman/app/events.py
@@ -17,11 +17,7 @@
"""Global events."""
-__all__ = [
- 'initialize',
- ]
-
-
+from mailman import public
from mailman.app import (
domain, membership, moderator, registrar, subscriptions)
from mailman.core import i18n, switchboard
@@ -31,7 +27,7 @@ from mailman.utilities import passwords
from zope import event
-
+@public
def initialize():
"""Initialize global event subscribers."""
event.subscribers.extend([
diff --git a/src/mailman/app/inject.py b/src/mailman/app/inject.py
index 528aa99c2..decc0fd0e 100644
--- a/src/mailman/app/inject.py
+++ b/src/mailman/app/inject.py
@@ -17,20 +17,15 @@
"""Inject a message into a queue."""
-__all__ = [
- 'inject_message',
- 'inject_text',
- ]
-
-
from email import message_from_string
from email.utils import formatdate, make_msgid
+from mailman import public
from mailman.config import config
from mailman.email.message import Message
from mailman.utilities.email import add_message_hash
-
+@public
def inject_message(mlist, msg, recipients=None, switchboard=None, **kws):
"""Inject a message into a queue.
@@ -73,7 +68,7 @@ def inject_message(mlist, msg, recipients=None, switchboard=None, **kws):
return config.switchboards[switchboard].enqueue(msg, **msgdata)
-
+@public
def inject_text(mlist, text, recipients=None, switchboard=None, **kws):
"""Turn text into a message and inject that into a queue.
diff --git a/src/mailman/app/lifecycle.py b/src/mailman/app/lifecycle.py
index 94ccbcc50..50145ce8f 100644
--- a/src/mailman/app/lifecycle.py
+++ b/src/mailman/app/lifecycle.py
@@ -17,15 +17,11 @@
"""Application level list creation."""
-__all__ = [
- 'create_list',
- 'remove_list',
- ]
-
-
import shutil
import logging
+from contextlib import suppress
+from mailman import public
from mailman.config import config
from mailman.interfaces.address import IEmailValidator
from mailman.interfaces.domain import (
@@ -41,7 +37,7 @@ from zope.component import getUtility
log = logging.getLogger('mailman.error')
-
+@public
def create_list(fqdn_listname, owners=None, style_name=None):
"""Create the named list and apply styles.
@@ -89,14 +85,12 @@ def create_list(fqdn_listname, owners=None, style_name=None):
return mlist
-
+@public
def remove_list(mlist):
"""Remove the list and all associated artifacts and subscriptions."""
# Remove the list's data directory, if it exists.
- try:
+ with suppress(FileNotFoundError):
shutil.rmtree(mlist.data_path)
- except FileNotFoundError:
- pass
# Delete the mailing list from the database.
getUtility(IListManager).delete(mlist)
# Do the MTA-specific list deletion tasks
diff --git a/src/mailman/app/membership.py b/src/mailman/app/membership.py
index 81f221edc..8ded39388 100644
--- a/src/mailman/app/membership.py
+++ b/src/mailman/app/membership.py
@@ -17,14 +17,8 @@
"""Application support for membership management."""
-__all__ = [
- 'add_member',
- 'delete_member',
- 'handle_SubscriptionEvent',
- ]
-
-
from email.utils import formataddr
+from mailman import public
from mailman.app.notifications import (
send_admin_subscription_notice, send_goodbye_message,
send_welcome_message)
@@ -41,7 +35,7 @@ from mailman.utilities.i18n import make
from zope.component import getUtility
-
+@public
def add_member(mlist, record, role=MemberRole.member):
"""Add a member right now.
@@ -99,7 +93,7 @@ def add_member(mlist, record, role=MemberRole.member):
return member
-
+@public
def delete_member(mlist, email, admin_notif=None, userack=None):
"""Delete a member right now.
@@ -142,7 +136,7 @@ def delete_member(mlist, email, admin_notif=None, userack=None):
msg.send(mlist)
-
+@public
def handle_SubscriptionEvent(event):
if not isinstance(event, SubscriptionEvent):
return
diff --git a/src/mailman/app/moderator.py b/src/mailman/app/moderator.py
index af2addea7..335c7a409 100644
--- a/src/mailman/app/moderator.py
+++ b/src/mailman/app/moderator.py
@@ -17,20 +17,11 @@
"""Application support for moderators."""
-__all__ = [
- 'handle_ListDeletingEvent',
- 'handle_message',
- 'handle_unsubscription',
- 'hold_message',
- 'hold_unsubscription',
- 'send_rejection',
- ]
-
-
import time
import logging
from email.utils import formatdate, getaddresses, make_msgid
+from mailman import public
from mailman.app.membership import delete_member
from mailman.config import config
from mailman.core.i18n import _
@@ -51,7 +42,7 @@ vlog = logging.getLogger('mailman.vette')
slog = logging.getLogger('mailman.subscribe')
-
+@public
def hold_message(mlist, msg, msgdata=None, reason=None):
"""Hold a message for moderator approval.
@@ -97,7 +88,7 @@ def hold_message(mlist, msg, msgdata=None, reason=None):
return request_id
-
+@public
def handle_message(mlist, id, action, comment=None, forward=None):
message_store = getUtility(IMessageStore)
requestdb = IListRequests(mlist)
@@ -187,7 +178,7 @@ def handle_message(mlist, id, action, comment=None, forward=None):
vlog.info(note, mlist.fqdn_listname, rejection, sender, subject)
-
+@public
def hold_unsubscription(mlist, email):
data = dict(email=email)
requestsdb = IListRequests(mlist)
@@ -214,7 +205,7 @@ def hold_unsubscription(mlist, email):
return request_id
-
+@public
def handle_unsubscription(mlist, id, action, comment=None):
requestdb = IListRequests(mlist)
key, data = requestdb.get_request(id)
@@ -244,12 +235,12 @@ def handle_unsubscription(mlist, id, action, comment=None):
requestdb.delete_request(id)
-
+@public
def send_rejection(mlist, request, recip, comment, origmsg=None, lang=None):
# As this message is going to the requester, try to set the language to
# his/her language choice, if they are a member. Otherwise use the list's
# preferred language.
- display_name = mlist.display_name
+ display_name = mlist.display_name # flake8: noqa
if lang is None:
member = mlist.members.get_member(recip)
lang = (mlist.preferred_language
@@ -276,7 +267,7 @@ def send_rejection(mlist, request, recip, comment, origmsg=None, lang=None):
msg.send(mlist)
-
+@public
def handle_ListDeletingEvent(event):
if not isinstance(event, ListDeletingEvent):
return
diff --git a/src/mailman/app/notifications.py b/src/mailman/app/notifications.py
index e28714eb5..09d5d2bc8 100644
--- a/src/mailman/app/notifications.py
+++ b/src/mailman/app/notifications.py
@@ -17,17 +17,11 @@
"""Sending notifications."""
-__all__ = [
- 'send_admin_subscription_notice',
- 'send_goodbye_message',
- 'send_welcome_message',
- ]
-
-
import logging
from email.utils import formataddr
from lazr.config import as_boolean
+from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.email.message import OwnerNotification, UserNotification
@@ -42,7 +36,6 @@ from zope.component import getUtility
log = logging.getLogger('mailman.error')
-
def _get_message(uri_template, mlist, language):
if not uri_template:
return ''
@@ -60,7 +53,7 @@ def _get_message(uri_template, mlist, language):
return wrap(message)
-
+@public
def send_welcome_message(mlist, member, language, text=''):
"""Send a welcome message to a subscriber.
@@ -98,7 +91,8 @@ def send_welcome_message(mlist, member, language, text=''):
user_address=member.address.email,
user_options_uri=options_url,
))
- digmode = ('' if member.delivery_mode is DeliveryMode.regular
+ digmode = ('' # flake8: noqa
+ if member.delivery_mode is DeliveryMode.regular
else _(' (Digest mode)'))
msg = UserNotification(
formataddr((display_name, member.address.email)),
@@ -109,7 +103,7 @@ def send_welcome_message(mlist, member, language, text=''):
msg.send(mlist, verp=as_boolean(config.mta.verp_personalized_deliveries))
-
+@public
def send_goodbye_message(mlist, address, language):
"""Send a goodbye message to a subscriber.
@@ -133,7 +127,7 @@ def send_goodbye_message(mlist, address, language):
msg.send(mlist, verp=as_boolean(config.mta.verp_personalized_deliveries))
-
+@public
def send_admin_subscription_notice(mlist, address, display_name):
"""Send the list administrators a subscription notice.
diff --git a/src/mailman/app/registrar.py b/src/mailman/app/registrar.py
index 7a6464a61..ca2804f5d 100644
--- a/src/mailman/app/registrar.py
+++ b/src/mailman/app/registrar.py
@@ -17,14 +17,9 @@
"""Implementation of the IRegistrar interface."""
-__all__ = [
- 'Registrar',
- 'handle_ConfirmationNeededEvent',
- ]
-
-
import logging
+from mailman import public
from mailman.app.subscriptions import SubscriptionWorkflow
from mailman.core.i18n import _
from mailman.database.transaction import flush
@@ -40,13 +35,12 @@ from zope.interface import implementer
log = logging.getLogger('mailman.error')
-
@implementer(IPendable)
class PendableRegistration(dict):
PEND_TYPE = 'registration'
-
+@public
@implementer(IRegistrar)
class Registrar:
"""Handle registrations and confirmations for subscriptions."""
@@ -81,7 +75,7 @@ class Registrar:
SubscriptionWorkflow.__name__, token)
-
+@public
def handle_ConfirmationNeededEvent(event):
if not isinstance(event, ConfirmationNeededEvent):
return
@@ -93,13 +87,13 @@ def handle_ConfirmationNeededEvent(event):
subject = 'confirm ' + event.token
confirm_address = event.mlist.confirm_address(event.token)
# For i18n interpolation.
- confirm_url = event.mlist.domain.confirm_url(event.token)
+ confirm_url = event.mlist.domain.confirm_url(event.token) # flake8: noqa
email_address = event.email
- domain_name = event.mlist.domain.mail_host
- contact_address = event.mlist.owner_address
+ domain_name = event.mlist.domain.mail_host # flake8: noqa
+ contact_address = event.mlist.owner_address # flake8: noqa
# Send a verification email to the address.
template = getUtility(ITemplateLoader).get(
- 'mailman:///{0}/{1}/confirm.txt'.format(
+ 'mailman:///{}/{}/confirm.txt'.format(
event.mlist.fqdn_listname,
event.mlist.preferred_language.code))
text = _(template)
diff --git a/src/mailman/app/replybot.py b/src/mailman/app/replybot.py
index f9e83dc9a..fc911c5a1 100644
--- a/src/mailman/app/replybot.py
+++ b/src/mailman/app/replybot.py
@@ -17,21 +17,10 @@
"""Application level auto-reply code."""
-# XXX This should undergo a rewrite to move this functionality off of the
-# mailing list. The reply governor should really apply site-wide per
-# recipient (I think).
+from mailman import public
-__all__ = [
- 'can_acknowledge',
- ]
-import logging
-
-
-log = logging.getLogger('mailman.vette')
-
-
-
+@public
def can_acknowledge(msg):
"""A boolean specifying whether this message can be acknowledged.
diff --git a/src/mailman/app/subscriptions.py b/src/mailman/app/subscriptions.py
index a75d4361d..ca7ede14f 100644
--- a/src/mailman/app/subscriptions.py
+++ b/src/mailman/app/subscriptions.py
@@ -17,18 +17,13 @@
"""Handle subscriptions."""
-__all__ = [
- 'SubscriptionWorkflow',
- 'handle_ListDeletingEvent',
- ]
-
-
import uuid
import logging
from email.utils import formataddr
from enum import Enum
from datetime import timedelta
+from mailman import public
from mailman.app.workflow import Workflow
from mailman.core.i18n import _
from mailman.email.message import UserNotification
@@ -64,7 +59,7 @@ class Pendable(dict):
PEND_TYPE = 'subscription'
-
+@public
class SubscriptionWorkflow(Workflow):
"""Workflow of a subscription request."""
@@ -225,10 +220,11 @@ class SubscriptionWorkflow(Workflow):
# required we need to check that, otherwise we can go straight to
# subscription.
if self.pre_confirmed:
- next_step = ('moderation_checks'
- if self.mlist.subscription_policy is
- SubscriptionPolicy.confirm_then_moderate
- else 'do_subscription')
+ next_step = (
+ 'moderation_checks'
+ if self.mlist.subscription_policy is
+ SubscriptionPolicy.confirm_then_moderate # flake8: noqa
+ else 'do_subscription')
self.push(next_step)
return
# The user must confirm their subscription.
@@ -327,11 +323,11 @@ class SubscriptionWorkflow(Workflow):
SubscriptionPolicy.moderate,
SubscriptionPolicy.confirm_then_moderate,
)
- else 'do_subscription')
+ else 'do_subscription')
self.push(next_step)
-
+@public
def handle_ListDeletingEvent(event):
"""Delete a mailing list's members when the list is being deleted."""
diff --git a/src/mailman/app/templates.py b/src/mailman/app/templates.py
index 1d1203ad7..c01b9af47 100644
--- a/src/mailman/app/templates.py
+++ b/src/mailman/app/templates.py
@@ -17,12 +17,8 @@
"""Template loader."""
-__all__ = [
- 'TemplateLoader',
- ]
-
-
from contextlib import closing
+from mailman import public
from mailman.interfaces.languages import ILanguageManager
from mailman.interfaces.listmanager import IListManager
from mailman.interfaces.templates import ITemplateLoader
@@ -35,7 +31,6 @@ from zope.component import getUtility
from zope.interface import implementer
-
class MailmanHandler(BaseHandler):
# Handle internal mailman: URLs.
def mailman_open(self, req):
@@ -94,7 +89,7 @@ class MailmanHandler(BaseHandler):
return addinfourl(fp, {}, original_url)
-
+@public
@implementer(ITemplateLoader)
class TemplateLoader:
"""Loader of templates, with caching and support for mailman:// URIs."""
diff --git a/src/mailman/app/tests/test_bounces.py b/src/mailman/app/tests/test_bounces.py
index d53a74b6c..ffc1cf2b4 100644
--- a/src/mailman/app/tests/test_bounces.py
+++ b/src/mailman/app/tests/test_bounces.py
@@ -17,16 +17,6 @@
"""Testing app.bounces functions."""
-__all__ = [
- 'TestBounceMessage',
- 'TestMaybeForward',
- 'TestProbe',
- 'TestSendProbe',
- 'TestSendProbeNonEnglish',
- 'TestVERP',
- ]
-
-
import os
import uuid
import shutil
@@ -49,7 +39,6 @@ from mailman.testing.layers import ConfigLayer
from zope.component import getUtility
-
class TestVERP(unittest.TestCase):
"""Test header VERP detection."""
@@ -184,7 +173,6 @@ Apparently-To: test-bounces+bart=example.org@example.com
set(['anne@example.org', 'bart@example.org']))
-
class TestSendProbe(unittest.TestCase):
"""Test sending of the probe message."""
@@ -218,25 +206,25 @@ Message-ID: <first>
def test_probe_is_multipart(self):
# The probe is a multipart/mixed with two subparts.
send_probe(self._member, self._msg)
- message = get_queue_messages('virgin')[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(message.get_content_type(), 'multipart/mixed')
self.assertTrue(message.is_multipart())
self.assertEqual(len(message.get_payload()), 2)
def test_probe_sends_one_message(self):
- # send_probe() places one message in the virgin queue.
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 0)
+ # send_probe() places one message in the virgin queue. We start out
+ # with no messages in the queue.
+ get_queue_messages('virgin', expected_count=0)
send_probe(self._member, self._msg)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ get_queue_messages('virgin', expected_count=1)
def test_probe_contains_original(self):
# Show that send_probe() places a properly formatted message in the
# virgin queue.
send_probe(self._member, self._msg)
- message = get_queue_messages('virgin')[0].msg
- rfc822 = message.get_payload(1)
+ items = get_queue_messages('virgin', expected_count=1)
+ rfc822 = items[0].msg.get_payload(1)
self.assertEqual(rfc822.get_content_type(), 'message/rfc822')
self.assertTrue(rfc822.is_multipart())
self.assertEqual(len(rfc822.get_payload()), 1)
@@ -246,7 +234,8 @@ Message-ID: <first>
def test_notice(self):
# Test that the notice in the first subpart is correct.
send_probe(self._member, self._msg)
- message = get_queue_messages('virgin')[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
notice = message.get_payload(0)
self.assertEqual(notice.get_content_type(), 'text/plain')
# The interesting bits are the parts that have been interpolated into
@@ -254,15 +243,16 @@ Message-ID: <first>
# interpolation values appear in the message. When Python 2.7 is our
# minimum requirement, we can use assertRegexpMatches().
body = notice.get_payload()
- self.assertTrue('test@example.com' in body)
- self.assertTrue('anne@example.com' in body)
- self.assertTrue('http://example.com/anne@example.com' in body)
- self.assertTrue('test-owner@example.com' in body)
+ self.assertIn('test@example.com', body)
+ self.assertIn('anne@example.com', body)
+ self.assertIn('http://example.com/anne@example.com', body)
+ self.assertIn('test-owner@example.com', body)
def test_headers(self):
# Check the headers of the outer message.
token = send_probe(self._member, self._msg)
- message = get_queue_messages('virgin')[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(message['from'],
'test-bounces+{0}@example.com'.format(token))
self.assertEqual(message['to'], 'anne@example.com')
@@ -271,15 +261,15 @@ Message-ID: <first>
def test_no_precedence_header(self):
# Probe messages should not have a Precedence header (LP: #808821).
send_probe(self._member, self._msg)
- message = get_queue_messages('virgin')[0].msg
- self.assertEqual(message['precedence'], None)
+ items = get_queue_messages('virgin', expected_count=1)
+ self.assertIsNone(items[0].msg['precedence'])
-
class TestSendProbeNonEnglish(unittest.TestCase):
"""Test sending of the probe message to a non-English speaker."""
layer = ConfigLayer
+ maxDiff = None
def setUp(self):
self._mlist = create_list('test@example.com')
@@ -293,13 +283,15 @@ Message-ID: <first>
""")
# Set up the translation context.
self._var_dir = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, self._var_dir)
xx_template_path = os.path.join(
self._var_dir, 'templates', 'site', 'xx', 'probe.txt')
os.makedirs(os.path.dirname(xx_template_path))
config.push('xx template dir', """\
[paths.testing]
- var_dir: {0}
+ var_dir: {}
""".format(self._var_dir))
+ self.addCleanup(config.pop, 'xx template dir')
language_manager = getUtility(ILanguageManager)
language_manager.add('xx', 'utf-8', 'Freedonia')
self._member.preferences.preferred_language = 'xx'
@@ -311,34 +303,28 @@ $address
$optionsurl
$owneraddr
""", file=fp)
- # Let assertMultiLineEqual work without bounds.
- self.maxDiff = None
-
- def tearDown(self):
- config.pop('xx template dir')
- shutil.rmtree(self._var_dir)
def test_subject_with_member_nonenglish(self):
# Test that members with non-English preferred language get a Subject
# header in the expected language.
send_probe(self._member, self._msg)
- message = get_queue_messages('virgin')[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
self.assertEqual(
- message['subject'].encode(),
+ items[0].msg['subject'].encode(),
'=?utf-8?q?ailing-may_ist-lay_Test_obe-pray_essage-may?=')
def test_probe_notice_with_member_nonenglish(self):
# Test that a member with non-English preferred language gets the
# probe message in their language.
send_probe(self._member, self._msg)
- message = get_queue_messages('virgin')[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
notice = message.get_payload(0).get_payload()
self.assertMultiLineEqual(notice, """\
blah blah blah test@example.com anne@example.com
http://example.com/anne@example.com test-owner@example.com""")
-
class TestProbe(unittest.TestCase):
"""Test VERP probe parsing."""
@@ -361,7 +347,8 @@ Message-ID: <first>
# based on the token in a probe bounce.
token = send_probe(self._member, self._msg)
# Simulate a bounce of the message in the virgin queue.
- message = get_queue_messages('virgin')[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
bounce = mfs("""\
To: {0}
From: mail-daemon@example.com
@@ -370,10 +357,9 @@ From: mail-daemon@example.com
addresses = ProbeVERP().get_verp(self._mlist, bounce)
self.assertEqual(addresses, set(['anne@example.com']))
# The pendable is no longer in the database.
- self.assertEqual(getUtility(IPendings).confirm(token), None)
+ self.assertIsNone(getUtility(IPendings).confirm(token))
-
class TestMaybeForward(unittest.TestCase):
"""Test forwarding of unrecognized bounces."""
@@ -384,6 +370,7 @@ class TestMaybeForward(unittest.TestCase):
[mailman]
site_owner: postmaster@example.com
""")
+ self.addCleanup(config.pop, 'test config')
self._mlist = create_list('test@example.com')
self._mlist.send_welcome_message = False
self._msg = mfs("""\
@@ -394,9 +381,6 @@ Message-ID: <first>
""")
- def tearDown(self):
- config.pop('test config')
-
def test_maybe_forward_discard(self):
# When forward_unrecognized_bounces_to is set to discard, no bounce
# messages are forwarded.
@@ -405,8 +389,7 @@ Message-ID: <first>
# The only artifact of this call is a log file entry.
mark = LogFileMark('mailman.bounce')
maybe_forward(self._mlist, self._msg)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 0)
+ get_queue_messages('virgin', expected_count=0)
line = mark.readline()
self.assertEqual(
line[-40:-1],
@@ -433,8 +416,7 @@ Message-ID: <first>
self._mlist.forward_unrecognized_bounces_to = (
UnrecognizedBounceDisposition.administrators)
maybe_forward(self._mlist, self._msg)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('virgin', expected_count=1)
msg = items[0].msg
self.assertEqual(msg['subject'], 'Uncaught bounce notification')
self.assertEqual(msg['from'], 'postmaster@example.com')
@@ -479,8 +461,7 @@ Message-ID: <first>
self._mlist.forward_unrecognized_bounces_to = (
UnrecognizedBounceDisposition.site_owner)
maybe_forward(self._mlist, self._msg)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('virgin', expected_count=1)
msg = items[0].msg
self.assertEqual(msg['subject'], 'Uncaught bounce notification')
self.assertEqual(msg['from'], 'postmaster@example.com')
@@ -501,10 +482,9 @@ Message-ID: <first>
# All of the owners and moderators, but none of the members, should be
# recipients of this message.
self.assertEqual(items[0].msgdata['recipients'],
- set(['postmaster@example.com',]))
+ set(['postmaster@example.com']))
-
class TestBounceMessage(unittest.TestCase):
"""Test the `mailman.app.bounces.bounce_message()` function."""
@@ -523,6 +503,5 @@ Subject: Ignore
# The message won't be bounced if it has no discernible sender.
del self._msg['from']
bounce_message(self._mlist, self._msg)
- items = get_queue_messages('virgin')
# Nothing in the virgin queue means nothing's been bounced.
- self.assertEqual(items, [])
+ get_queue_messages('virgin', expected_count=0)
diff --git a/src/mailman/app/tests/test_digests.py b/src/mailman/app/tests/test_digests.py
index 80aee6439..c2919dcbb 100644
--- a/src/mailman/app/tests/test_digests.py
+++ b/src/mailman/app/tests/test_digests.py
@@ -17,12 +17,6 @@
"""Digest helper tests."""
-__all__ = [
- 'TestBumpDigest',
- 'TestMaybeSendDigest',
- ]
-
-
import os
import unittest
@@ -41,7 +35,6 @@ from mailman.testing.layers import ConfigLayer
from mailman.utilities.datetime import factory, now as right_now
-
class TestBumpDigest(unittest.TestCase):
layer = ConfigLayer
@@ -162,7 +155,6 @@ class TestBumpDigest(unittest.TestCase):
bump_digest_number_and_volume, self._mlist)
-
class TestMaybeSendDigest(unittest.TestCase):
layer = ConfigLayer
@@ -196,10 +188,9 @@ Subject: message {}
self._runner.run()
# There are no digests in flight now, and a single digest message has
# been sent.
- self.assertEqual(len(get_queue_messages('digest')), 0)
+ get_queue_messages('digest', expected_count=0)
self.assertFalse(os.path.exists(self._mailbox_path))
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('virgin', expected_count=1)
digest_contents = str(items[0].msg)
self.assertIn('Subject: message 1', digest_contents)
self.assertIn('Subject: message 2', digest_contents)
@@ -212,11 +203,10 @@ Subject: message {}
maybe_send_digest_now(self._mlist)
self._runner.run()
# A digest is still being collected, but none have been sent.
- self.assertEqual(len(get_queue_messages('digest')), 0)
+ get_queue_messages('digest', expected_count=0)
self.assertGreater(os.path.getsize(self._mailbox_path), 0)
self.assertLess(os.path.getsize(self._mailbox_path), 100 * 1024.0)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 0)
+ get_queue_messages('virgin', expected_count=0)
def test_force_send_digest_under_threshold(self):
# Put a few messages in the digest.
@@ -228,10 +218,9 @@ Subject: message {}
self._runner.run()
# There are no digests in flight now, and a single digest message has
# been sent.
- self.assertEqual(len(get_queue_messages('digest')), 0)
+ get_queue_messages('digest', expected_count=0)
self.assertFalse(os.path.exists(self._mailbox_path))
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('virgin', expected_count=1)
digest_contents = str(items[0].msg)
self.assertIn('Subject: message 1', digest_contents)
self.assertIn('Subject: message 2', digest_contents)
diff --git a/src/mailman/app/tests/test_inject.py b/src/mailman/app/tests/test_inject.py
index b8e311ed8..e71980163 100644
--- a/src/mailman/app/tests/test_inject.py
+++ b/src/mailman/app/tests/test_inject.py
@@ -17,12 +17,6 @@
"""Testing app.inject functions."""
-__all__ = [
- 'TestInjectMessage',
- 'TestInjectText',
- ]
-
-
import unittest
from mailman.app.inject import inject_message, inject_text
@@ -37,7 +31,6 @@ from mailman.testing.layers import ConfigLayer
NL = '\n'
-
class TestInjectMessage(unittest.TestCase):
"""Test message injection."""
@@ -59,8 +52,7 @@ Nothing.
def test_inject_message(self):
# Test basic inject_message() call.
inject_message(self.mlist, self.msg)
- items = get_queue_messages('in')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('in', expected_count=1)
self.assertMultiLineEqual(items[0].msg.as_string(),
self.msg.as_string())
self.assertEqual(items[0].msgdata['listid'], 'test.example.com')
@@ -71,16 +63,14 @@ Nothing.
# Explicit recipients end up in the metadata.
recipients = ['bart@example.com', 'cris@example.com']
inject_message(self.mlist, self.msg, recipients)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertEqual(items[0].msgdata['recipients'], recipients)
def test_inject_message_to_queue(self):
# Explicitly use a different queue.
inject_message(self.mlist, self.msg, switchboard='virgin')
- items = get_queue_messages('in')
- self.assertEqual(len(items), 0)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ get_queue_messages('in', expected_count=0)
+ items = get_queue_messages('virgin', expected_count=1)
self.assertMultiLineEqual(items[0].msg.as_string(),
self.msg.as_string())
self.assertEqual(items[0].msgdata['listid'], 'test.example.com')
@@ -93,7 +83,7 @@ Nothing.
self.assertNotIn('message-id', self.msg)
inject_message(self.mlist, self.msg)
self.assertIn('message-id', self.msg)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertIn('message-id', items[0].msg)
self.assertEqual(items[0].msg['message-id'], self.msg['message-id'])
@@ -103,14 +93,14 @@ Nothing.
self.assertNotIn('date', self.msg)
inject_message(self.mlist, self.msg)
self.assertIn('date', self.msg)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertIn('date', items[0].msg)
self.assertEqual(items[0].msg['date'], self.msg['date'])
def test_inject_message_with_keywords(self):
# Keyword arguments are copied into the metadata.
inject_message(self.mlist, self.msg, foo='yes', bar='no')
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertEqual(items[0].msgdata['foo'], 'yes')
self.assertEqual(items[0].msgdata['bar'], 'no')
@@ -118,7 +108,7 @@ Nothing.
# When the injected message has a Message-ID header, the injected
# message will also get an Message-ID-Hash header.
inject_message(self.mlist, self.msg)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertEqual(items[0].msg['message-id-hash'],
'4CMWUN6BHVCMHMDAOSJZ2Q72G5M32MWB')
@@ -130,12 +120,11 @@ Nothing.
self.assertNotIn('message-id', self.msg)
self.assertNotIn('message-id-hash', self.msg)
inject_message(self.mlist, self.msg)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertIn('message-id', items[0].msg)
self.assertIn('message-id-hash', items[0].msg)
-
class TestInjectText(unittest.TestCase):
"""Test text injection."""
@@ -161,9 +150,8 @@ Nothing.
def test_inject_text(self):
# Test basic inject_text() call.
inject_text(self.mlist, self.text)
- items = get_queue_messages('in')
- self.assertEqual(len(items), 1)
- self.assertTrue(isinstance(items[0].msg, Message))
+ items = get_queue_messages('in', expected_count=1)
+ self.assertIsInstance(items[0].msg, Message)
self.assertEqual(items[0].msg['message-id-hash'],
'GUXXQKNCHBFQAHGBFMGCME6HKZCUUH3K')
# Delete these headers because they don't exist in the original text.
@@ -182,16 +170,14 @@ Nothing.
# Explicit recipients end up in the metadata.
recipients = ['bart@example.com', 'cris@example.com']
inject_text(self.mlist, self.text, recipients)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertEqual(items[0].msgdata['recipients'], recipients)
def test_inject_text_to_queue(self):
# Explicitly use a different queue.
inject_text(self.mlist, self.text, switchboard='virgin')
- items = get_queue_messages('in')
- self.assertEqual(len(items), 0)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ get_queue_messages('in', expected_count=0)
+ items = get_queue_messages('virgin', expected_count=1)
# Remove the Message-ID-Hash header which isn't in the original text.
del items[0].msg['message-id-hash']
del items[0].msg['x-message-id-hash']
@@ -209,7 +195,7 @@ Nothing.
filtered = self._remove_line('message-id')
self.assertNotIn('Message-ID', filtered)
inject_text(self.mlist, filtered)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertIn('message-id', items[0].msg)
def test_inject_text_without_date(self):
@@ -217,14 +203,14 @@ Nothing.
filtered = self._remove_line('date')
self.assertNotIn('date', filtered)
inject_text(self.mlist, self.text)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertIn('date', items[0].msg)
def test_inject_text_adds_original_size(self):
# The metadata gets an original_size attribute that is the length of
# the injected text.
inject_text(self.mlist, self.text)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertEqual(items[0].msgdata['original_size'],
# Add back the Message-ID-Hash and X-Message-ID-Hash
# headers which wer in the message contributing to the
@@ -235,7 +221,7 @@ Nothing.
def test_inject_text_with_keywords(self):
# Keyword arguments are copied into the metadata.
inject_text(self.mlist, self.text, foo='yes', bar='no')
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertEqual(items[0].msgdata['foo'], 'yes')
self.assertEqual(items[0].msgdata['bar'], 'no')
@@ -243,7 +229,7 @@ Nothing.
# When the injected message has a Message-ID header, the injected
# message will also get an Message-ID-Hash header.
inject_text(self.mlist, self.text)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertEqual(items[0].msg['message-id-hash'],
'GUXXQKNCHBFQAHGBFMGCME6HKZCUUH3K')
@@ -255,6 +241,6 @@ Nothing.
self.assertNotIn('Message-ID', filtered)
self.assertNotIn('Message-ID-Hash', filtered)
inject_text(self.mlist, filtered)
- items = get_queue_messages('in')
+ items = get_queue_messages('in', expected_count=1)
self.assertIn('message-id', items[0].msg)
self.assertIn('message-id-hash', items[0].msg)
diff --git a/src/mailman/app/tests/test_lifecycle.py b/src/mailman/app/tests/test_lifecycle.py
index ad9e36e4f..d4ad067d2 100644
--- a/src/mailman/app/tests/test_lifecycle.py
+++ b/src/mailman/app/tests/test_lifecycle.py
@@ -17,11 +17,6 @@
"""Test the high level list lifecycle API."""
-__all__ = [
- 'TestLifecycle',
- ]
-
-
import os
import shutil
import unittest
@@ -34,7 +29,6 @@ from mailman.testing.layers import ConfigLayer
from zope.component import getUtility
-
class TestLifecycle(unittest.TestCase):
"""Test the high level list lifecycle API."""
diff --git a/src/mailman/app/tests/test_membership.py b/src/mailman/app/tests/test_membership.py
index ad61d875b..e17e5704b 100644
--- a/src/mailman/app/tests/test_membership.py
+++ b/src/mailman/app/tests/test_membership.py
@@ -17,12 +17,6 @@
"""Tests of application level membership functions."""
-__all__ = [
- 'TestAddMember',
- 'TestDeleteMember',
- ]
-
-
import unittest
from mailman.app.lifecycle import create_list
@@ -38,7 +32,6 @@ from mailman.testing.layers import ConfigLayer
from zope.component import getUtility
-
class TestAddMember(unittest.TestCase):
layer = ConfigLayer
@@ -229,7 +222,6 @@ class TestAddMember(unittest.TestCase):
self.assertEqual(cm.exception.email, email.lower())
-
class TestDeleteMember(unittest.TestCase):
layer = ConfigLayer
diff --git a/src/mailman/app/tests/test_moderation.py b/src/mailman/app/tests/test_moderation.py
index e71b692c0..931b85fd0 100644
--- a/src/mailman/app/tests/test_moderation.py
+++ b/src/mailman/app/tests/test_moderation.py
@@ -17,12 +17,6 @@
"""Moderation tests."""
-__all__ = [
- 'TestModeration',
- 'TestUnsubscription',
- ]
-
-
import unittest
from mailman.app.lifecycle import create_list
@@ -37,13 +31,13 @@ from mailman.runners.incoming import IncomingRunner
from mailman.runners.outgoing import OutgoingRunner
from mailman.runners.pipeline import PipelineRunner
from mailman.testing.helpers import (
- get_queue_messages, make_testable_runner, specialized_message_from_string)
+ get_queue_messages, make_testable_runner,
+ specialized_message_from_string as mfs)
from mailman.testing.layers import SMTPLayer
from mailman.utilities.datetime import now
from zope.component import getUtility
-
class TestModeration(unittest.TestCase):
"""Test moderation functionality."""
@@ -52,7 +46,7 @@ class TestModeration(unittest.TestCase):
def setUp(self):
self._mlist = create_list('test@example.com')
self._request_db = IListRequests(self._mlist)
- self._msg = specialized_message_from_string("""\
+ self._msg = mfs("""\
From: anne@example.com
To: test@example.com
Subject: hold me
@@ -78,8 +72,8 @@ Message-ID: <alpha>
message = messages[0]
# We don't need to test the entire posted message, just the bits that
# prove it got sent out.
- self.assertTrue('x-mailman-version' in message)
- self.assertTrue('x-peer' in message)
+ self.assertIn('x-mailman-version', message)
+ self.assertIn('x-peer', message)
# The X-Mailman-Approved-At header has local timezone information in
# it, so test that separately.
self.assertEqual(message['x-mailman-approved-at'][:-5],
@@ -127,11 +121,10 @@ Message-ID: <alpha>
handle_message(self._mlist, request_id, Action.discard,
forward=['zack@example.com'])
# The forwarded message lives in the virgin queue.
- messages = get_queue_messages('virgin')
- self.assertEqual(len(messages), 1)
- self.assertEqual(str(messages[0].msg['subject']),
+ items = get_queue_messages('virgin', expected_count=1)
+ self.assertEqual(str(items[0].msg['subject']),
'Forward of moderated message')
- self.assertEqual(messages[0].msgdata['recipients'],
+ self.assertEqual(items[0].msgdata['recipients'],
['zack@example.com'])
def test_survive_a_deleted_message(self):
@@ -153,7 +146,6 @@ Message-ID: <alpha>
self.assertEqual(message['subject'], 'hold me')
-
class TestUnsubscription(unittest.TestCase):
"""Test unsubscription requests."""
diff --git a/src/mailman/app/tests/test_notifications.py b/src/mailman/app/tests/test_notifications.py
index 248ead6cc..09873f9bb 100644
--- a/src/mailman/app/tests/test_notifications.py
+++ b/src/mailman/app/tests/test_notifications.py
@@ -17,11 +17,6 @@
"""Test notifications."""
-__all__ = [
- 'TestNotifications',
- ]
-
-
import os
import shutil
import tempfile
@@ -39,7 +34,6 @@ from mailman.utilities.datetime import now
from zope.component import getUtility
-
class TestNotifications(unittest.TestCase):
"""Test notifications."""
@@ -51,10 +45,12 @@ class TestNotifications(unittest.TestCase):
self._mlist.welcome_message_uri = 'mailman:///welcome.txt'
self._mlist.display_name = 'Test List'
self.var_dir = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, self.var_dir)
config.push('template config', """\
[paths.testing]
- template_dir: {0}/templates
+ template_dir: {}/templates
""".format(self.var_dir))
+ self.addCleanup(config.pop, 'template config')
# Populate the template directories with a few fake templates.
path = os.path.join(self.var_dir, 'templates', 'site', 'en')
os.makedirs(path)
@@ -76,16 +72,11 @@ Welcome to the $list_name mailing list.
# Let assertMultiLineEqual work without bounds.
self.maxDiff = None
- def tearDown(self):
- config.pop('template config')
- shutil.rmtree(self.var_dir)
-
def test_welcome_message(self):
subscribe(self._mlist, 'Anne', email='anne@example.com')
# Now there's one message in the virgin queue.
- messages = get_queue_messages('virgin')
- self.assertEqual(len(messages), 1)
- message = messages[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(str(message['subject']),
'Welcome to the "Test List" mailing list')
self.assertMultiLineEqual(message.get_payload(), """\
@@ -113,9 +104,8 @@ Welcome to the Test List mailing list.
address.preferences.preferred_language = 'xx'
self._mlist.subscribe(address)
# Now there's one message in the virgin queue.
- messages = get_queue_messages('virgin')
- self.assertEqual(len(messages), 1)
- message = messages[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(str(message['subject']),
'Welcome to the "Test List" mailing list')
self.assertMultiLineEqual(
@@ -126,40 +116,37 @@ Welcome to the Test List mailing list.
# Welcome messages go only to mailing list members, not to owners.
subscribe(self._mlist, 'Anne', MemberRole.owner, 'anne@example.com')
# There is no welcome message in the virgin queue.
- messages = get_queue_messages('virgin')
- self.assertEqual(len(messages), 0)
+ get_queue_messages('virgin', expected_count=0)
def test_no_welcome_message_to_nonmembers(self):
# Welcome messages go only to mailing list members, not to nonmembers.
subscribe(self._mlist, 'Anne', MemberRole.nonmember,
'anne@example.com')
# There is no welcome message in the virgin queue.
- messages = get_queue_messages('virgin')
- self.assertEqual(len(messages), 0)
+ get_queue_messages('virgin', expected_count=0)
def test_no_welcome_message_to_moderators(self):
# Welcome messages go only to mailing list members, not to moderators.
subscribe(self._mlist, 'Anne', MemberRole.moderator,
'anne@example.com')
# There is no welcome message in the virgin queue.
- messages = get_queue_messages('virgin')
- self.assertEqual(len(messages), 0)
+ get_queue_messages('virgin', expected_count=0)
def test_member_susbcribed_address_has_display_name(self):
address = getUtility(IUserManager).create_address(
'anne@example.com', 'Anne Person')
address.verified_on = now()
self._mlist.subscribe(address)
- messages = get_queue_messages('virgin', expected_count=1)
- message = messages[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(message['to'], 'Anne Person <anne@example.com>')
def test_member_subscribed_address_has_no_display_name(self):
address = getUtility(IUserManager).create_address('anne@example.com')
address.verified_on = now()
self._mlist.subscribe(address)
- messages = get_queue_messages('virgin', expected_count=1)
- message = messages[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(message['to'], 'anne@example.com')
def test_member_is_user_and_has_display_name(self):
@@ -167,16 +154,16 @@ Welcome to the Test List mailing list.
'anne@example.com', 'Anne Person')
set_preferred(user)
self._mlist.subscribe(user)
- messages = get_queue_messages('virgin', expected_count=1)
- message = messages[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(message['to'], 'Anne Person <anne@example.com>')
def test_member_is_user_and_has_no_display_name(self):
user = getUtility(IUserManager).create_user('anne@example.com')
set_preferred(user)
self._mlist.subscribe(user)
- messages = get_queue_messages('virgin', expected_count=1)
- message = messages[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(message['to'], 'anne@example.com')
def test_member_has_linked_user_display_name(self):
@@ -187,8 +174,8 @@ Welcome to the Test List mailing list.
address.verified_on = now()
user.link(address)
self._mlist.subscribe(address)
- messages = get_queue_messages('virgin', expected_count=1)
- message = messages[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(message['to'], 'Anne Person <anne2@example.com>')
def test_member_has_no_linked_display_name(self):
@@ -198,8 +185,8 @@ Welcome to the Test List mailing list.
address.verified_on = now()
user.link(address)
self._mlist.subscribe(address)
- messages = get_queue_messages('virgin', expected_count=1)
- message = messages[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(message['to'], 'anne2@example.com')
def test_member_has_address_and_user_display_name(self):
@@ -211,6 +198,6 @@ Welcome to the Test List mailing list.
address.verified_on = now()
user.link(address)
self._mlist.subscribe(address)
- messages = get_queue_messages('virgin', expected_count=1)
- message = messages[0].msg
+ items = get_queue_messages('virgin', expected_count=1)
+ message = items[0].msg
self.assertEqual(message['to'], 'Anne X Person <anne2@example.com>')
diff --git a/src/mailman/app/tests/test_registrar.py b/src/mailman/app/tests/test_registrar.py
index 773b7b7aa..cec90c88b 100644
--- a/src/mailman/app/tests/test_registrar.py
+++ b/src/mailman/app/tests/test_registrar.py
@@ -17,11 +17,6 @@
"""Test email address registration."""
-__all__ = [
- 'TestRegistrar',
- ]
-
-
import unittest
from mailman.app.lifecycle import create_list
@@ -37,7 +32,6 @@ from mailman.utilities.datetime import now
from zope.component import getUtility
-
class TestRegistrar(unittest.TestCase):
"""Test registration."""
@@ -151,8 +145,8 @@ class TestRegistrar(unittest.TestCase):
# approve. Running the workflow gives us a token. Confirming the
# token runs the workflow a little farther, but still gives us a
# token. Confirming again subscribes the user.
- self._mlist.subscription_policy = \
- SubscriptionPolicy.confirm_then_moderate
+ self._mlist.subscription_policy = (
+ SubscriptionPolicy.confirm_then_moderate)
self._anne.verified_on = now()
# Runs until subscription confirmation.
token, token_owner, rmember = self._registrar.register(self._anne)
@@ -186,8 +180,8 @@ class TestRegistrar(unittest.TestCase):
# confirm their subscription is different than the token the moderator
# sees when they approve the subscription. This prevents the user
# from using a replay attack to subvert moderator approval.
- self._mlist.subscription_policy = \
- SubscriptionPolicy.confirm_then_moderate
+ self._mlist.subscription_policy = (
+ SubscriptionPolicy.confirm_then_moderate)
self._anne.verified_on = now()
# Runs until subscription confirmation.
token, token_owner, rmember = self._registrar.register(self._anne)
@@ -248,8 +242,7 @@ class TestRegistrar(unittest.TestCase):
# Anne is now a member.
self.assertEqual(member.address.email, 'anne@example.com')
# And there's a notification email waiting for Bart.
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('virgin', expected_count=1)
message = items[0].msg
self.assertEqual(message['To'], 'ant-owner@example.com')
self.assertEqual(message['Subject'], 'Ant subscription notification')
@@ -272,5 +265,4 @@ anne@example.com has been successfully subscribed to Ant.""")
# Anne is now a member.
self.assertEqual(member.address.email, 'anne@example.com')
# There's no notification email waiting for Bart.
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 0)
+ get_queue_messages('virgin', expected_count=0)
diff --git a/src/mailman/app/tests/test_subscriptions.py b/src/mailman/app/tests/test_subscriptions.py
index 3aaa5887a..02b5fe6da 100644
--- a/src/mailman/app/tests/test_subscriptions.py
+++ b/src/mailman/app/tests/test_subscriptions.py
@@ -17,11 +17,6 @@
"""Tests for the subscription service."""
-__all__ = [
- 'TestSubscriptionWorkflow',
- ]
-
-
import unittest
from mailman.app.lifecycle import create_list
@@ -40,7 +35,6 @@ from unittest.mock import patch
from zope.component import getUtility
-
class TestSubscriptionWorkflow(unittest.TestCase):
layer = ConfigLayer
maxDiff = None
@@ -230,8 +224,8 @@ class TestSubscriptionWorkflow(unittest.TestCase):
# The subscription policy requires user confirmation, but their
# subscription is pre-confirmed. Since moderation is required, that
# check will be performed.
- self._mlist.subscription_policy = \
- SubscriptionPolicy.confirm_then_moderate
+ self._mlist.subscription_policy = (
+ SubscriptionPolicy.confirm_then_moderate)
anne = self._user_manager.create_address(self._anne)
workflow = SubscriptionWorkflow(self._mlist, anne,
pre_verified=True,
@@ -244,8 +238,8 @@ class TestSubscriptionWorkflow(unittest.TestCase):
def test_confirmation_checks_confirm_and_moderate_pre_confirmed(self):
# The subscription policy requires user confirmation and moderation,
# but their subscription is pre-confirmed.
- self._mlist.subscription_policy = \
- SubscriptionPolicy.confirm_then_moderate
+ self._mlist.subscription_policy = (
+ SubscriptionPolicy.confirm_then_moderate)
anne = self._user_manager.create_address(self._anne)
workflow = SubscriptionWorkflow(self._mlist, anne,
pre_verified=True,
@@ -269,8 +263,8 @@ class TestSubscriptionWorkflow(unittest.TestCase):
def test_confirmation_checks_moderate_confirmation_needed(self):
# The subscription policy requires confirmation and moderation, and the
# subscription is not pre-confirmed.
- self._mlist.subscription_policy = \
- SubscriptionPolicy.confirm_then_moderate
+ self._mlist.subscription_policy = (
+ SubscriptionPolicy.confirm_then_moderate)
anne = self._user_manager.create_address(self._anne)
workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
workflow.run_thru('confirmation_checks')
@@ -340,8 +334,8 @@ class TestSubscriptionWorkflow(unittest.TestCase):
# An moderation-requiring subscription policy plus a pre-verified and
# pre-approved address means the user gets subscribed to the mailing
# list without any further confirmations or approvals.
- self._mlist.subscription_policy = \
- SubscriptionPolicy.confirm_then_moderate
+ self._mlist.subscription_policy = (
+ SubscriptionPolicy.confirm_then_moderate)
anne = self._user_manager.create_address(self._anne)
workflow = SubscriptionWorkflow(self._mlist, anne,
pre_verified=True,
@@ -445,8 +439,7 @@ class TestSubscriptionWorkflow(unittest.TestCase):
pre_confirmed=True)
# Consume the entire state machine.
list(workflow)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('virgin', expected_count=1)
message = items[0].msg
self.assertEqual(message['From'], 'test-owner@example.com')
self.assertEqual(message['To'], 'test-owner@example.com')
@@ -471,8 +464,7 @@ approval:
pre_confirmed=True)
# Consume the entire state machine.
list(workflow)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 0)
+ get_queue_messages('virgin', expected_count=0)
def test_send_confirmation(self):
# A confirmation message gets sent when the address is not verified.
@@ -481,8 +473,7 @@ approval:
# Run the workflow to model the confirmation step.
workflow = SubscriptionWorkflow(self._mlist, anne)
list(workflow)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('virgin', expected_count=1)
message = items[0].msg
token = workflow.token
self.assertEqual(message['Subject'], 'confirm {}'.format(token))
@@ -499,8 +490,7 @@ approval:
# Run the workflow to model the confirmation step.
workflow = SubscriptionWorkflow(self._mlist, anne, pre_confirmed=True)
list(workflow)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('virgin', expected_count=1)
message = items[0].msg
token = workflow.token
self.assertEqual(
@@ -517,8 +507,7 @@ approval:
# Run the workflow to model the confirmation step.
workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
list(workflow)
- items = get_queue_messages('virgin')
- self.assertEqual(len(items), 1)
+ items = get_queue_messages('virgin', expected_count=1)
message = items[0].msg
token = workflow.token
self.assertEqual(
@@ -596,8 +585,8 @@ approval:
# Ensure that if the workflow requires two confirmations, e.g. first
# the user confirming their subscription, and then the moderator
# approving it, that different tokens are used in these two cases.
- self._mlist.subscription_policy = \
- SubscriptionPolicy.confirm_then_moderate
+ self._mlist.subscription_policy = (
+ SubscriptionPolicy.confirm_then_moderate)
anne = self._user_manager.create_address(self._anne)
workflow = SubscriptionWorkflow(self._mlist, anne, pre_verified=True)
# Run the state machine up to the first confirmation, and cache the
diff --git a/src/mailman/app/tests/test_templates.py b/src/mailman/app/tests/test_templates.py
index 9c8df4188..59bf74a0b 100644
--- a/src/mailman/app/tests/test_templates.py
+++ b/src/mailman/app/tests/test_templates.py
@@ -17,11 +17,6 @@
"""Test the template downloader API."""
-__all__ = [
- 'TestTemplateLoader',
- ]
-
-
import os
import shutil
import tempfile
@@ -35,7 +30,6 @@ from urllib.error import URLError
from zope.component import getUtility
-
class TestTemplateLoader(unittest.TestCase):
"""Test the template downloader API."""
@@ -43,10 +37,12 @@ class TestTemplateLoader(unittest.TestCase):
def setUp(self):
self.var_dir = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, self.var_dir)
config.push('template config', """\
[paths.testing]
var_dir: {0}
""".format(self.var_dir))
+ self.addCleanup(config.pop, 'template config')
# Put a demo template in the site directory.
path = os.path.join(self.var_dir, 'templates', 'site', 'en')
os.makedirs(path)
@@ -55,10 +51,6 @@ class TestTemplateLoader(unittest.TestCase):
self._loader = getUtility(ITemplateLoader)
self._mlist = create_list('test@example.com')
- def tearDown(self):
- config.pop('template config')
- shutil.rmtree(self.var_dir)
-
def test_mailman_internal_uris(self):
# mailman://demo.txt
content = self._loader.get('mailman:///demo.txt')
diff --git a/src/mailman/app/tests/test_workflow.py b/src/mailman/app/tests/test_workflow.py
index 0d0ebc9fc..a5bbd0792 100644
--- a/src/mailman/app/tests/test_workflow.py
+++ b/src/mailman/app/tests/test_workflow.py
@@ -17,11 +17,6 @@
"""App-level workflow tests."""
-__all__ = [
- 'TestWorkflow',
- ]
-
-
import unittest
from mailman.app.workflow import Workflow
@@ -52,7 +47,6 @@ class MyWorkflow(Workflow):
return 'three'
-
class TestWorkflow(unittest.TestCase):
layer = ConfigLayer
diff --git a/src/mailman/app/workflow.py b/src/mailman/app/workflow.py
index 7508e9b37..eec8a14a8 100644
--- a/src/mailman/app/workflow.py
+++ b/src/mailman/app/workflow.py
@@ -17,16 +17,12 @@
"""Generic workflow."""
-__all__ = [
- 'Workflow',
- ]
-
-
import sys
import json
import logging
from collections import deque
+from mailman import public
from mailman.interfaces.workflow import IWorkflowStateManager
from zope.component import getUtility
@@ -35,7 +31,7 @@ COMMASPACE = ', '
log = logging.getLogger('mailman.error')
-
+@public
class Workflow:
"""Generic workflow."""
diff --git a/src/mailman/archiving/mailarchive.py b/src/mailman/archiving/mailarchive.py
index 8a38abd67..782cec29a 100644
--- a/src/mailman/archiving/mailarchive.py
+++ b/src/mailman/archiving/mailarchive.py
@@ -17,11 +17,7 @@
"""The Mail-Archive.com archiver."""
-__all__ = [
- 'MailArchive',
- ]
-
-
+from mailman import public
from mailman.config import config
from mailman.config.config import external_configuration
from mailman.interfaces.archiver import ArchivePolicy, IArchiver
@@ -29,7 +25,7 @@ from urllib.parse import quote, urljoin
from zope.interface import implementer
-
+@public
@implementer(IArchiver)
class MailArchive:
"""Public archiver at the Mail-Archive.com.
diff --git a/src/mailman/archiving/mhonarc.py b/src/mailman/archiving/mhonarc.py
index abe7f725a..3aa482bff 100644
--- a/src/mailman/archiving/mhonarc.py
+++ b/src/mailman/archiving/mhonarc.py
@@ -17,13 +17,9 @@
"""MHonArc archiver."""
-__all__ = [
- 'MHonArc',
- ]
-
-
import logging
+from mailman import public
from mailman.config import config
from mailman.config.config import external_configuration
from mailman.interfaces.archiver import IArchiver
@@ -36,7 +32,7 @@ from zope.interface import implementer
log = logging.getLogger('mailman.archiver')
-
+@public
@implementer(IArchiver)
class MHonArc:
"""Local MHonArc archiver."""
diff --git a/src/mailman/archiving/prototype.py b/src/mailman/archiving/prototype.py
index e8435370f..73983cf8d 100644
--- a/src/mailman/archiving/prototype.py
+++ b/src/mailman/archiving/prototype.py
@@ -26,9 +26,11 @@ import os
import errno
import logging
+from contextlib import suppress
from datetime import timedelta
from flufl.lock import Lock, TimeOutError
from mailbox import Maildir
+from mailman import public
from mailman.config import config
from mailman.interfaces.archiver import IArchiver
from zope.interface import implementer
@@ -37,7 +39,7 @@ from zope.interface import implementer
log = logging.getLogger('mailman.error')
-
+@public
@implementer(IArchiver)
class Prototype:
"""A prototype of a third party archiver.
@@ -68,13 +70,8 @@ class Prototype:
This archiver saves messages into a maildir.
"""
archive_dir = os.path.join(config.ARCHIVE_DIR, 'prototype')
- try:
+ with suppress(FileExistsError):
os.makedirs(archive_dir, 0o775)
- except OSError as error:
- # If this already exists, then we're fine
- if error.errno != errno.EEXIST:
- raise
-
# Maildir will throw an error if the directories are partially created
# (for instance the toplevel exists but cur, new, or tmp do not)
# therefore we don't create the toplevel as we did above.
diff --git a/src/mailman/model/address.py b/src/mailman/model/address.py
index b632f54e1..f33a7ef46 100644
--- a/src/mailman/model/address.py
+++ b/src/mailman/model/address.py
@@ -17,11 +17,6 @@
"""Model for addresses."""
-__all__ = [
- 'Address',
- ]
-
-
from email.utils import formataddr
from mailman.database.model import Model
from mailman.interfaces.address import (
@@ -34,7 +29,11 @@ from zope.event import notify
from zope.interface import implementer
-
+__all__ = [
+ 'Address',
+ ]
+
+
@implementer(IAddress)
class Address(Model):
"""See `IAddress`."""
diff --git a/src/mailman/model/autorespond.py b/src/mailman/model/autorespond.py
index 08a014fd2..00c329ff5 100644
--- a/src/mailman/model/autorespond.py
+++ b/src/mailman/model/autorespond.py
@@ -15,13 +15,7 @@
# You should have received a copy of the GNU General Public License along with
# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
-"""Module stuff."""
-
-__all__ = [
- 'AutoResponseRecord',
- 'AutoResponseSet',
- ]
-
+"""Autoresponder records."""
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
@@ -33,8 +27,13 @@ from sqlalchemy import Column, Date, ForeignKey, Integer, desc
from sqlalchemy.orm import relationship
from zope.interface import implementer
+__all__ = [
+ 'AutoResponseRecord',
+ 'AutoResponseSet',
+ ]
+
+
-
@implementer(IAutoResponseRecord)
class AutoResponseRecord(Model):
"""See `IAutoResponseRecord`."""
@@ -59,7 +58,6 @@ class AutoResponseRecord(Model):
self.date_sent = today()
-
@implementer(IAutoResponseSet)
class AutoResponseSet:
"""See `IAutoResponseSet`."""
diff --git a/src/mailman/model/bans.py b/src/mailman/model/bans.py
index a2a52a657..e81a7a01a 100644
--- a/src/mailman/model/bans.py
+++ b/src/mailman/model/bans.py
@@ -17,11 +17,6 @@
"""Ban manager."""
-__all__ = [
- 'BanManager',
- ]
-
-
import re
from mailman.database.model import Model
@@ -30,8 +25,11 @@ from mailman.interfaces.bans import IBan, IBanManager
from sqlalchemy import Column, Integer, Unicode
from zope.interface import implementer
+__all__ = [
+ 'BanManager',
+ ]
+
-
@implementer(IBan)
class Ban(Model):
"""See `IBan`."""
@@ -48,7 +46,6 @@ class Ban(Model):
self.list_id = list_id
-
@implementer(IBanManager)
class BanManager:
"""See `IBanManager`."""
diff --git a/src/mailman/model/bounce.py b/src/mailman/model/bounce.py
index 3ccf58091..544907ad5 100644
--- a/src/mailman/model/bounce.py
+++ b/src/mailman/model/bounce.py
@@ -17,13 +17,6 @@
"""Bounce support."""
-__all__ = [
- 'BounceEvent',
- 'BounceProcessor',
- ]
-
-
-
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import Enum
@@ -34,7 +27,6 @@ from sqlalchemy import Boolean, Column, DateTime, Integer, Unicode
from zope.interface import implementer
-
@implementer(IBounceEvent)
class BounceEvent(Model):
"""See `IBounceEvent`."""
@@ -59,7 +51,6 @@ class BounceEvent(Model):
self.processed = False
-
@implementer(IBounceProcessor)
class BounceProcessor:
"""See `IBounceProcessor`."""
diff --git a/src/mailman/model/digests.py b/src/mailman/model/digests.py
index e5a49a8a7..39eef0c6f 100644
--- a/src/mailman/model/digests.py
+++ b/src/mailman/model/digests.py
@@ -17,11 +17,6 @@
"""One last digest."""
-__all__ = [
- 'OneLastDigest',
- ]
-
-
from mailman.database.model import Model
from mailman.database.types import Enum
from mailman.interfaces.digests import IOneLastDigest
@@ -30,8 +25,11 @@ from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship
from zope.interface import implementer
+__all__ = [
+ 'OneLastDigest',
+ ]
+
-
@implementer(IOneLastDigest)
class OneLastDigest(Model):
"""See `IOneLastDigest`."""
diff --git a/src/mailman/model/domain.py b/src/mailman/model/domain.py
index 7fb6d6821..fb73bf470 100644
--- a/src/mailman/model/domain.py
+++ b/src/mailman/model/domain.py
@@ -17,12 +17,6 @@
"""Domains."""
-__all__ = [
- 'Domain',
- 'DomainManager',
- ]
-
-
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.interfaces.domain import (
@@ -38,8 +32,12 @@ from zope.event import notify
from zope.interface import implementer
from zope.component import getUtility
+__all__ = [
+ 'Domain',
+ 'DomainManager',
+ ]
+
-
@implementer(IDomain)
class Domain(Model):
"""Domains."""
@@ -136,7 +134,6 @@ class Domain(Model):
self.owners.remove(user_manager.get_user(owner))
-
@implementer(IDomainManager)
class DomainManager:
"""Domain manager."""
diff --git a/src/mailman/model/language.py b/src/mailman/model/language.py
index 33b0e2ef4..fd51f9522 100644
--- a/src/mailman/model/language.py
+++ b/src/mailman/model/language.py
@@ -17,18 +17,16 @@
"""Model for languages."""
-__all__ = [
- 'Language',
- ]
-
-
from mailman.database.model import Model
from mailman.interfaces.languages import ILanguage
from sqlalchemy import Column, Integer, Unicode
from zope.interface import implementer
+__all__ = [
+ 'Language',
+ ]
+
-
@implementer(ILanguage)
class Language(Model):
"""See `ILanguage`."""
diff --git a/src/mailman/model/listmanager.py b/src/mailman/model/listmanager.py
index 45f91bb6a..074b6b600 100644
--- a/src/mailman/model/listmanager.py
+++ b/src/mailman/model/listmanager.py
@@ -17,11 +17,6 @@
"""A mailing list manager."""
-__all__ = [
- 'ListManager',
- ]
-
-
from mailman.database.transaction import dbconnection
from mailman.interfaces.address import InvalidEmailAddressError
from mailman.interfaces.listmanager import (
@@ -36,8 +31,11 @@ from mailman.utilities.datetime import now
from zope.event import notify
from zope.interface import implementer
+__all__ = [
+ 'ListManager',
+ ]
+
-
@implementer(IListManager)
class ListManager:
"""An implementation of the `IListManager` interface."""
diff --git a/src/mailman/model/mailinglist.py b/src/mailman/model/mailinglist.py
index 5b015e5b5..8e4df5f50 100644
--- a/src/mailman/model/mailinglist.py
+++ b/src/mailman/model/mailinglist.py
@@ -17,11 +17,6 @@
"""Model for mailing lists."""
-__all__ = [
- 'MailingList',
- ]
-
-
import os
from mailman.config import config
@@ -65,6 +60,10 @@ from zope.component import getUtility
from zope.event import notify
from zope.interface import implementer
+__all__ = [
+ 'MailingList',
+ ]
+
SPACE = ' '
UNDERSCORE = '_'
diff --git a/src/mailman/model/member.py b/src/mailman/model/member.py
index 1fb11218d..ecd1c3d9e 100644
--- a/src/mailman/model/member.py
+++ b/src/mailman/model/member.py
@@ -17,11 +17,6 @@
"""Model for members."""
-__all__ = [
- 'Member',
- ]
-
-
from mailman.core.constants import system_preferences
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
@@ -40,11 +35,15 @@ from zope.component import getUtility
from zope.event import notify
from zope.interface import implementer
+__all__ = [
+ 'Member',
+ ]
+
+
uid_factory = UIDFactory(context='members')
-
@implementer(IMember)
class Member(Model):
"""See `IMember`."""
diff --git a/src/mailman/rules/administrivia.py b/src/mailman/rules/administrivia.py
index abb6527a2..b4656d33f 100644
--- a/src/mailman/rules/administrivia.py
+++ b/src/mailman/rules/administrivia.py
@@ -17,17 +17,16 @@
"""The administrivia rule."""
-__all__ = [
- 'Administrivia',
- ]
-
-
from email.iterators import typed_subpart_iterator
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'Administrivia',
+ ]
+
# The list of email commands we search for in the Subject header and payload.
# We probably should get this information from the actual implemented
@@ -48,7 +47,6 @@ EMAIL_COMMANDS = {
}
-
@implementer(IRule)
class Administrivia:
"""The administrivia rule."""
diff --git a/src/mailman/rules/any.py b/src/mailman/rules/any.py
index e71b18639..67504875c 100644
--- a/src/mailman/rules/any.py
+++ b/src/mailman/rules/any.py
@@ -17,17 +17,15 @@
"""Check if any previous rules have matched."""
-__all__ = [
- 'Any',
- ]
-
-
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'Any',
+ ]
+
-
@implementer(IRule)
class Any:
"""Look for any previous rule match."""
diff --git a/src/mailman/rules/approved.py b/src/mailman/rules/approved.py
index 3d16b44f9..cb3b98915 100644
--- a/src/mailman/rules/approved.py
+++ b/src/mailman/rules/approved.py
@@ -17,11 +17,6 @@
"""Look for moderator pre-approval."""
-__all__ = [
- 'Approved',
- ]
-
-
import re
from email.iterators import typed_subpart_iterator
@@ -30,6 +25,10 @@ from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'Approved',
+ ]
+
EMPTYSTRING = ''
HEADERS = [
@@ -40,7 +39,6 @@ HEADERS = [
]
-
@implementer(IRule)
class Approved:
"""Look for moderator pre-approval."""
@@ -134,7 +132,6 @@ class Approved:
return is_valid
-
def reset_payload(part, payload):
# Set decoded payload maintaining content-type, charset, format and delsp.
charset = part.get_content_charset() or 'us-ascii'
diff --git a/src/mailman/rules/emergency.py b/src/mailman/rules/emergency.py
index 5f2208109..f6dacfe37 100644
--- a/src/mailman/rules/emergency.py
+++ b/src/mailman/rules/emergency.py
@@ -17,17 +17,15 @@
"""The emergency hold rule."""
-__all__ = [
- 'Emergency',
- ]
-
-
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'Emergency',
+ ]
+
-
@implementer(IRule)
class Emergency:
"""The emergency hold rule."""
diff --git a/src/mailman/rules/implicit_dest.py b/src/mailman/rules/implicit_dest.py
index 484bd6a40..6d75ba637 100644
--- a/src/mailman/rules/implicit_dest.py
+++ b/src/mailman/rules/implicit_dest.py
@@ -17,11 +17,6 @@
"""The implicit destination rule."""
-__all__ = [
- 'ImplicitDestination',
- ]
-
-
import re
from email.utils import getaddresses
@@ -30,8 +25,11 @@ from mailman.interfaces.mailinglist import IAcceptableAliasSet
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'ImplicitDestination',
+ ]
+
-
@implementer(IRule)
class ImplicitDestination:
"""The implicit destination rule."""
diff --git a/src/mailman/rules/loop.py b/src/mailman/rules/loop.py
index 4c5b00c0f..280939a74 100644
--- a/src/mailman/rules/loop.py
+++ b/src/mailman/rules/loop.py
@@ -17,17 +17,15 @@
"""Look for a posting loop."""
-__all__ = [
- 'Loop',
- ]
-
-
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'Loop',
+ ]
+
-
@implementer(IRule)
class Loop:
"""Look for a posting loop."""
diff --git a/src/mailman/rules/max_recipients.py b/src/mailman/rules/max_recipients.py
index 8557aca44..3d4fa139f 100644
--- a/src/mailman/rules/max_recipients.py
+++ b/src/mailman/rules/max_recipients.py
@@ -17,18 +17,16 @@
"""The maximum number of recipients rule."""
-__all__ = [
- 'MaximumRecipients',
- ]
-
-
from email.utils import getaddresses
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'MaximumRecipients',
+ ]
+
-
@implementer(IRule)
class MaximumRecipients:
"""The maximum number of recipients rule."""
diff --git a/src/mailman/rules/max_size.py b/src/mailman/rules/max_size.py
index a4d5785d8..0ed781a38 100644
--- a/src/mailman/rules/max_size.py
+++ b/src/mailman/rules/max_size.py
@@ -17,17 +17,15 @@
"""The maximum message size rule."""
-__all__ = [
- 'MaximumSize',
- ]
-
-
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'MaximumSize',
+ ]
+
-
@implementer(IRule)
class MaximumSize:
"""The implicit destination rule."""
diff --git a/src/mailman/rules/moderation.py b/src/mailman/rules/moderation.py
index ecf5cc8bf..b89e7c9c2 100644
--- a/src/mailman/rules/moderation.py
+++ b/src/mailman/rules/moderation.py
@@ -17,12 +17,6 @@
"""Membership related rules."""
-__all__ = [
- 'MemberModeration',
- 'NonmemberModeration',
- ]
-
-
import re
from mailman.core.i18n import _
@@ -33,8 +27,12 @@ from mailman.interfaces.usermanager import IUserManager
from zope.component import getUtility
from zope.interface import implementer
+__all__ = [
+ 'MemberModeration',
+ 'NonmemberModeration',
+ ]
+
-
@implementer(IRule)
class MemberModeration:
"""The member moderation rule."""
@@ -65,7 +63,6 @@ class MemberModeration:
return False
-
def _record_action(msgdata, action, sender, reason):
msgdata['moderation_action'] = action
msgdata['moderation_sender'] = sender
@@ -88,13 +85,13 @@ class NonmemberModeration:
# list, make them nonmembers.
for sender in msg.senders:
if (mlist.members.get_member(sender) is None and
- mlist.nonmembers.get_member(sender) is None):
+ mlist.nonmembers.get_member(sender) is None):
# The address is neither a member nor nonmember.
address = user_manager.get_address(sender)
assert address is not None, (
'Posting address is not registered: {0}'.format(sender))
mlist.subscribe(address, MemberRole.nonmember)
- ## # If a member is found, the member-moderation rule takes precedence.
+ # If a member is found, the member-moderation rule takes precedence.
for sender in msg.senders:
if mlist.members.get_member(sender) is not None:
return False
diff --git a/src/mailman/rules/news_moderation.py b/src/mailman/rules/news_moderation.py
index e408043bb..2feeed4a1 100644
--- a/src/mailman/rules/news_moderation.py
+++ b/src/mailman/rules/news_moderation.py
@@ -17,18 +17,16 @@
"""The news moderation rule."""
-__all__ = [
- 'ModeratedNewsgroup',
- ]
-
-
from mailman.core.i18n import _
from mailman.interfaces.nntp import NewsgroupModeration
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'ModeratedNewsgroup',
+ ]
+
-
@implementer(IRule)
class ModeratedNewsgroup:
"""The news moderation rule."""
diff --git a/src/mailman/rules/no_subject.py b/src/mailman/rules/no_subject.py
index 0348be5c5..ff63d8c37 100644
--- a/src/mailman/rules/no_subject.py
+++ b/src/mailman/rules/no_subject.py
@@ -17,17 +17,15 @@
"""The no-Subject header rule."""
-__all__ = [
- 'NoSubject',
- ]
-
-
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'NoSubject',
+ ]
+
-
@implementer(IRule)
class NoSubject:
"""The no-Subject rule."""
diff --git a/src/mailman/rules/suspicious.py b/src/mailman/rules/suspicious.py
index f7dc50ab4..d385ea490 100644
--- a/src/mailman/rules/suspicious.py
+++ b/src/mailman/rules/suspicious.py
@@ -17,11 +17,6 @@
"""The historical 'suspicious header' rule."""
-__all__ = [
- 'SuspiciousHeader',
- ]
-
-
import re
import logging
@@ -29,11 +24,14 @@ from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'SuspiciousHeader',
+ ]
+
log = logging.getLogger('mailman.error')
-
@implementer(IRule)
class SuspiciousHeader:
"""The historical 'suspicious header' rule."""
@@ -48,7 +46,6 @@ class SuspiciousHeader:
has_matching_bounce_header(mlist, msg))
-
def _parse_matching_header_opt(mlist):
"""Return a list of triples [(field name, regex, line), ...]."""
# - Blank lines and lines with '#' as first char are skipped.
diff --git a/src/mailman/rules/tests/test_approved.py b/src/mailman/rules/tests/test_approved.py
index 401e26634..62d67c848 100644
--- a/src/mailman/rules/tests/test_approved.py
+++ b/src/mailman/rules/tests/test_approved.py
@@ -17,15 +17,6 @@
"""Test the `approved` handler."""
-__all__ = [
- 'TestApproved',
- 'TestApprovedNonASCII',
- 'TestApprovedPseudoHeader',
- 'TestApprovedPseudoHeaderMIME',
- 'TestPasswordHashMigration',
- ]
-
-
import os
import unittest
@@ -37,7 +28,6 @@ from mailman.testing.helpers import (
from mailman.testing.layers import ConfigLayer
-
class TestApproved(unittest.TestCase):
"""Test the approved handler."""
@@ -145,7 +135,6 @@ A message body.
self.assertFalse(result)
-
class TestApprovedPseudoHeader(unittest.TestCase):
"""Test the approved handler."""
@@ -278,7 +267,6 @@ X-Approve: not the password
self.assertFalse('X-Approve' in self._msg.get_payload())
-
class TestApprovedPseudoHeaderMIME(unittest.TestCase):
"""Test the approved handler."""
@@ -392,7 +380,6 @@ An important message.
self.assertFalse('X-Approve' in msg.get_payload(1).get_payload())
-
class TestApprovedNonASCII(unittest.TestCase):
"""Test the approved handler with non-ascii messages."""
@@ -514,7 +501,6 @@ deprecated = roundup_plaintext
'{plaintext}super secret')
-
class TestApprovedNoTextPlainPart(unittest.TestCase):
"""Test the approved handler with HTML-only messages."""
diff --git a/src/mailman/rules/tests/test_moderation.py b/src/mailman/rules/tests/test_moderation.py
index 655e92863..df1658792 100644
--- a/src/mailman/rules/tests/test_moderation.py
+++ b/src/mailman/rules/tests/test_moderation.py
@@ -17,11 +17,6 @@
"""Test the `member-moderation` and `nonmember-moderation` rules."""
-__all__ = [
- 'TestModeration',
- ]
-
-
import unittest
from mailman.app.lifecycle import create_list
@@ -34,7 +29,6 @@ from mailman.testing.layers import ConfigLayer
from zope.component import getUtility
-
class TestModeration(unittest.TestCase):
"""Test the approved handler."""
@@ -147,5 +141,6 @@ A message body.
result = rule.check(self._mlist, msg, msgdata)
self.assertTrue(result, 'NonmemberModeration rule should hit')
self.assertIn('moderation_action', msgdata)
- self.assertEqual(msgdata['moderation_action'], action_name,
+ self.assertEqual(
+ msgdata['moderation_action'], action_name,
'Wrong action for {}: {}'.format(address, action_name))
diff --git a/src/mailman/rules/truth.py b/src/mailman/rules/truth.py
index 3189c233a..16b2e1893 100644
--- a/src/mailman/rules/truth.py
+++ b/src/mailman/rules/truth.py
@@ -17,17 +17,15 @@
"""A rule which always matches."""
-__all__ = [
- 'Truth',
- ]
-
-
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
from zope.interface import implementer
+__all__ = [
+ 'Truth',
+ ]
+
-
@implementer(IRule)
class Truth:
"""Look for any previous rule match."""
diff --git a/src/mailman/version.py b/src/mailman/version.py
index 32431d756..229bb7fba 100644
--- a/src/mailman/version.py
+++ b/src/mailman/version.py
@@ -23,10 +23,10 @@ CODENAME = 'Between The Wheels'
# And as a hex number in the manner of PY_VERSION_HEX.
ALPHA = 0xa
-BETA = 0xb
+BETA = 0xb # flake8: noqa
GAMMA = 0xc
# Release candidates.
-RC = GAMMA
+RC = GAMMA # flake8: noqa
FINAL = 0xf
MAJOR_REV = 3
@@ -37,7 +37,7 @@ REL_LEVEL = ALPHA
REL_SERIAL = 1
HEX_VERSION = ((MAJOR_REV << 24) | (MINOR_REV << 16) | (MICRO_REV << 8) |
- (REL_LEVEL << 4) | (REL_SERIAL << 0))
+ (REL_LEVEL << 4) | (REL_SERIAL << 0)) # flake8: noqa
# queue/*.pck schema version number.