diff options
| author | Barry Warsaw | 2016-03-23 23:40:54 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2016-03-23 23:40:54 -0400 |
| commit | f51c63ca108134dd30f26641bef15bfcddd6e502 (patch) | |
| tree | b3cc41a2d54d11f62886db7ceab3985b9bee18f1 /src | |
| parent | ab2b619db5f3de47cffc2740901c4f82958a7d96 (diff) | |
| download | mailman-f51c63ca108134dd30f26641bef15bfcddd6e502.tar.gz mailman-f51c63ca108134dd30f26641bef15bfcddd6e502.tar.zst mailman-f51c63ca108134dd30f26641bef15bfcddd6e502.zip | |
Diffstat (limited to 'src')
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. |
