diff options
Diffstat (limited to 'src')
32 files changed, 156 insertions, 381 deletions
diff --git a/src/mailman/app/tests/test_membership.py b/src/mailman/app/tests/test_membership.py index 113ae6a52..a22a239b7 100644 --- a/src/mailman/app/tests/test_membership.py +++ b/src/mailman/app/tests/test_membership.py @@ -137,17 +137,14 @@ class AddMemberTest(unittest.TestCase): 'Anne Person', '123', DeliveryMode.regular, system_preferences.preferred_language, MemberRole.member) - try: + with self.assertRaises(AlreadySubscribedError) as cm: add_member(self._mlist, 'aperson@example.com', 'Anne Person', '123', DeliveryMode.regular, system_preferences.preferred_language, MemberRole.member) - except AlreadySubscribedError as exc: - self.assertEqual(exc.fqdn_listname, 'test@example.com') - self.assertEqual(exc.email, 'aperson@example.com') - self.assertEqual(exc.role, MemberRole.member) - else: - raise AssertionError('AlreadySubscribedError expected') + self.assertEqual(cm.exception.fqdn_listname, 'test@example.com') + self.assertEqual(cm.exception.email, 'aperson@example.com') + self.assertEqual(cm.exception.role, MemberRole.member) def test_add_member_with_different_roles(self): # Adding a member twice with different roles is okay. diff --git a/src/mailman/app/tests/test_subscriptions.py b/src/mailman/app/tests/test_subscriptions.py index 1c37d4cb9..c4c8f2795 100644 --- a/src/mailman/app/tests/test_subscriptions.py +++ b/src/mailman/app/tests/test_subscriptions.py @@ -51,19 +51,13 @@ class TestJoin(unittest.TestCase): def test_join_user_with_bogus_id(self): # When `subscriber` is a missing user id, an exception is raised. - try: + with self.assertRaises(MissingUserError) as cm: self._service.join('test.example.com', uuid.UUID(int=99)) - except MissingUserError as exc: - self.assertEqual(exc.user_id, uuid.UUID(int=99)) - else: - raise AssertionError('MissingUserError expected') + self.assertEqual(cm.exception.user_id, uuid.UUID(int=99)) def test_join_user_with_invalid_email_address(self): # When `subscriber` is a string that is not an email address, an # exception is raised. - try: + with self.assertRaises(InvalidEmailAddressError) as cm: self._service.join('test.example.com', 'bogus') - except InvalidEmailAddressError as exc: - self.assertEqual(exc.email, 'bogus') - else: - raise AssertionError('InvalidEmailAddressError expected') + self.assertEqual(cm.exception.email, 'bogus') diff --git a/src/mailman/app/tests/test_templates.py b/src/mailman/app/tests/test_templates.py index 6dfbd7109..788412a57 100644 --- a/src/mailman/app/tests/test_templates.py +++ b/src/mailman/app/tests/test_templates.py @@ -98,49 +98,31 @@ class TestTemplateLoader(unittest.TestCase): self.assertEqual(content, 'Test content') def test_uri_not_found(self): - try: + with self.assertRaises(urllib2.URLError) as cm: self._loader.get('mailman:///missing.txt') - except urllib2.URLError as error: - self.assertEqual(error.reason, 'No such file') - else: - raise AssertionError('Exception expected') + self.assertEqual(cm.exception.reason, 'No such file') def test_shorter_url_error(self): - try: + with self.assertRaises(urllib2.URLError) as cm: self._loader.get('mailman:///') - except urllib2.URLError as error: - self.assertEqual(error.reason, 'No template specified') - else: - raise AssertionError('Exception expected') + self.assertEqual(cm.exception.reason, 'No template specified') def test_short_url_error(self): - try: + with self.assertRaises(urllib2.URLError) as cm: self._loader.get('mailman://') - except urllib2.URLError as error: - self.assertEqual(error.reason, 'No template specified') - else: - raise AssertionError('Exception expected') + self.assertEqual(cm.exception.reason, 'No template specified') def test_bad_language(self): - try: + with self.assertRaises(urllib2.URLError) as cm: self._loader.get('mailman:///xx/demo.txt') - except urllib2.URLError as error: - self.assertEqual(error.reason, 'Bad language or list name') - else: - raise AssertionError('Exception expected') + self.assertEqual(cm.exception.reason, 'Bad language or list name') def test_bad_mailing_list(self): - try: + with self.assertRaises(urllib2.URLError) as cm: self._loader.get('mailman:///missing@example.com/demo.txt') - except urllib2.URLError as error: - self.assertEqual(error.reason, 'Bad language or list name') - else: - raise AssertionError('Exception expected') + self.assertEqual(cm.exception.reason, 'Bad language or list name') def test_too_many_path_components(self): - try: + with self.assertRaises(urllib2.URLError) as cm: self._loader.get('mailman:///missing@example.com/en/foo/demo.txt') - except urllib2.URLError as error: - self.assertEqual(error.reason, 'No such file') - else: - raise AssertionError('Exception expected') + self.assertEqual(cm.exception.reason, 'No such file') diff --git a/src/mailman/chains/tests/test_headers.py b/src/mailman/chains/tests/test_headers.py index 65a23d891..e8856031c 100644 --- a/src/mailman/chains/tests/test_headers.py +++ b/src/mailman/chains/tests/test_headers.py @@ -44,8 +44,6 @@ class TestHeaderChain(unittest.TestCase): def setUp(self): self._mlist = create_list('test@example.com') - # Python 2.6 does not have assertListEqual(). - self._leq = getattr(self, 'assertListEqual', self.assertEqual) @configuration('antispam', header_checks=""" Foo: a+ @@ -71,7 +69,7 @@ class TestHeaderChain(unittest.TestCase): self.assertEqual(link.rule.name[:13], 'header-match-') self.assertEqual(link.action, LinkAction.defer) post_checks.append((link.rule.header, link.rule.pattern)) - self._leq(post_checks, [ + self.assertListEqual(post_checks, [ ('Foo', 'a+'), ('Bar', 'bb?'), ]) @@ -103,7 +101,7 @@ class TestHeaderChain(unittest.TestCase): self.assertEqual(link.rule.name[:13], 'header-match-') self.assertEqual(link.action, LinkAction.defer) post_checks.append((link.rule.header, link.rule.pattern)) - self._leq(post_checks, [ + self.assertListEqual(post_checks, [ ('Foo', 'foo'), ('Bar', 'bar'), ]) diff --git a/src/mailman/core/errors.py b/src/mailman/core/errors.py index 95a318ca6..42b536d46 100644 --- a/src/mailman/core/errors.py +++ b/src/mailman/core/errors.py @@ -90,6 +90,12 @@ def _(s): class HandlerError(MailmanError): """Base class for all handler errors.""" + def __init__(self, message=None): + self.message = message + + def __str__(self): + return self.message + class HoldMessage(HandlerError): """Base class for all message-being-held short circuits.""" diff --git a/src/mailman/core/logging.py b/src/mailman/core/logging.py index af04b58d1..2442d4913 100644 --- a/src/mailman/core/logging.py +++ b/src/mailman/core/logging.py @@ -40,8 +40,8 @@ _handlers = {} -# XXX I would love to simplify things and use Python 2.6's WatchedFileHandler, -# but there are two problems. First, it's more difficult to handle the test +# XXX I would love to simplify things and use Python's WatchedFileHandler, but +# there are two problems. First, it's more difficult to handle the test # suite's need to reopen the file handler to a different path. Does # zope.testing's logger support fix this? # diff --git a/src/mailman/core/tests/test_runner.py b/src/mailman/core/tests/test_runner.py index ad2548adc..80a503f5d 100644 --- a/src/mailman/core/tests/test_runner.py +++ b/src/mailman/core/tests/test_runner.py @@ -81,7 +81,7 @@ Message-ID: <ant> self.assertEqual(event.message['message-id'], '<ant>') self.assertEqual(event.metadata['listname'], 'test@example.com') self.assertTrue(isinstance(event.error, RuntimeError)) - self.assertEqual(event.error.message, 'borked') + self.assertEqual(str(event.error), 'borked') self.assertTrue(isinstance(event.runner, CrashingRunner)) # The message should also have ended up in the shunt queue. shunted = get_queue_messages('shunt') diff --git a/src/mailman/docs/INTRODUCTION.rst b/src/mailman/docs/INTRODUCTION.rst index 11d13c239..8e334c08a 100644 --- a/src/mailman/docs/INTRODUCTION.rst +++ b/src/mailman/docs/INTRODUCTION.rst @@ -82,7 +82,7 @@ lists and archives, etc., are available at: Requirements ============ -Mailman 3.0 requires `Python 2.6`_ or newer. +Mailman 3.0 requires `Python 2.7`_ or newer. .. _`GNU Mailman`: http://www.list.org @@ -90,4 +90,4 @@ Mailman 3.0 requires `Python 2.6`_ or newer. .. _`Getting Started`: START.html .. _Python: http://www.python.org .. _FAQ: http://wiki.list.org/display/DOC/Frequently+Asked+Questions -.. _`Python 2.6`: http://www.python.org/download/releases/2.6.6/ +.. _`Python 2.7`: http://www.python.org/download/releases/2.7.3/ diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst index 11f52a3de..892cc52c4 100644 --- a/src/mailman/docs/NEWS.rst +++ b/src/mailman/docs/NEWS.rst @@ -12,6 +12,11 @@ Here is a history of user visible changes to Mailman. ========================== (2012-XX-XX) +Compatibility +------------- + * Python 2.7 is not required. Python 2.6 is no longer officially supported. + LP: #1073506 + REST ---- * Add list_id to JSON representation for a mailing list (given by Jimmy diff --git a/src/mailman/docs/START.rst b/src/mailman/docs/START.rst index da76feae0..dbf4966c4 100644 --- a/src/mailman/docs/START.rst +++ b/src/mailman/docs/START.rst @@ -32,14 +32,13 @@ mailman-developers@python.org mailing list. Requirements ============ -Python 2.6 or 2.7 is required. It can either be the default 'python' on your -$PATH or it can be accessible via the ``python2.6`` or ``python2.7`` binary. +Python 2.7 is required. It can either be the default 'python' on your +$PATH or it can be accessible via the ``python2.7`` binary. If your operating system does not include Python, see http://www.python.org downloading and installing it from source. Python 3 is not yet supported. In this documentation, a bare ``python`` refers to the Python executable used -to invoke ``bootstrap.py``, which might be ``python2.6`` or ``python2.7``, as -well as the system ``python`` or an absolute path. +to invoke ``bootstrap.py``. Mailman 3 is now based on the `zc.buildout`_ infrastructure, which greatly simplifies building and testing Mailman. diff --git a/src/mailman/docs/STYLEGUIDE.rst b/src/mailman/docs/STYLEGUIDE.rst index b744c6557..29661701b 100644 --- a/src/mailman/docs/STYLEGUIDE.rst +++ b/src/mailman/docs/STYLEGUIDE.rst @@ -15,7 +15,7 @@ http://barry.warsaw.us/software/STYLEGUIDE.txt This document contains a style guide for Python programming, as used in GNU Mailman. `PEP 8`_ is the basis for this style guide so it's recommendations should be followed except for the differences outlined here. This document -assumes the use of Python 2.6 or 2.7, but not (yet) Python 3. +assumes the use of Python 2.7, but not (yet) Python 3. * After file comments (e.g. license block), add a ``__metaclass__`` definition so that all classes will be new-style. Following that, add an ``__all__`` diff --git a/src/mailman/docs/WebUIin5.rst b/src/mailman/docs/WebUIin5.rst index 56f2df9fb..6419e4752 100644 --- a/src/mailman/docs/WebUIin5.rst +++ b/src/mailman/docs/WebUIin5.rst @@ -7,8 +7,8 @@ Mailman 3's web UI, called Postorius. If all goes as planned, you should be done within 5 minutes. This has been tested on Ubuntu 11.04. In order to download the components necessary you need to have the `Bazaar`_ -version control system installed on your system. Mailman and mailman.client -need at least Python version 2.6. +version control system installed on your system. Mailman requires Python 2.7, +while mailman.client needs at least Python version 2.6. It's probably a good idea to set up a virtual Python environment using `virtualenv`_. `Here is a brief HOWTO`_. diff --git a/src/mailman/email/message.py b/src/mailman/email/message.py index dcea82425..601d4f839 100644 --- a/src/mailman/email/message.py +++ b/src/mailman/email/message.py @@ -219,11 +219,7 @@ class UserNotification(Message): if mlist is not None: enqueue_kws['listname'] = mlist.fqdn_listname enqueue_kws.update(_kws) - # Keywords must be strings in Python 2.6. - str_keywords = dict() - for key, val in enqueue_kws.items(): - str_keywords[str(key)] = val - virginq.enqueue(self, **str_keywords) + virginq.enqueue(self, **enqueue_kws) diff --git a/src/mailman/handlers/tests/test_mimedel.py b/src/mailman/handlers/tests/test_mimedel.py index 6ca34b17b..74790fbf7 100644 --- a/src/mailman/handlers/tests/test_mimedel.py +++ b/src/mailman/handlers/tests/test_mimedel.py @@ -37,8 +37,7 @@ from mailman.interfaces.action import FilterAction from mailman.interfaces.member import MemberRole from mailman.interfaces.usermanager import IUserManager from mailman.testing.helpers import ( - LogFileMark, - get_queue_messages, + LogFileMark, configuration, get_queue_messages, specialized_message_from_string as mfs) from mailman.testing.layers import ConfigLayer @@ -71,25 +70,17 @@ Message-ID: <ant> def test_dispose_discard(self): self._mlist.filter_action = FilterAction.discard - try: + with self.assertRaises(errors.DiscardMessage) as cm: mime_delete.dispose(self._mlist, self._msg, {}, 'discarding') - except errors.DiscardMessage as error: - pass - else: - raise AssertionError('DiscardMessage exception expected') - self.assertEqual(error.message, 'discarding') + self.assertEqual(cm.exception.message, 'discarding') # There should be no messages in the 'bad' queue. self.assertEqual(len(get_queue_messages('bad')), 0) def test_dispose_bounce(self): self._mlist.filter_action = FilterAction.reject - try: + with self.assertRaises(errors.RejectMessage) as cm: mime_delete.dispose(self._mlist, self._msg, {}, 'rejecting') - except errors.RejectMessage as error: - pass - else: - raise AssertionError('RejectMessage exception expected') - self.assertEqual(error.message, 'rejecting') + self.assertEqual(cm.exception.message, 'rejecting') # There should be no messages in the 'bad' queue. self.assertEqual(len(get_queue_messages('bad')), 0) @@ -103,13 +94,9 @@ Message-ID: <ant> self._mlist.subscribe(bart, MemberRole.moderator) # Now set the filter action and dispose the message. self._mlist.filter_action = FilterAction.forward - try: + with self.assertRaises(errors.DiscardMessage) as cm: mime_delete.dispose(self._mlist, self._msg, {}, 'forwarding') - except errors.DiscardMessage as error: - pass - else: - raise AssertionError('DiscardMessage exception expected') - self.assertEqual(error.message, 'forwarding') + self.assertEqual(cm.exception.message, 'forwarding') # There should now be a multipart message in the virgin queue destined # for the mailing list owners. messages = get_queue_messages('virgin') @@ -143,46 +130,28 @@ message. self.assertEqual(original['subject'], 'A disposable message') self.assertEqual(original['message-id'], '<ant>') + @configuration('mailman', filtered_messages_are_preservable='no') def test_dispose_non_preservable(self): # Two actions can happen here, depending on a site-wide setting. If # the site owner has indicated that filtered messages cannot be # preserved, then this is the same as discarding them. self._mlist.filter_action = FilterAction.preserve - config.push('non-preservable', """ - [mailman] - filtered_messages_are_preservable: no - """) - try: + with self.assertRaises(errors.DiscardMessage) as cm: mime_delete.dispose(self._mlist, self._msg, {}, 'not preserved') - except errors.DiscardMessage as error: - pass - else: - raise AssertionError('DiscardMessage exception expected') - finally: - config.pop('non-preservable') - self.assertEqual(error.message, 'not preserved') + self.assertEqual(cm.exception.message, 'not preserved') # There should be no messages in the 'bad' queue. self.assertEqual(len(get_queue_messages('bad')), 0) + @configuration('mailman', filtered_messages_are_preservable='yes') def test_dispose_preservable(self): # Two actions can happen here, depending on a site-wide setting. If # the site owner has indicated that filtered messages can be # preserved, then this is similar to discarding the message except # that a copy is preserved in the 'bad' queue. self._mlist.filter_action = FilterAction.preserve - config.push('preservable', """ - [mailman] - filtered_messages_are_preservable: yes - """) - try: + with self.assertRaises(errors.DiscardMessage) as cm: mime_delete.dispose(self._mlist, self._msg, {}, 'preserved') - except errors.DiscardMessage as error: - pass - else: - raise AssertionError('DiscardMessage exception expected') - finally: - config.pop('preservable') - self.assertEqual(error.message, 'preserved') + self.assertEqual(cm.exception.message, 'preserved') # There should be no messages in the 'bad' queue. messages = get_queue_messages('bad') self.assertEqual(len(messages), 1) @@ -200,13 +169,9 @@ message. FilterAction.defer): self._mlist.filter_action = action mark = LogFileMark('mailman.error') - try: + with self.assertRaises(errors.DiscardMessage) as cm: mime_delete.dispose(self._mlist, self._msg, {}, 'bad action') - except errors.DiscardMessage as error: - pass - else: - raise AssertionError('DiscardMessage exception expected') - self.assertEqual(error.message, 'bad action') + self.assertEqual(cm.exception.message, 'bad action') line = mark.readline()[:-1] self.assertTrue(line.endswith( '{0} invalid FilterAction: test@example.com. ' diff --git a/src/mailman/interfaces/address.py b/src/mailman/interfaces/address.py index 54bf6b283..7df15b91f 100644 --- a/src/mailman/interfaces/address.py +++ b/src/mailman/interfaces/address.py @@ -47,11 +47,7 @@ class EmailError(MailmanError): self.email = email def __str__(self): - # This is a workaround for Python 2.6 support. When self.email - # contains non-ascii characters, this will cause unprintable output in - # doctests. Python 2.7 can handle it but we haven't dropped support - # for 2.6 yet. - return self.email.encode('us-ascii', 'backslashreplace') + return self.email class AddressError(MailmanError): diff --git a/src/mailman/model/docs/listmanager.rst b/src/mailman/model/docs/listmanager.rst index 380fe7704..41450b15d 100644 --- a/src/mailman/model/docs/listmanager.rst +++ b/src/mailman/model/docs/listmanager.rst @@ -126,8 +126,7 @@ address components. test_3@example.com test_4@example.com - >>> for list_name, mail_host in sorted(list_manager.name_components, - ... key=lambda (name, host): name): + >>> for list_name, mail_host in sorted(list_manager.name_components): ... print list_name, '@', mail_host test @ example.com test_3 @ example.com diff --git a/src/mailman/rest/tests/test_addresses.py b/src/mailman/rest/tests/test_addresses.py index 01ce710b2..35a19f77f 100644 --- a/src/mailman/rest/tests/test_addresses.py +++ b/src/mailman/rest/tests/test_addresses.py @@ -48,34 +48,24 @@ class TestAddresses(unittest.TestCase): def test_membership_of_missing_address(self): # Try to get the memberships of a missing address. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/addresses/' 'nobody@example.com/memberships') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError 404') + self.assertEqual(cm.exception.code, 404) def test_verify_a_missing_address(self): # POSTing to the 'verify' sub-resource returns a 404. - try: + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/addresses/' 'nobody@example.com/verify', {}) - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError 404') + self.assertEqual(cm.exception.code, 404) def test_unverify_a_missing_address(self): # POSTing to the 'unverify' sub-resource returns a 404. - try: + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/addresses/' 'nobody@example.com/unverify', {}) - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError 404') + self.assertEqual(cm.exception.code, 404) def test_verify_already_verified(self): # It's okay to verify an already verified; it just doesn't change the @@ -105,23 +95,17 @@ class TestAddresses(unittest.TestCase): with transaction(): anne = getUtility(IUserManager).create_address('anne@example.com') self.assertEqual(anne.verified_on, None) - try: + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/addresses/' 'anne@example.com/verify/foo', {}) - except HTTPError as exc: - self.assertEqual(exc.code, 400) - else: - raise AssertionError('Expected HTTPError 400') + self.assertEqual(cm.exception.code, 400) def test_unverify_bad_request(self): # Too many segments after /verify. with transaction(): anne = getUtility(IUserManager).create_address('anne@example.com') self.assertEqual(anne.verified_on, None) - try: + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/addresses/' 'anne@example.com/unverify/foo', {}) - except HTTPError as exc: - self.assertEqual(exc.code, 400) - else: - raise AssertionError('Expected HTTPError 400') + self.assertEqual(cm.exception.code, 400) diff --git a/src/mailman/rest/tests/test_domains.py b/src/mailman/rest/tests/test_domains.py index a86768481..dea6a0aa6 100644 --- a/src/mailman/rest/tests/test_domains.py +++ b/src/mailman/rest/tests/test_domains.py @@ -47,24 +47,16 @@ class TestDomains(unittest.TestCase): def test_bogus_endpoint_extension(self): # /domains/<domain>/lists/<anything> is not a valid endpoint. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/domains/example.com' '/lists/wrong') - except HTTPError as exc: - self.assertEqual(exc.code, 400) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 400) def test_bogus_endpoint(self): # /domains/<domain>/<!lists> does not exist. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/domains/example.com/wrong') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) def test_lists_are_deleted_when_domain_is_deleted(self): # /domains/<domain> DELETE removes all associated mailing lists. diff --git a/src/mailman/rest/tests/test_lists.py b/src/mailman/rest/tests/test_lists.py index cd0ebaf8e..9686ce6a8 100644 --- a/src/mailman/rest/tests/test_lists.py +++ b/src/mailman/rest/tests/test_lists.py @@ -46,47 +46,31 @@ class TestListsMissing(unittest.TestCase): def test_missing_list_roster_member_404(self): # /lists/<missing>/roster/member gives 404 - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/lists/missing@example.com' '/roster/member') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) def test_missing_list_roster_owner_404(self): # /lists/<missing>/roster/owner gives 404 - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/lists/missing@example.com' '/roster/owner') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) def test_missing_list_roster_moderator_404(self): # /lists/<missing>/roster/member gives 404 - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/lists/missing@example.com' '/roster/moderator') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) def test_missing_list_configuration_404(self): # /lists/<missing>/config gives 404 - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api( 'http://localhost:9001/3.0/lists/missing@example.com/config') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) diff --git a/src/mailman/rest/tests/test_membership.py b/src/mailman/rest/tests/test_membership.py index 18469e537..3bbe821ac 100644 --- a/src/mailman/rest/tests/test_membership.py +++ b/src/mailman/rest/tests/test_membership.py @@ -50,41 +50,29 @@ class TestMembership(unittest.TestCase): def test_try_to_join_missing_list(self): # A user tries to join a non-existent list. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/members', { 'list_id': 'missing.example.com', 'subscriber': 'nobody@example.com', }) - except HTTPError as exc: - self.assertEqual(exc.code, 400) - self.assertEqual(exc.msg, 'No such list') - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 400) + self.assertEqual(cm.exception.msg, 'No such list') def test_try_to_leave_missing_list(self): # A user tries to leave a non-existent list. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/lists/missing@example.com' '/member/nobody@example.com', method='DELETE') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - self.assertEqual(exc.msg, '404 Not Found') - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) + self.assertEqual(cm.exception.msg, '404 Not Found') def test_try_to_leave_list_with_bogus_address(self): # Try to leave a mailing list using an invalid membership address. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/members/1', method='DELETE') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - self.assertEqual(exc.msg, '404 Not Found') - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) + self.assertEqual(cm.exception.msg, '404 Not Found') def test_try_to_leave_a_list_twice(self): with transaction(): @@ -96,45 +84,34 @@ class TestMembership(unittest.TestCase): # content. self.assertEqual(content, None) self.assertEqual(response.status, 204) - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api(url, method='DELETE') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - self.assertEqual(exc.msg, '404 Not Found') - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) + self.assertEqual(cm.exception.msg, '404 Not Found') def test_try_to_join_a_list_twice(self): with transaction(): anne = self._usermanager.create_address('anne@example.com') self._mlist.subscribe(anne) - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/members', { 'list_id': 'test.example.com', 'subscriber': 'anne@example.com', }) - except HTTPError as exc: - self.assertEqual(exc.code, 409) - self.assertEqual(exc.msg, 'Member already subscribed') - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 409) + self.assertEqual(cm.exception.msg, 'Member already subscribed') def test_join_with_invalid_delivery_mode(self): - try: + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/members', { 'list_id': 'test.example.com', 'subscriber': 'anne@example.com', 'display_name': 'Anne Person', 'delivery_mode': 'invalid-mode', }) - except HTTPError as exc: - self.assertEqual(exc.code, 400) - self.assertEqual(exc.msg, - 'Cannot convert parameters: delivery_mode') - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 400) + self.assertEqual(cm.exception.msg, + 'Cannot convert parameters: delivery_mode') def test_join_email_contains_slash(self): content, response = call_api('http://localhost:9001/3.0/members', { @@ -196,47 +173,31 @@ class TestMembership(unittest.TestCase): def test_get_nonexistent_member(self): # /members/<bogus> returns 404 - try: - # For Python 2.6 + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/members/bogus') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) def test_patch_nonexistent_member(self): # /members/<missing> PATCH returns 404 - try: - # For Python 2.6 + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/members/801', method='PATCH') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) def test_patch_member_bogus_attribute(self): # /members/<id> PATCH 'bogus' returns 400 with transaction(): anne = self._usermanager.create_address('anne@example.com') self._mlist.subscribe(anne) - try: - # For Python 2.6 + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/members/1', { 'powers': 'super', }, method='PATCH') - except HTTPError as exc: - self.assertEqual(exc.code, 400) - self.assertEqual(exc.msg, 'Unexpected parameters: powers') - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 400) + self.assertEqual(cm.exception.msg, 'Unexpected parameters: powers') def test_member_all_without_preferences(self): # /members/<id>/all should return a 404 when it isn't trailed by # `preferences` - try: - # For Python 2.6 + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/members/1/all') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) diff --git a/src/mailman/rest/tests/test_moderation.py b/src/mailman/rest/tests/test_moderation.py index dfcedef05..2ee796c87 100644 --- a/src/mailman/rest/tests/test_moderation.py +++ b/src/mailman/rest/tests/test_moderation.py @@ -56,24 +56,16 @@ Something else. def test_not_found(self): # When a bogus mailing list is given, 404 should result. - try: - # For Python 2.6 + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/lists/bee@example.com/held') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) def test_bad_request_id(self): # Bad request when request_id is not an integer. - try: - # For Python 2.6 + with self.assertRaises(HTTPError) as cm: call_api( 'http://localhost:9001/3.0/lists/ant@example.com/held/bogus') - except HTTPError as exc: - self.assertEqual(exc.code, 400) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 400) def test_subscription_request_as_held_message(self): # Provide the request id of a subscription request using the held @@ -85,12 +77,9 @@ Something else. DeliveryMode.regular, 'en') config.db.store.commit() url = 'http://localhost:9001/3.0/lists/ant@example.com/held/{0}' - try: + with self.assertRaises(HTTPError) as cm: call_api(url.format(subscribe_id)) - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) # But using the held_id returns a valid response. response, content = call_api(url.format(held_id)) self.assertEqual(response['key'], '<alpha>') @@ -99,10 +88,7 @@ Something else. # POSTing to a held message with a bad action. held_id = hold_message(self._mlist, self._msg) url = 'http://localhost:9001/3.0/lists/ant@example.com/held/{0}' - try: + with self.assertRaises(HTTPError) as cm: call_api(url.format(held_id), {'action': 'bogus'}) - except HTTPError as exc: - self.assertEqual(exc.code, 400) - self.assertEqual(exc.msg, 'Cannot convert parameters: action') - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 400) + self.assertEqual(cm.exception.msg, 'Cannot convert parameters: action') diff --git a/src/mailman/rest/tests/test_root.py b/src/mailman/rest/tests/test_root.py index 90d30bd80..4a9ba0dd1 100644 --- a/src/mailman/rest/tests/test_root.py +++ b/src/mailman/rest/tests/test_root.py @@ -38,38 +38,25 @@ class TestSystem(unittest.TestCase): def test_system_url_too_long(self): # /system/foo/bar is not allowed. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/system/foo/bar') - except HTTPError as exc: - self.assertEqual(exc.code, 400) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 400) def test_system_url_not_preferences(self): # /system/foo where `foo` is not `preferences`. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/system/foo') - except HTTPError as exc: - self.assertEqual(exc.code, 400) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 400) def test_system_preferences_are_read_only(self): # /system/preferences are read-only. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/system/preferences', { 'acknowledge_posts': True, }, method='PATCH') - except HTTPError as exc: - self.assertEqual(exc.code, 405) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 405) # /system/preferences are read-only. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/system/preferences', { 'acknowledge_posts': False, 'delivery_mode': 'regular', @@ -79,7 +66,4 @@ class TestSystem(unittest.TestCase): 'receive_list_copy': True, 'receive_own_postings': True, }, method='PUT') - except HTTPError as exc: - self.assertEqual(exc.code, 405) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 405) diff --git a/src/mailman/rest/tests/test_users.py b/src/mailman/rest/tests/test_users.py index 301027885..4595c69d8 100644 --- a/src/mailman/rest/tests/test_users.py +++ b/src/mailman/rest/tests/test_users.py @@ -45,10 +45,6 @@ class TestUsers(unittest.TestCase): def test_delete_bogus_user(self): # Try to delete a user that does not exist. - try: - # For Python 2.6. + with self.assertRaises(HTTPError) as cm: call_api('http://localhost:9001/3.0/users/99', method='DELETE') - except HTTPError as exc: - self.assertEqual(exc.code, 404) - else: - raise AssertionError('Expected HTTPError') + self.assertEqual(cm.exception.code, 404) diff --git a/src/mailman/rules/administrivia.py b/src/mailman/rules/administrivia.py index 4c49e4ff2..6f5f41cd3 100644 --- a/src/mailman/rules/administrivia.py +++ b/src/mailman/rules/administrivia.py @@ -84,7 +84,7 @@ class Administrivia: if len(line) == 0: continue lineno += 1 - if lineno > config.mailman.email_commands_max_lines: + if lineno > int(config.mailman.email_commands_max_lines): break lines_to_check.append(line) # Only look at the first text/plain part. diff --git a/src/mailman/runners/digest.py b/src/mailman/runners/digest.py index 99710dff5..f87dd4e76 100644 --- a/src/mailman/runners/digest.py +++ b/src/mailman/runners/digest.py @@ -318,9 +318,9 @@ class DigestRunner(Runner): """See `IRunner`.""" volume = msgdata['volume'] digest_number = msgdata['digest_number'] - with nested(Mailbox(msgdata['digest_path']), - _.using(mlist.preferred_language.code)) as (mailbox, - language_code): + # Backslashes make me cry. + with Mailbox(msgdata['digest_path']) as mailbox, \ + _.using(mlist.preferred_language.code): # Create the digesters. mime_digest = MIMEDigester(mlist, volume, digest_number) rfc1153_digest = RFC1153Digester(mlist, volume, digest_number) @@ -354,7 +354,7 @@ class DigestRunner(Runner): # receive. digest_members = set(mlist.digest_members.members) for member in digest_members: - if member.delivery_status <> DeliveryStatus.enabled: + if member.delivery_status is not DeliveryStatus.enabled: continue # Send the digest to the case-preserved address of the digest # members. diff --git a/src/mailman/runners/tests/test_confirm.py b/src/mailman/runners/tests/test_confirm.py index 62171979c..78f6a382c 100644 --- a/src/mailman/runners/tests/test_confirm.py +++ b/src/mailman/runners/tests/test_confirm.py @@ -28,6 +28,7 @@ __all__ = [ import unittest from datetime import datetime +from email.iterators import body_line_iterator from zope.component import getUtility from mailman.app.lifecycle import create_list @@ -37,7 +38,6 @@ from mailman.interfaces.registrar import IRegistrar from mailman.interfaces.usermanager import IUserManager from mailman.runners.command import CommandRunner from mailman.testing.helpers import ( - body_line_iterator, get_queue_messages, make_testable_runner, specialized_message_from_string as mfs) diff --git a/src/mailman/runners/tests/test_join.py b/src/mailman/runners/tests/test_join.py index a584fd2c2..41adcc450 100644 --- a/src/mailman/runners/tests/test_join.py +++ b/src/mailman/runners/tests/test_join.py @@ -28,6 +28,7 @@ __all__ = [ import unittest +from email.iterators import body_line_iterator from zope.component import getUtility from mailman.app.lifecycle import create_list @@ -38,10 +39,7 @@ from mailman.interfaces.subscriptions import ISubscriptionService from mailman.interfaces.usermanager import IUserManager from mailman.runners.command import CommandRunner from mailman.testing.helpers import ( - body_line_iterator, - get_queue_messages, - make_testable_runner, - reset_the_world, + get_queue_messages, make_testable_runner, reset_the_world, specialized_message_from_string as mfs) from mailman.testing.layers import ConfigLayer diff --git a/src/mailman/runners/tests/test_lmtp.py b/src/mailman/runners/tests/test_lmtp.py index 46d4ed986..a502c317d 100644 --- a/src/mailman/runners/tests/test_lmtp.py +++ b/src/mailman/runners/tests/test_lmtp.py @@ -53,22 +53,19 @@ class TestLMTP(unittest.TestCase): def test_message_id_required(self): # The message is rejected if it does not have a Message-ID header. - try: + with self.assertRaises(smtplib.SMTPDataError) as cm: self._lmtp.sendmail('anne@example.com', ['test@example.com'], """\ From: anne@example.com To: test@example.com Subject: This has no Message-ID header """) - except smtplib.SMTPDataError as error: - pass - else: - raise AssertionError('SMTPDataError expected') # LMTP returns a 550: Requested action not taken: mailbox unavailable # (e.g., mailbox not found, no access, or command rejected for policy # reasons) - self.assertEqual(error.smtp_code, 550) - self.assertEqual(error.smtp_error, 'No Message-ID header provided') + self.assertEqual(cm.exception.smtp_code, 550) + self.assertEqual(cm.exception.smtp_error, + 'No Message-ID header provided') def test_message_id_hash_is_added(self): self._lmtp.sendmail('anne@example.com', ['test@example.com'], """\ diff --git a/src/mailman/styles/tests/test_styles.py b/src/mailman/styles/tests/test_styles.py index 990ce541f..a2ffc931f 100644 --- a/src/mailman/styles/tests/test_styles.py +++ b/src/mailman/styles/tests/test_styles.py @@ -63,28 +63,16 @@ class TestStyle(unittest.TestCase): # Registering a style with the same name as a previous style raises an # exception. self.manager.register(DummyStyle()) - try: - self.manager.register(DummyStyle()) - except DuplicateStyleError: - pass - else: - raise AssertionError('DuplicateStyleError exception expected') + self.assertRaises(DuplicateStyleError, + self.manager.register, DummyStyle()) def test_register_a_non_style(self): # You can't register something that doesn't implement the IStyle # interface. - try: - self.manager.register(object()) - except DoesNotImplement: - pass - else: - raise AssertionError('DoesNotImplement exception expected') + self.assertRaises(DoesNotImplement, + self.manager.register, object()) def test_unregister_a_non_registered_style(self): # You cannot unregister a style that hasn't yet been registered. - try: - self.manager.unregister(DummyStyle()) - except KeyError: - pass - else: - raise AssertionError('KeyError expected') + self.assertRaises(KeyError, + self.manager.unregister, DummyStyle()) diff --git a/src/mailman/testing/helpers.py b/src/mailman/testing/helpers.py index 054dd4ff7..99f4b8961 100644 --- a/src/mailman/testing/helpers.py +++ b/src/mailman/testing/helpers.py @@ -249,8 +249,8 @@ def get_lmtp_client(quiet=False): if not quiet: print(response) return lmtp - except socket.error as error: - if error[0] == errno.ECONNREFUSED: + except IOError as error: + if error.errno == errno.ECONNREFUSED: time.sleep(0.1) else: raise @@ -284,8 +284,8 @@ def wait_for_webservice(): try: socket.socket().connect((config.webservice.hostname, int(config.webservice.port))) - except socket.error as error: - if error[0] == errno.ECONNREFUSED: + except IOError as error: + if error.errno == errno.ECONNREFUSED: time.sleep(0.1) else: raise @@ -515,19 +515,3 @@ class LogFileMark: with open(self._filename) as fp: fp.seek(self._filepos) return fp.readline() - - - -# In Python 2.6, body_line_iterator() uses a cStringIO.StringIO() which cannot -# handle unicode. In Python 2.7 this works fine. I hate version checks but -# this is the easiest way to handle it. OTOH, we could just use the manual -# way for all Python versions instead. -import sys -if sys.hexversion >= 0x2070000: - from email.iterators import body_line_iterator -else: - def body_line_iterator(msg, decode=False): - payload = msg.get_payload(decode=decode) - bytes_payload = payload.encode('utf-8') - for line in bytes_payload.splitlines(): - yield line diff --git a/src/mailman/utilities/string.py b/src/mailman/utilities/string.py index 7470bd476..cd3adc536 100644 --- a/src/mailman/utilities/string.py +++ b/src/mailman/utilities/string.py @@ -60,19 +60,7 @@ def expand(template, substitutions, template_class=Template): :return: The substituted string. :rtype: string """ - # Python 2.6 requires ** dictionaries to have str, not unicode keys, so - # convert as necessary. Note that string.Template uses **. For our - # purposes, keys should always be ascii. Values though can be anything. - cooked = substitutions.__class__() - for key in substitutions: - if isinstance(key, unicode): - key = key.encode('ascii') - cooked[key] = substitutions[key] - try: - return template_class(template).safe_substitute(cooked) - except (TypeError, ValueError): - # The template is really screwed up. - log.exception('broken template: %s', template) + return template_class(template).safe_substitute(substitutions) diff --git a/src/mailman/utilities/tests/test_templates.py b/src/mailman/utilities/tests/test_templates.py index d205eef34..8e335f69b 100644 --- a/src/mailman/utilities/tests/test_templates.py +++ b/src/mailman/utilities/tests/test_templates.py @@ -224,13 +224,9 @@ class TestFind(unittest.TestCase): self.assertEqual(self.fp.read(), 'List template') def test_template_not_found(self): - # Python 2.6 compatibility. - try: + with self.assertRaises(TemplateNotFoundError) as cm: find('missing.txt', self.mlist) - except TemplateNotFoundError as error: - self.assertEqual(error.template_file, 'missing.txt') - else: - raise AssertionError('TemplateNotFoundError expected') + self.assertEqual(cm.exception.template_file, 'missing.txt') |
