From 36d114b37755ef96c4b0215feabe5095237c15e2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard
Date: Wed, 30 Mar 2016 12:07:22 +0200
Subject: Cover another header match import case
---
src/mailman/utilities/importer.py | 2 +-
src/mailman/utilities/tests/test_import.py | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/mailman/utilities/importer.py b/src/mailman/utilities/importer.py
index c908a2ada..b2138cb9b 100644
--- a/src/mailman/utilities/importer.py
+++ b/src/mailman/utilities/importer.py
@@ -336,7 +336,7 @@ def import_config_pck(mlist, config_dict):
for line_pattern in line_patterns.splitlines():
if len(line_pattern.strip()) == 0:
continue
- for sep in (': ', ':.', ':'):
+ for sep in (': ', ':.*', ':.', ':'):
header, sep, pattern = line_pattern.partition(sep)
if sep:
# We found it.
diff --git a/src/mailman/utilities/tests/test_import.py b/src/mailman/utilities/tests/test_import.py
index d2729e8e1..0d245d594 100644
--- a/src/mailman/utilities/tests/test_import.py
+++ b/src/mailman/utilities/tests/test_import.py
@@ -336,6 +336,7 @@ class TestBasicImport(unittest.TestCase):
('^Subject: dev-\r\n^Subject: staging-', 3, False),
('from: .*info@aolanchem.com\r\nfrom: .*@jw-express.com',
2, False),
+ ('^Subject:.*\\Wwas:\\W', 3, False),
('^Received: from smtp-.*\\.fedoraproject\\.org\r\n'
'^Received: from mx.*\\.redhat.com\r\n'
'^Resent-date:\r\n'
@@ -372,6 +373,7 @@ class TestBasicImport(unittest.TestCase):
('subject', 'staging-', 'discard'),
('from', '.*info@aolanchem.com', 'reject'),
('from', '.*@jw-express.com', 'reject'),
+ ('subject', '\\Wwas:\\W', 'discard'),
('received', 'from smtp-.*\\.fedoraproject\\.org', 'hold'),
('received', 'from mx.*\\.redhat.com', 'hold'),
('resent-date', '.*', 'hold'),
--
cgit v1.3.1
From a8f2fc64c683420f40bac1b4c5d551305a0e0ecc Mon Sep 17 00:00:00 2001
From: Aurélien Bompard
Date: Mon, 18 Jan 2016 18:25:03 +0100
Subject: Don't show the disabled archivers in the REST API
Because one can't add a configuration overlay to the running REST server
in testing mode, the prototype archiver was disabled in the testing
configuration. This is where most of the changes in this commit come
from.
---
src/mailman/rest/docs/lists.rst | 4 ----
src/mailman/rest/lists.py | 6 ++++--
src/mailman/rest/tests/test_lists.py | 10 ++++------
src/mailman/testing/testing.cfg | 2 +-
4 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/src/mailman/rest/docs/lists.rst b/src/mailman/rest/docs/lists.rst
index 6554b04c2..0fb877722 100644
--- a/src/mailman/rest/docs/lists.rst
+++ b/src/mailman/rest/docs/lists.rst
@@ -250,7 +250,6 @@ archivers are available, and whether they are enabled for this mailing list.
http_etag: "..."
mail-archive: True
mhonarc: True
- prototype: True
You can set all the archiver states by putting new state flags on the
resource.
@@ -260,7 +259,6 @@ resource.
... 'http://localhost:9001/3.0/lists/dog@example.com/archivers', {
... 'mail-archive': False,
... 'mhonarc': True,
- ... 'prototype': False,
... }, method='PUT')
content-length: 0
date: ...
@@ -271,7 +269,6 @@ resource.
http_etag: "..."
mail-archive: False
mhonarc: True
- prototype: False
You can change the state of a subset of the list archivers.
::
@@ -289,7 +286,6 @@ You can change the state of a subset of the list archivers.
http_etag: "..."
mail-archive: False
mhonarc: False
- prototype: False
List digests
diff --git a/src/mailman/rest/lists.py b/src/mailman/rest/lists.py
index c3919c001..8e82cd1a4 100644
--- a/src/mailman/rest/lists.py
+++ b/src/mailman/rest/lists.py
@@ -330,13 +330,15 @@ class ListArchivers:
"""Get all the archiver statuses."""
archiver_set = IListArchiverSet(self._mlist)
resource = {archiver.name: archiver.is_enabled
- for archiver in archiver_set.archivers}
+ for archiver in archiver_set.archivers
+ if archiver.system_archiver.is_enabled}
okay(response, etag(resource))
def patch_put(self, request, response, is_optional):
archiver_set = IListArchiverSet(self._mlist)
kws = {archiver.name: ArchiverGetterSetter(self._mlist)
- for archiver in archiver_set.archivers}
+ for archiver in archiver_set.archivers
+ if archiver.system_archiver.is_enabled}
if is_optional:
# For a PATCH, all attributes are optional.
kws['_optional'] = kws.keys()
diff --git a/src/mailman/rest/tests/test_lists.py b/src/mailman/rest/tests/test_lists.py
index 787009855..d83f70058 100644
--- a/src/mailman/rest/tests/test_lists.py
+++ b/src/mailman/rest/tests/test_lists.py
@@ -32,7 +32,7 @@ from mailman.interfaces.usermanager import IUserManager
from mailman.model.mailinglist import AcceptableAlias
from mailman.runners.digest import DigestRunner
from mailman.testing.helpers import (
- call_api, get_queue_messages, make_testable_runner,
+ call_api, configuration, get_queue_messages, make_testable_runner,
specialized_message_from_string as mfs)
from mailman.testing.layers import RESTLayer
from mailman.utilities.datetime import now as right_now
@@ -339,7 +339,6 @@ class TestListArchivers(unittest.TestCase):
self.assertEqual(resource, {
'mail-archive': True,
'mhonarc': True,
- 'prototype': True,
})
def test_archiver_statuses_on_missing_lists(self):
@@ -375,7 +374,7 @@ class TestListArchivers(unittest.TestCase):
def test_put_incomplete_statuses(self):
# PUT requires the full resource representation. This one forgets to
- # specify the prototype and mhonarc archiver.
+ # specify the mhonarc archiver.
with self.assertRaises(HTTPError) as cm:
call_api(
'http://localhost:9001/3.0/lists/ant.example.com/archivers', {
@@ -384,7 +383,7 @@ class TestListArchivers(unittest.TestCase):
method='PUT')
self.assertEqual(cm.exception.code, 400)
self.assertEqual(cm.exception.reason,
- b'Missing parameters: mhonarc, prototype')
+ b'Missing parameters: mhonarc')
def test_patch_bogus_status(self):
# Archiver statuses must be interpretable as booleans.
@@ -392,8 +391,7 @@ class TestListArchivers(unittest.TestCase):
call_api(
'http://localhost:9001/3.0/lists/ant.example.com/archivers', {
'mail-archive': 'sure',
- 'mhonarc': False,
- 'prototype': 'no'
+ 'mhonarc': 'no'
},
method='PATCH')
self.assertEqual(cm.exception.code, 400)
diff --git a/src/mailman/testing/testing.cfg b/src/mailman/testing/testing.cfg
index 022f9f289..8b6a48c36 100644
--- a/src/mailman/testing/testing.cfg
+++ b/src/mailman/testing/testing.cfg
@@ -65,7 +65,7 @@ max_restarts: 1
max_restarts: 1
[archiver.prototype]
-enable: yes
+enable: no
[archiver.mail_archive]
enable: yes
--
cgit v1.3.1
From accc4f1a883d4a5757eb9b0156e58e72b77a8af7 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard
Date: Thu, 21 Jan 2016 11:46:49 +0100
Subject: Fix tests
---
src/mailman/config/tests/test_archivers.py | 6 +++---
src/mailman/model/tests/test_mailinglist.py | 14 +++++++-------
src/mailman/rest/tests/test_lists.py | 2 +-
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/mailman/config/tests/test_archivers.py b/src/mailman/config/tests/test_archivers.py
index 322a5040d..b09b89273 100644
--- a/src/mailman/config/tests/test_archivers.py
+++ b/src/mailman/config/tests/test_archivers.py
@@ -28,11 +28,11 @@ class TestArchivers(unittest.TestCase):
layer = ConfigLayer
def test_enabled(self):
- # By default, the testing configuration enables the archivers.
+ # By default, the testing configuration enables some archivers.
archivers = {}
for archiver in config.archivers:
archivers[archiver.name] = archiver
- self.assertTrue(archivers['prototype'].is_enabled)
+ self.assertFalse(archivers['prototype'].is_enabled)
self.assertTrue(archivers['mail-archive'].is_enabled)
self.assertTrue(archivers['mhonarc'].is_enabled)
@@ -42,6 +42,6 @@ class TestArchivers(unittest.TestCase):
archivers = {}
for archiver in config.archivers:
archivers[archiver.name] = archiver
- self.assertTrue(archivers['prototype'].is_enabled)
+ self.assertFalse(archivers['prototype'].is_enabled)
self.assertTrue(archivers['mail-archive'].is_enabled)
self.assertFalse(archivers['mhonarc'].is_enabled)
diff --git a/src/mailman/model/tests/test_mailinglist.py b/src/mailman/model/tests/test_mailinglist.py
index c9aecc93b..0f37fa2f3 100644
--- a/src/mailman/model/tests/test_mailinglist.py
+++ b/src/mailman/model/tests/test_mailinglist.py
@@ -108,11 +108,11 @@ class TestListArchiver(unittest.TestCase):
def test_get_archiver(self):
# Use .get() to see if a mailing list has an archiver.
- archiver = self._set.get('prototype')
- self.assertEqual(archiver.name, 'prototype')
+ archiver = self._set.get('mhonarc')
+ self.assertEqual(archiver.name, 'mhonarc')
self.assertTrue(archiver.is_enabled)
self.assertEqual(archiver.mailing_list, self._mlist)
- self.assertEqual(archiver.system_archiver.name, 'prototype')
+ self.assertEqual(archiver.system_archiver.name, 'mhonarc')
def test_get_archiver_no_such(self):
# Using .get() on a non-existing name returns None.
@@ -124,15 +124,15 @@ class TestListArchiver(unittest.TestCase):
# then the site-wide archiver gets disabled, so the list specific
# archiver will also be disabled.
archiver_set = IListArchiverSet(self._mlist)
- archiver = archiver_set.get('prototype')
+ archiver = archiver_set.get('mhonarc')
self.assertTrue(archiver.is_enabled)
# Disable the site-wide archiver.
- config.push('enable prototype', """\
- [archiver.prototype]
+ config.push('enable mhonarc', """\
+ [archiver.mhonarc]
enable: no
""")
self.assertFalse(archiver.is_enabled)
- config.pop('enable prototype')
+ config.pop('enable mhonarc')
class TestDisabledListArchiver(unittest.TestCase):
diff --git a/src/mailman/rest/tests/test_lists.py b/src/mailman/rest/tests/test_lists.py
index d83f70058..3bee23314 100644
--- a/src/mailman/rest/tests/test_lists.py
+++ b/src/mailman/rest/tests/test_lists.py
@@ -32,7 +32,7 @@ from mailman.interfaces.usermanager import IUserManager
from mailman.model.mailinglist import AcceptableAlias
from mailman.runners.digest import DigestRunner
from mailman.testing.helpers import (
- call_api, configuration, get_queue_messages, make_testable_runner,
+ call_api, get_queue_messages, make_testable_runner,
specialized_message_from_string as mfs)
from mailman.testing.layers import RESTLayer
from mailman.utilities.datetime import now as right_now
--
cgit v1.3.1
From 228e70d799ab9e37ed0d42dd96b9126d77e20d45 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 22 Nov 2016 09:43:49 -0500
Subject: Start porting to Python 3.6
---
BREAKS.rst | 5 +++++
src/mailman/handlers/subject_prefix.py | 2 +-
tox.ini | 2 +-
3 files changed, 7 insertions(+), 2 deletions(-)
create mode 100644 BREAKS.rst
diff --git a/BREAKS.rst b/BREAKS.rst
new file mode 100644
index 000000000..020126ad1
--- /dev/null
+++ b/BREAKS.rst
@@ -0,0 +1,5 @@
+======================
+ Python 3.6 breakages
+======================
+
+* https://bugs.python.org/issue27030
diff --git a/src/mailman/handlers/subject_prefix.py b/src/mailman/handlers/subject_prefix.py
index ff728d92e..5dcfe410a 100644
--- a/src/mailman/handlers/subject_prefix.py
+++ b/src/mailman/handlers/subject_prefix.py
@@ -158,7 +158,7 @@ class SubjectPrefix:
prefix_pattern = re.escape(prefix)
# Unescape '%'.
prefix_pattern = '%'.join(prefix_pattern.split(r'\%'))
- p = re.compile('%\d*d')
+ p = re.compile(r'%\d*d')
if p.search(prefix, 1):
# The prefix has number, so we should search prefix w/number in
# subject. Also, force new style.
diff --git a/tox.ini b/tox.ini
index c015cc699..7892b557a 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = {py34,py35}{,-coverage,-diffcov}{,-pg}{,-mysql},qa
+envlist = {py34,py35,py36}{,-coverage,-diffcov}{,-pg}{,-mysql},qa
recreate = True
skip_missing_interpreters = True
--
cgit v1.3.1
From 2ca7f91cf4a95cfb91152d0cb8fa342e1883b534 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 22 Nov 2016 13:22:25 -0500
Subject: Back out the last change.
---
src/mailman/handlers/subject_prefix.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mailman/handlers/subject_prefix.py b/src/mailman/handlers/subject_prefix.py
index 5dcfe410a..ff728d92e 100644
--- a/src/mailman/handlers/subject_prefix.py
+++ b/src/mailman/handlers/subject_prefix.py
@@ -158,7 +158,7 @@ class SubjectPrefix:
prefix_pattern = re.escape(prefix)
# Unescape '%'.
prefix_pattern = '%'.join(prefix_pattern.split(r'\%'))
- p = re.compile(r'%\d*d')
+ p = re.compile('%\d*d')
if p.search(prefix, 1):
# The prefix has number, so we should search prefix w/number in
# subject. Also, force new style.
--
cgit v1.3.1
From 40b586facc07f71be4fd65a1b06af93681ba0441 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 22 Nov 2016 15:52:34 -0500
Subject: A couple of fixes for Python 3.6
---
src/mailman/handlers/subject_prefix.py | 2 +-
src/mailman/testing/mta.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/mailman/handlers/subject_prefix.py b/src/mailman/handlers/subject_prefix.py
index ff728d92e..20f47fc5d 100644
--- a/src/mailman/handlers/subject_prefix.py
+++ b/src/mailman/handlers/subject_prefix.py
@@ -162,7 +162,7 @@ class SubjectPrefix:
if p.search(prefix, 1):
# The prefix has number, so we should search prefix w/number in
# subject. Also, force new style.
- prefix_pattern = p.sub(r'\s*\d+\s*', prefix_pattern)
+ prefix_pattern = p.sub(r'\\s*\\d+\\s*', prefix_pattern)
# Substitute %d in prefix with post_id
with suppress(TypeError):
prefix = prefix % mlist.post_id
diff --git a/src/mailman/testing/mta.py b/src/mailman/testing/mta.py
index c1327f428..fbbb890d8 100644
--- a/src/mailman/testing/mta.py
+++ b/src/mailman/testing/mta.py
@@ -183,7 +183,7 @@ class ConnectionCountingServer(QueueServer):
log.info('[ConnectionCountingServer] accepted: %s', address)
StatisticsChannel(self, connection, address)
- def process_message(self, peer, mailfrom, rcpttos, data):
+ def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
# Provide a guaranteed order to recpttos.
QueueServer.process_message(
self, peer, mailfrom, sorted(rcpttos), data)
--
cgit v1.3.1
From 2bcab3d589de9b16ca7b9405b452fd47e2c094b0 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 22 Nov 2016 09:43:49 -0500
Subject: Start porting to Python 3.6
---
BREAKS.rst | 5 +++++
src/mailman/handlers/subject_prefix.py | 2 +-
tox.ini | 2 +-
3 files changed, 7 insertions(+), 2 deletions(-)
create mode 100644 BREAKS.rst
diff --git a/BREAKS.rst b/BREAKS.rst
new file mode 100644
index 000000000..020126ad1
--- /dev/null
+++ b/BREAKS.rst
@@ -0,0 +1,5 @@
+======================
+ Python 3.6 breakages
+======================
+
+* https://bugs.python.org/issue27030
diff --git a/src/mailman/handlers/subject_prefix.py b/src/mailman/handlers/subject_prefix.py
index ff728d92e..5dcfe410a 100644
--- a/src/mailman/handlers/subject_prefix.py
+++ b/src/mailman/handlers/subject_prefix.py
@@ -158,7 +158,7 @@ class SubjectPrefix:
prefix_pattern = re.escape(prefix)
# Unescape '%'.
prefix_pattern = '%'.join(prefix_pattern.split(r'\%'))
- p = re.compile('%\d*d')
+ p = re.compile(r'%\d*d')
if p.search(prefix, 1):
# The prefix has number, so we should search prefix w/number in
# subject. Also, force new style.
diff --git a/tox.ini b/tox.ini
index c015cc699..7892b557a 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = {py34,py35}{,-coverage,-diffcov}{,-pg}{,-mysql},qa
+envlist = {py34,py35,py36}{,-coverage,-diffcov}{,-pg}{,-mysql},qa
recreate = True
skip_missing_interpreters = True
--
cgit v1.3.1
From f638cc15a9db75c2a97758d67e5829293e8765bf Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 22 Nov 2016 13:22:25 -0500
Subject: Back out the last change.
---
src/mailman/handlers/subject_prefix.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mailman/handlers/subject_prefix.py b/src/mailman/handlers/subject_prefix.py
index 5dcfe410a..ff728d92e 100644
--- a/src/mailman/handlers/subject_prefix.py
+++ b/src/mailman/handlers/subject_prefix.py
@@ -158,7 +158,7 @@ class SubjectPrefix:
prefix_pattern = re.escape(prefix)
# Unescape '%'.
prefix_pattern = '%'.join(prefix_pattern.split(r'\%'))
- p = re.compile(r'%\d*d')
+ p = re.compile('%\d*d')
if p.search(prefix, 1):
# The prefix has number, so we should search prefix w/number in
# subject. Also, force new style.
--
cgit v1.3.1
From 867c7e562b82015a4fd38b45e875691cb06ea134 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 22 Nov 2016 15:52:34 -0500
Subject: A couple of fixes for Python 3.6
---
src/mailman/handlers/subject_prefix.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mailman/handlers/subject_prefix.py b/src/mailman/handlers/subject_prefix.py
index ff728d92e..20f47fc5d 100644
--- a/src/mailman/handlers/subject_prefix.py
+++ b/src/mailman/handlers/subject_prefix.py
@@ -162,7 +162,7 @@ class SubjectPrefix:
if p.search(prefix, 1):
# The prefix has number, so we should search prefix w/number in
# subject. Also, force new style.
- prefix_pattern = p.sub(r'\s*\d+\s*', prefix_pattern)
+ prefix_pattern = p.sub(r'\\s*\\d+\\s*', prefix_pattern)
# Substitute %d in prefix with post_id
with suppress(TypeError):
prefix = prefix % mlist.post_id
--
cgit v1.3.1
From ffc8ed1347121079c047ec454f94e27bf54a9d42 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Fri, 25 Nov 2016 09:05:26 -0500
Subject: Handle a Python 3.6 difference in interact().
Also:
* Fix a regexp that 3.6 raises an exception on.
* Remove a deprecated attribute from passlib.cfg.
---
src/mailman/config/passlib.cfg | 1 -
src/mailman/utilities/interact.py | 9 ++++++++-
src/mailman/utilities/tests/test_import.py | 7 ++++---
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/mailman/config/passlib.cfg b/src/mailman/config/passlib.cfg
index 805f0fb11..0564f9eb3 100644
--- a/src/mailman/config/passlib.cfg
+++ b/src/mailman/config/passlib.cfg
@@ -3,7 +3,6 @@
# See http://packages.python.org/passlib/index.html for details.
schemes = sha512_crypt, sha256_crypt
default = sha512_crypt
-all__vary_rounds = 0.1
sha256_crypt__min_rounds = 80000
sha512_crypt__min_rounds = 60000
admin__sha256_crypt__min_rounds = 160000
diff --git a/src/mailman/utilities/interact.py b/src/mailman/utilities/interact.py
index fec980b80..ac1612156 100644
--- a/src/mailman/utilities/interact.py
+++ b/src/mailman/utilities/interact.py
@@ -22,6 +22,7 @@ import sys
import code
from contextlib import suppress
+from inspect import signature
from mailman import public
@@ -67,4 +68,10 @@ def interact(upframe=True, banner=DEFAULT_BANNER, overrides=None):
Python %s on %s
Type "help", "copyright", "credits" or "license" for more information.''' % (
sys.version, sys.platform)
- interp.interact(banner)
+ # Python 3.6 added an exitmsg keyword but we don't currently support
+ # configuring it. For consistency between Python 3.6 and earlier
+ # versions, suppress the exit message if possible.
+ kws = dict(banner=banner)
+ if 'exitmsg' in signature(interp.interact).parameters:
+ kws['exitmsg'] = ''
+ interp.interact(**kws)
diff --git a/src/mailman/utilities/tests/test_import.py b/src/mailman/utilities/tests/test_import.py
index ca3a4afb7..5a226ba26 100644
--- a/src/mailman/utilities/tests/test_import.py
+++ b/src/mailman/utilities/tests/test_import.py
@@ -65,6 +65,7 @@ def list_to_string(data):
class TestBasicImport(unittest.TestCase):
layer = ConfigLayer
+ maxDiff = None
def setUp(self):
self._mlist = create_list('blank@example.com')
@@ -322,12 +323,12 @@ class TestBasicImport(unittest.TestCase):
SubscriptionPolicy.confirm_then_moderate)
def test_header_matches(self):
- # This test contail real cases of header_filter_rules
+ # This test containes real cases of header_filter_rules.
self._pckdict['header_filter_rules'] = [
('X\\-Spam\\-Status\\: Yes.*', 3, False),
('^X-Spam-Status: Yes\r\n\r\n', 2, False),
('^X-Spam-Level: \\*\\*\\*.*$', 3, False),
- ('^X-Spam-Level:.\\*\\*\r\n^X-Spam:.\\Yes', 3, False),
+ ('^X-Spam-Level:.\\*\\*\r\n^X-Spam:.Yes', 3, False),
('Subject: \\[SPAM\\].*', 3, False),
('^Subject: .*loan.*', 3, False),
('Original-Received: from *linkedin.com*\r\n', 3, False),
@@ -362,7 +363,7 @@ class TestBasicImport(unittest.TestCase):
('x-spam-status', 'Yes', 'reject'),
('x-spam-level', '\\*\\*\\*.*$', 'discard'),
('x-spam-level', '\\*\\*', 'discard'),
- ('x-spam', '\\Yes', 'discard'),
+ ('x-spam', 'Yes', 'discard'),
('subject', '\\[SPAM\\].*', 'discard'),
('subject', '.*loan.*', 'discard'),
('original-received', 'from *linkedin.com*', 'discard'),
--
cgit v1.3.1
From 86162ef47bbf9ab71faceed9eaa656ebb8e1ec63 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Sat, 26 Nov 2016 00:06:55 -0500
Subject: NEWS.
---
src/mailman/docs/NEWS.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst
index 27f3ea5eb..26d7433c3 100644
--- a/src/mailman/docs/NEWS.rst
+++ b/src/mailman/docs/NEWS.rst
@@ -245,6 +245,8 @@ REST
Aurélien Bompard. (Closes #284)
* Query parameters now allow you to filter mailing lists by the
``advertised`` boolean parameter. Given by Aurélien Bompard.
+ * Only the system-enabled archivers are returned in the REST API. Given by
+ Aurélien Bompard.
Other
-----
--
cgit v1.3.1
From b9250ebdefaae0ca98324cf42e4dd51ad550d839 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Mon, 28 Nov 2016 17:22:28 -0500
Subject: Officially support Python 3.6.
Closes #295
---
.gitlab-ci.yml | 6 +++---
src/mailman/docs/NEWS.rst | 1 +
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 94f8b1de7..8630fe549 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -21,13 +21,13 @@ docs:
sqlite:
script:
- - tox -e py34,py35
+ - tox -e py34,py35,py36
pgsql:
services:
- postgres:latest
script:
- - MAILMAN_EXTRA_TESTING_CFG=/home/runner/configs/postgres.cfg tox -e py34-pg,py35-pg
+ - MAILMAN_EXTRA_TESTING_CFG=/home/runner/configs/postgres.cfg tox -e py34-pg,py35-pg,py36-pg
tags:
- postgres
@@ -35,6 +35,6 @@ mysql:
services:
- mysql:latest
script:
- - MAILMAN_EXTRA_TESTING_CFG=/home/runner/configs/mysql.cfg tox -e py34-mysql,py35-mysql
+ - MAILMAN_EXTRA_TESTING_CFG=/home/runner/configs/mysql.cfg tox -e py34-mysql,py35-mysql,py36-mysql
tags:
- mysql
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst
index 26d7433c3..1841f8fb7 100644
--- a/src/mailman/docs/NEWS.rst
+++ b/src/mailman/docs/NEWS.rst
@@ -151,6 +151,7 @@ Interfaces
Internal
--------
+ * Add official support for Python 3.6. (Closes #295)
* A handful of unused legacy exceptions have been removed. The redundant
`MailmanException` has been removed; use `MailmanError` everywhere.
* Drop the use of the `lazr.smtptest` library, which is based on the
--
cgit v1.3.1
From f977a1a815460042baeb9704bc25c8a8e75652a4 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard
Date: Fri, 20 Nov 2015 08:17:36 +0100
Subject: Fix the email senders list when there's a Header instance
The mailman.email.Message.senders property would fail when one of the
headers was an email.header.Header instance.
---
src/mailman/email/message.py | 7 ++++---
src/mailman/email/tests/test_message.py | 10 ++++++++++
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/mailman/email/message.py b/src/mailman/email/message.py
index ebfef9d9b..26bc35b78 100644
--- a/src/mailman/email/message.py
+++ b/src/mailman/email/message.py
@@ -93,9 +93,10 @@ class Message(email.message.Message):
if envelope_sender is not None
else '')
else:
- field_values = self.get_all(header, [])
- senders.extend(address.lower() for (display_name, address)
- in email.utils.getaddresses(field_values))
+ for field_value in self.get_all(header, []):
+ # Convert the header to str in case it's a Header instance.
+ name, address = email.utils.parseaddr(str(field_value))
+ senders.append(address.lower())
# Filter out None and the empty string, and convert to unicode.
clean_senders = []
for sender in senders:
diff --git a/src/mailman/email/tests/test_message.py b/src/mailman/email/tests/test_message.py
index 3ec099904..c23d37f7f 100644
--- a/src/mailman/email/tests/test_message.py
+++ b/src/mailman/email/tests/test_message.py
@@ -19,6 +19,7 @@
import unittest
+from email.header import Header
from email.parser import FeedParser
from mailman.app.lifecycle import create_list
from mailman.email.message import Message, UserNotification
@@ -52,6 +53,9 @@ class TestMessage(unittest.TestCase):
class TestMessageSubclass(unittest.TestCase):
+
+ layer = ConfigLayer
+
def test_i18n_filenames(self):
parser = FeedParser(_factory=Message)
parser.feed("""\
@@ -79,3 +83,9 @@ Test content
except TypeError as error:
self.fail(error)
self.assertEqual(filename, u'd\xe9jeuner.txt')
+
+ def test_senders_header_instances(self):
+ msg = Message()
+ msg['From'] = Header('test@example.com')
+ # Make sure the senders property does not fail
+ self.assertEqual(msg.senders, ["test@example.com"])
--
cgit v1.3.1
From 432088db522219d6caa6c2cfede3df45acb6f3e0 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard
Date: Fri, 20 Nov 2015 08:33:34 +0100
Subject: Fix a crash with the no_subject rule and Header instances
---
src/mailman/rules/no_subject.py | 4 ++-
src/mailman/rules/tests/test_no_subject.py | 57 ++++++++++++++++++++++++++++++
2 files changed, 60 insertions(+), 1 deletion(-)
create mode 100644 src/mailman/rules/tests/test_no_subject.py
diff --git a/src/mailman/rules/no_subject.py b/src/mailman/rules/no_subject.py
index 4b53067a5..e6a3be6ed 100644
--- a/src/mailman/rules/no_subject.py
+++ b/src/mailman/rules/no_subject.py
@@ -34,5 +34,7 @@ class NoSubject:
def check(self, mlist, msg, msgdata):
"""See `IRule`."""
- subject = msg.get('subject', '').strip()
+ # Convert the header value to string because it may be an
+ # email.header.Header instance.
+ subject = str(msg.get('subject', '')).strip()
return subject == ''
diff --git a/src/mailman/rules/tests/test_no_subject.py b/src/mailman/rules/tests/test_no_subject.py
new file mode 100644
index 000000000..1647f96d5
--- /dev/null
+++ b/src/mailman/rules/tests/test_no_subject.py
@@ -0,0 +1,57 @@
+# Copyright (C) 2015 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see .
+
+"""Test the `no_subject` header rule."""
+
+__all__ = [
+ 'TestNoSubject',
+ ]
+
+
+import os
+import unittest
+from email.header import Header
+
+from mailman.app.lifecycle import create_list
+from mailman.email.message import Message
+from mailman.rules import no_subject
+from mailman.testing.layers import ConfigLayer
+
+
+
+class TestNoSubject(unittest.TestCase):
+ """Test the no_subject rule."""
+
+ layer = ConfigLayer
+
+ def setUp(self):
+ self._mlist = create_list('test@example.com')
+ self._rule = no_subject.NoSubject()
+
+ def test_header_instance_empty(self):
+ # Check the case where the subject is a Header instance
+ msg = Message()
+ msg["Subject"] = Header("")
+ result = self._rule.check(self._mlist, msg, {})
+ self.assertTrue(result)
+
+ def test_header_instance_not_empty(self):
+ # Check the case where the subject is a Header instance
+ msg = Message()
+ msg["Subject"] = Header("Test subject")
+ result = self._rule.check(self._mlist, msg, {})
+ self.assertFalse(result)
--
cgit v1.3.1
From b570b76724c6341921ebe531071904df312d39e6 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard
Date: Fri, 20 Nov 2015 09:11:56 +0100
Subject: Fix a crash with the suspicious rule and Header instances
---
src/mailman/rules/suspicious.py | 4 ++-
src/mailman/rules/tests/test_suspicious.py | 52 ++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+), 1 deletion(-)
create mode 100644 src/mailman/rules/tests/test_suspicious.py
diff --git a/src/mailman/rules/suspicious.py b/src/mailman/rules/suspicious.py
index f349a313e..acb17334a 100644
--- a/src/mailman/rules/suspicious.py
+++ b/src/mailman/rules/suspicious.py
@@ -87,6 +87,8 @@ def has_matching_bounce_header(mlist, msg):
"""
for header, cre, line in _parse_matching_header_opt(mlist):
for value in msg.get_all(header, []):
- if cre.search(value):
+ # Convert the header value to string because it may be an
+ # email.header.Header instance.
+ if cre.search(str(value)):
return True
return False
diff --git a/src/mailman/rules/tests/test_suspicious.py b/src/mailman/rules/tests/test_suspicious.py
new file mode 100644
index 000000000..1be0eb8e7
--- /dev/null
+++ b/src/mailman/rules/tests/test_suspicious.py
@@ -0,0 +1,52 @@
+# Copyright (C) 2015 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see .
+
+"""Test the `suspicious` rule."""
+
+__all__ = [
+ 'TestSuspicious',
+ ]
+
+
+import os
+import unittest
+from email.header import Header
+
+from mailman.app.lifecycle import create_list
+from mailman.email.message import Message
+from mailman.rules import suspicious
+from mailman.testing.layers import ConfigLayer
+
+
+
+class TestSuspicious(unittest.TestCase):
+ """Test the suspicous rule."""
+
+ layer = ConfigLayer
+
+ def setUp(self):
+ self._mlist = create_list('test@example.com')
+ self._rule = suspicious.SuspiciousHeader()
+
+ def test_header_instance(self):
+ # Check the case where the subject is a Header instance
+ msg = Message()
+ msg["From"] = Header("user@example.com")
+ self._mlist.bounce_matching_headers = 'from: spam@example.com'
+ result = self._rule.check(self._mlist, msg, {})
+ self.assertFalse(result)
+
--
cgit v1.3.1
From b521d6739edda8737fb784536d9282fbc708e3e2 Mon Sep 17 00:00:00 2001
From: Aurélien Bompard
Date: Fri, 20 Nov 2015 11:54:31 +0100
Subject: Learn to encode Messages and Header instances to JSON
---
src/mailman/rest/helpers.py | 6 ++++++
src/mailman/rest/tests/test_helpers.py | 33 ++++++++++++++++++++++++++++++++-
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/src/mailman/rest/helpers.py b/src/mailman/rest/helpers.py
index 9ab1f434e..a4b072408 100644
--- a/src/mailman/rest/helpers.py
+++ b/src/mailman/rest/helpers.py
@@ -23,6 +23,8 @@ import hashlib
from contextlib import suppress
from datetime import datetime, timedelta
+from email.header import Header
+from email.message import Message
from enum import Enum
from lazr.config import as_boolean
from mailman import public
@@ -49,6 +51,10 @@ class ExtendedEncoder(json.JSONEncoder):
return obj.name
elif isinstance(obj, bytes):
return bytes_to_str(obj)
+ elif isinstance(obj, Message):
+ return obj.as_string()
+ elif isinstance(obj, Header):
+ return str(obj)
return super().default(obj)
diff --git a/src/mailman/rest/tests/test_helpers.py b/src/mailman/rest/tests/test_helpers.py
index 982b97ef3..31ed8c88b 100644
--- a/src/mailman/rest/tests/test_helpers.py
+++ b/src/mailman/rest/tests/test_helpers.py
@@ -17,11 +17,14 @@
"""Additional tests for helpers."""
+import json
import unittest
+from email.message import Message
+from email.header import Header
from datetime import timedelta
from mailman.rest import helpers
-from mailman.testing.layers import ConfigLayer
+from mailman.testing.layers import ConfigLayer, RESTLayer
class FakeResponse:
@@ -74,3 +77,31 @@ class TestHelpers(unittest.TestCase):
def test_json_encoding_default(self):
resource = dict(interval=Unserializable())
self.assertRaises(TypeError, helpers.etag, resource)
+
+
+
+class TestJSONEncoder(unittest.TestCase):
+ """Test the JSON ExtendedEncoder."""
+
+ layer = RESTLayer
+
+ def test_encode_message(self):
+ msg = Message()
+ msg['From'] = 'test@example.com'
+ msg.set_payload('Test content.')
+ try:
+ result = json.dumps(msg, cls=helpers.ExtendedEncoder)
+ except TypeError as e:
+ self.fail(e)
+ self.assertEqual(result,
+ json.dumps('From: test@example.com\n\nTest content.'))
+
+ def test_encode_header(self):
+ value = 'Contains non-ascii \u00e9 \u00e7 \u00e0'
+ header = Header(value, charset='utf-8')
+ try:
+ result = json.dumps(Header(value, charset='utf-8'),
+ cls=helpers.ExtendedEncoder)
+ except TypeError as e:
+ self.fail(e)
+ self.assertEqual(result, json.dumps(value))
--
cgit v1.3.1
From 8ee8a7d2cb598138aeadfebe8eb5cc3f8fb2d88a Mon Sep 17 00:00:00 2001
From: Aurélien Bompard
Date: Tue, 24 May 2016 10:50:41 +0200
Subject: Fix Flake8 errors
---
src/mailman/rest/tests/test_helpers.py | 15 +++++++--------
src/mailman/rules/tests/test_no_subject.py | 8 +-------
src/mailman/rules/tests/test_suspicious.py | 9 +--------
3 files changed, 9 insertions(+), 23 deletions(-)
diff --git a/src/mailman/rest/tests/test_helpers.py b/src/mailman/rest/tests/test_helpers.py
index 31ed8c88b..3f19a9e5e 100644
--- a/src/mailman/rest/tests/test_helpers.py
+++ b/src/mailman/rest/tests/test_helpers.py
@@ -20,9 +20,9 @@
import json
import unittest
-from email.message import Message
-from email.header import Header
from datetime import timedelta
+from email.header import Header
+from email.message import Message
from mailman.rest import helpers
from mailman.testing.layers import ConfigLayer, RESTLayer
@@ -79,7 +79,6 @@ class TestHelpers(unittest.TestCase):
self.assertRaises(TypeError, helpers.etag, resource)
-
class TestJSONEncoder(unittest.TestCase):
"""Test the JSON ExtendedEncoder."""
@@ -93,15 +92,15 @@ class TestJSONEncoder(unittest.TestCase):
result = json.dumps(msg, cls=helpers.ExtendedEncoder)
except TypeError as e:
self.fail(e)
- self.assertEqual(result,
- json.dumps('From: test@example.com\n\nTest content.'))
+ self.assertEqual(
+ result, json.dumps('From: test@example.com\n\nTest content.'))
def test_encode_header(self):
value = 'Contains non-ascii \u00e9 \u00e7 \u00e0'
- header = Header(value, charset='utf-8')
try:
- result = json.dumps(Header(value, charset='utf-8'),
- cls=helpers.ExtendedEncoder)
+ result = json.dumps(
+ Header(value, charset='utf-8'),
+ cls=helpers.ExtendedEncoder)
except TypeError as e:
self.fail(e)
self.assertEqual(result, json.dumps(value))
diff --git a/src/mailman/rules/tests/test_no_subject.py b/src/mailman/rules/tests/test_no_subject.py
index 1647f96d5..efe942af6 100644
--- a/src/mailman/rules/tests/test_no_subject.py
+++ b/src/mailman/rules/tests/test_no_subject.py
@@ -17,22 +17,16 @@
"""Test the `no_subject` header rule."""
-__all__ = [
- 'TestNoSubject',
- ]
-
-import os
import unittest
-from email.header import Header
+from email.header import Header
from mailman.app.lifecycle import create_list
from mailman.email.message import Message
from mailman.rules import no_subject
from mailman.testing.layers import ConfigLayer
-
class TestNoSubject(unittest.TestCase):
"""Test the no_subject rule."""
diff --git a/src/mailman/rules/tests/test_suspicious.py b/src/mailman/rules/tests/test_suspicious.py
index 1be0eb8e7..e1649928c 100644
--- a/src/mailman/rules/tests/test_suspicious.py
+++ b/src/mailman/rules/tests/test_suspicious.py
@@ -17,22 +17,16 @@
"""Test the `suspicious` rule."""
-__all__ = [
- 'TestSuspicious',
- ]
-
-import os
import unittest
-from email.header import Header
+from email.header import Header
from mailman.app.lifecycle import create_list
from mailman.email.message import Message
from mailman.rules import suspicious
from mailman.testing.layers import ConfigLayer
-
class TestSuspicious(unittest.TestCase):
"""Test the suspicous rule."""
@@ -49,4 +43,3 @@ class TestSuspicious(unittest.TestCase):
self._mlist.bounce_matching_headers = 'from: spam@example.com'
result = self._rule.check(self._mlist, msg, {})
self.assertFalse(result)
-
--
cgit v1.3.1
From da0789ceedbeddcae6b47545c115f5e659de019d Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Mon, 28 Nov 2016 17:19:18 -0500
Subject: Starting to clean up the branch.
---
src/mailman/email/tests/test_message.py | 3 +--
src/mailman/rest/tests/test_helpers.py | 15 ++++-----------
src/mailman/rules/no_subject.py | 2 +-
src/mailman/rules/suspicious.py | 2 +-
src/mailman/rules/tests/test_no_subject.py | 9 +++------
src/mailman/rules/tests/test_suspicious.py | 7 +++----
6 files changed, 13 insertions(+), 25 deletions(-)
diff --git a/src/mailman/email/tests/test_message.py b/src/mailman/email/tests/test_message.py
index c23d37f7f..461659865 100644
--- a/src/mailman/email/tests/test_message.py
+++ b/src/mailman/email/tests/test_message.py
@@ -53,7 +53,6 @@ class TestMessage(unittest.TestCase):
class TestMessageSubclass(unittest.TestCase):
-
layer = ConfigLayer
def test_i18n_filenames(self):
@@ -88,4 +87,4 @@ Test content
msg = Message()
msg['From'] = Header('test@example.com')
# Make sure the senders property does not fail
- self.assertEqual(msg.senders, ["test@example.com"])
+ self.assertEqual(msg.senders, ['test@example.com'])
diff --git a/src/mailman/rest/tests/test_helpers.py b/src/mailman/rest/tests/test_helpers.py
index 3f19a9e5e..07ae784c8 100644
--- a/src/mailman/rest/tests/test_helpers.py
+++ b/src/mailman/rest/tests/test_helpers.py
@@ -81,26 +81,19 @@ class TestHelpers(unittest.TestCase):
class TestJSONEncoder(unittest.TestCase):
"""Test the JSON ExtendedEncoder."""
-
layer = RESTLayer
def test_encode_message(self):
msg = Message()
msg['From'] = 'test@example.com'
msg.set_payload('Test content.')
- try:
- result = json.dumps(msg, cls=helpers.ExtendedEncoder)
- except TypeError as e:
- self.fail(e)
+ result = json.dumps(msg, cls=helpers.ExtendedEncoder)
self.assertEqual(
result, json.dumps('From: test@example.com\n\nTest content.'))
def test_encode_header(self):
value = 'Contains non-ascii \u00e9 \u00e7 \u00e0'
- try:
- result = json.dumps(
- Header(value, charset='utf-8'),
- cls=helpers.ExtendedEncoder)
- except TypeError as e:
- self.fail(e)
+ result = json.dumps(
+ Header(value, charset='utf-8'),
+ cls=helpers.ExtendedEncoder)
self.assertEqual(result, json.dumps(value))
diff --git a/src/mailman/rules/no_subject.py b/src/mailman/rules/no_subject.py
index e6a3be6ed..ed020b81e 100644
--- a/src/mailman/rules/no_subject.py
+++ b/src/mailman/rules/no_subject.py
@@ -34,7 +34,7 @@ class NoSubject:
def check(self, mlist, msg, msgdata):
"""See `IRule`."""
- # Convert the header value to string because it may be an
+ # Convert the header value to a str because it may be an
# email.header.Header instance.
subject = str(msg.get('subject', '')).strip()
return subject == ''
diff --git a/src/mailman/rules/suspicious.py b/src/mailman/rules/suspicious.py
index acb17334a..679605fd6 100644
--- a/src/mailman/rules/suspicious.py
+++ b/src/mailman/rules/suspicious.py
@@ -87,7 +87,7 @@ def has_matching_bounce_header(mlist, msg):
"""
for header, cre, line in _parse_matching_header_opt(mlist):
for value in msg.get_all(header, []):
- # Convert the header value to string because it may be an
+ # Convert the header value to a str because it may be an
# email.header.Header instance.
if cre.search(str(value)):
return True
diff --git a/src/mailman/rules/tests/test_no_subject.py b/src/mailman/rules/tests/test_no_subject.py
index efe942af6..0155e25ee 100644
--- a/src/mailman/rules/tests/test_no_subject.py
+++ b/src/mailman/rules/tests/test_no_subject.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 by the Free Software Foundation, Inc.
+# Copyright (C) 2016 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -17,7 +17,6 @@
"""Test the `no_subject` header rule."""
-
import unittest
from email.header import Header
@@ -37,15 +36,13 @@ class TestNoSubject(unittest.TestCase):
self._rule = no_subject.NoSubject()
def test_header_instance_empty(self):
- # Check the case where the subject is a Header instance
msg = Message()
- msg["Subject"] = Header("")
+ msg['Subject'] = Header('')
result = self._rule.check(self._mlist, msg, {})
self.assertTrue(result)
def test_header_instance_not_empty(self):
- # Check the case where the subject is a Header instance
msg = Message()
- msg["Subject"] = Header("Test subject")
+ msg['Subject'] = Header('Test subject')
result = self._rule.check(self._mlist, msg, {})
self.assertFalse(result)
diff --git a/src/mailman/rules/tests/test_suspicious.py b/src/mailman/rules/tests/test_suspicious.py
index e1649928c..441fb0b48 100644
--- a/src/mailman/rules/tests/test_suspicious.py
+++ b/src/mailman/rules/tests/test_suspicious.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 by the Free Software Foundation, Inc.
+# Copyright (C) 2016 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
@@ -28,7 +28,7 @@ from mailman.testing.layers import ConfigLayer
class TestSuspicious(unittest.TestCase):
- """Test the suspicous rule."""
+ """Test the suspicious rule."""
layer = ConfigLayer
@@ -37,9 +37,8 @@ class TestSuspicious(unittest.TestCase):
self._rule = suspicious.SuspiciousHeader()
def test_header_instance(self):
- # Check the case where the subject is a Header instance
msg = Message()
- msg["From"] = Header("user@example.com")
+ msg['From'] = Header('user@example.com')
self._mlist.bounce_matching_headers = 'from: spam@example.com'
result = self._rule.check(self._mlist, msg, {})
self.assertFalse(result)
--
cgit v1.3.1
From cb498d3e960af6c741fac9896d8a60bab9f79865 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Mon, 28 Nov 2016 21:06:35 -0500
Subject: Remove cruft.
---
BREAKS.rst | 5 -----
1 file changed, 5 deletions(-)
delete mode 100644 BREAKS.rst
diff --git a/BREAKS.rst b/BREAKS.rst
deleted file mode 100644
index 020126ad1..000000000
--- a/BREAKS.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-======================
- Python 3.6 breakages
-======================
-
-* https://bugs.python.org/issue27030
--
cgit v1.3.1
From fe22ebdb98d125db840c980cbd953a8fbc2e5cdf Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 29 Nov 2016 18:51:05 -0500
Subject: Use `atpublic` for @public instead of internal copy.
---
setup.py | 1 +
src/mailman/__init__.py | 14 --------------
src/mailman/app/bounces.py | 2 +-
src/mailman/app/commands.py | 2 +-
src/mailman/app/digests.py | 2 +-
src/mailman/app/domain.py | 2 +-
src/mailman/app/events.py | 2 +-
src/mailman/app/inject.py | 2 +-
src/mailman/app/lifecycle.py | 2 +-
src/mailman/app/membership.py | 2 +-
src/mailman/app/moderator.py | 2 +-
src/mailman/app/notifications.py | 2 +-
src/mailman/app/replybot.py | 2 +-
src/mailman/app/subscriptions.py | 2 +-
src/mailman/app/workflow.py | 2 +-
src/mailman/archiving/mailarchive.py | 2 +-
src/mailman/archiving/mhonarc.py | 2 +-
src/mailman/archiving/prototype.py | 2 +-
src/mailman/bin/mailman.py | 2 +-
src/mailman/bin/master.py | 2 +-
src/mailman/bin/runner.py | 2 +-
src/mailman/chains/accept.py | 2 +-
src/mailman/chains/base.py | 2 +-
src/mailman/chains/builtin.py | 2 +-
src/mailman/chains/discard.py | 2 +-
src/mailman/chains/headers.py | 2 +-
src/mailman/chains/hold.py | 2 +-
src/mailman/chains/moderation.py | 2 +-
src/mailman/chains/owner.py | 2 +-
src/mailman/chains/reject.py | 2 +-
src/mailman/commands/cli_aliases.py | 2 +-
src/mailman/commands/cli_conf.py | 2 +-
src/mailman/commands/cli_control.py | 2 +-
src/mailman/commands/cli_digests.py | 2 +-
src/mailman/commands/cli_help.py | 2 +-
src/mailman/commands/cli_import.py | 2 +-
src/mailman/commands/cli_info.py | 2 +-
src/mailman/commands/cli_inject.py | 2 +-
src/mailman/commands/cli_lists.py | 2 +-
src/mailman/commands/cli_members.py | 2 +-
src/mailman/commands/cli_qfile.py | 2 +-
src/mailman/commands/cli_status.py | 2 +-
src/mailman/commands/cli_unshunt.py | 2 +-
src/mailman/commands/cli_version.py | 2 +-
src/mailman/commands/cli_withlist.py | 2 +-
src/mailman/commands/eml_confirm.py | 2 +-
src/mailman/commands/eml_echo.py | 2 +-
src/mailman/commands/eml_end.py | 2 +-
src/mailman/commands/eml_help.py | 2 +-
src/mailman/commands/eml_membership.py | 2 +-
src/mailman/config/__init__.py | 2 +-
src/mailman/config/config.py | 2 +-
src/mailman/core/api.py | 2 +-
src/mailman/core/chains.py | 2 +-
src/mailman/core/constants.py | 2 +-
src/mailman/core/i18n.py | 2 +-
src/mailman/core/initialize.py | 2 +-
src/mailman/core/logging.py | 2 +-
src/mailman/core/pipelines.py | 2 +-
src/mailman/core/rules.py | 2 +-
src/mailman/core/runner.py | 2 +-
src/mailman/core/switchboard.py | 2 +-
src/mailman/core/system.py | 2 +-
src/mailman/database/alembic/__init__.py | 2 +-
src/mailman/database/alembic/env.py | 2 +-
src/mailman/database/base.py | 2 +-
src/mailman/database/factory.py | 2 +-
src/mailman/database/helpers.py | 2 +-
src/mailman/database/model.py | 2 +-
src/mailman/database/mysql.py | 2 +-
src/mailman/database/postgresql.py | 2 +-
src/mailman/database/sqlite.py | 2 +-
src/mailman/database/transaction.py | 2 +-
src/mailman/database/types.py | 2 +-
src/mailman/docs/__init__.py | 2 +-
src/mailman/email/message.py | 2 +-
src/mailman/email/validate.py | 2 +-
src/mailman/handlers/acknowledge.py | 2 +-
src/mailman/handlers/after_delivery.py | 2 +-
src/mailman/handlers/avoid_duplicates.py | 2 +-
src/mailman/handlers/cleanse.py | 2 +-
src/mailman/handlers/cleanse_dkim.py | 2 +-
src/mailman/handlers/cook_headers.py | 2 +-
src/mailman/handlers/decorate.py | 2 +-
src/mailman/handlers/file_recipients.py | 2 +-
src/mailman/handlers/member_recipients.py | 2 +-
src/mailman/handlers/mime_delete.py | 2 +-
src/mailman/handlers/owner_recipients.py | 2 +-
src/mailman/handlers/replybot.py | 2 +-
src/mailman/handlers/rfc_2369.py | 2 +-
src/mailman/handlers/subject_prefix.py | 2 +-
src/mailman/handlers/tagger.py | 2 +-
src/mailman/handlers/to_archive.py | 2 +-
src/mailman/handlers/to_digest.py | 2 +-
src/mailman/handlers/to_outgoing.py | 2 +-
src/mailman/handlers/to_usenet.py | 2 +-
src/mailman/interfaces/action.py | 2 +-
src/mailman/interfaces/address.py | 2 +-
src/mailman/interfaces/api.py | 2 +-
src/mailman/interfaces/archiver.py | 2 +-
src/mailman/interfaces/autorespond.py | 2 +-
src/mailman/interfaces/bans.py | 2 +-
src/mailman/interfaces/bounce.py | 2 +-
src/mailman/interfaces/cache.py | 2 +-
src/mailman/interfaces/chain.py | 2 +-
src/mailman/interfaces/command.py | 2 +-
src/mailman/interfaces/configuration.py | 2 +-
src/mailman/interfaces/database.py | 2 +-
src/mailman/interfaces/digests.py | 2 +-
src/mailman/interfaces/domain.py | 2 +-
src/mailman/interfaces/errors.py | 2 +-
src/mailman/interfaces/handler.py | 2 +-
src/mailman/interfaces/languages.py | 2 +-
src/mailman/interfaces/listmanager.py | 2 +-
src/mailman/interfaces/mailinglist.py | 2 +-
src/mailman/interfaces/member.py | 2 +-
src/mailman/interfaces/messages.py | 2 +-
src/mailman/interfaces/mime.py | 2 +-
src/mailman/interfaces/mlistrequest.py | 2 +-
src/mailman/interfaces/mta.py | 2 +-
src/mailman/interfaces/nntp.py | 2 +-
src/mailman/interfaces/pending.py | 2 +-
src/mailman/interfaces/pipeline.py | 2 +-
src/mailman/interfaces/preferences.py | 2 +-
src/mailman/interfaces/requests.py | 2 +-
src/mailman/interfaces/roster.py | 2 +-
src/mailman/interfaces/rules.py | 2 +-
src/mailman/interfaces/runner.py | 2 +-
src/mailman/interfaces/styles.py | 2 +-
src/mailman/interfaces/subscriptions.py | 2 +-
src/mailman/interfaces/switchboard.py | 2 +-
src/mailman/interfaces/system.py | 2 +-
src/mailman/interfaces/template.py | 2 +-
src/mailman/interfaces/user.py | 2 +-
src/mailman/interfaces/usermanager.py | 2 +-
src/mailman/interfaces/workflow.py | 2 +-
src/mailman/languages/language.py | 2 +-
src/mailman/languages/manager.py | 2 +-
src/mailman/model/address.py | 2 +-
src/mailman/model/autorespond.py | 2 +-
src/mailman/model/bans.py | 2 +-
src/mailman/model/bounce.py | 2 +-
src/mailman/model/cache.py | 2 +-
src/mailman/model/digests.py | 2 +-
src/mailman/model/domain.py | 2 +-
src/mailman/model/language.py | 2 +-
src/mailman/model/listmanager.py | 2 +-
src/mailman/model/mailinglist.py | 2 +-
src/mailman/model/member.py | 2 +-
src/mailman/model/message.py | 2 +-
src/mailman/model/messagestore.py | 2 +-
src/mailman/model/mime.py | 2 +-
src/mailman/model/pending.py | 2 +-
src/mailman/model/preferences.py | 2 +-
src/mailman/model/requests.py | 2 +-
src/mailman/model/roster.py | 2 +-
src/mailman/model/subscriptions.py | 2 +-
src/mailman/model/template.py | 2 +-
src/mailman/model/uid.py | 2 +-
src/mailman/model/user.py | 2 +-
src/mailman/model/usermanager.py | 2 +-
src/mailman/model/workflow.py | 2 +-
src/mailman/mta/aliases.py | 2 +-
src/mailman/mta/base.py | 2 +-
src/mailman/mta/bulk.py | 2 +-
src/mailman/mta/connection.py | 2 +-
src/mailman/mta/decorating.py | 2 +-
src/mailman/mta/deliver.py | 2 +-
src/mailman/mta/exim4.py | 2 +-
src/mailman/mta/null.py | 2 +-
src/mailman/mta/personalized.py | 2 +-
src/mailman/mta/postfix.py | 2 +-
src/mailman/mta/verp.py | 2 +-
src/mailman/rest/addresses.py | 2 +-
src/mailman/rest/bans.py | 2 +-
src/mailman/rest/docs/__init__.py | 2 +-
src/mailman/rest/domains.py | 2 +-
src/mailman/rest/header_matches.py | 2 +-
src/mailman/rest/helpers.py | 2 +-
src/mailman/rest/listconf.py | 2 +-
src/mailman/rest/lists.py | 2 +-
src/mailman/rest/members.py | 2 +-
src/mailman/rest/post_moderation.py | 2 +-
src/mailman/rest/preferences.py | 2 +-
src/mailman/rest/queues.py | 2 +-
src/mailman/rest/root.py | 2 +-
src/mailman/rest/sub_moderation.py | 2 +-
src/mailman/rest/templates.py | 2 +-
src/mailman/rest/uris.py | 2 +-
src/mailman/rest/users.py | 2 +-
src/mailman/rest/validator.py | 2 +-
src/mailman/rest/wsgiapp.py | 2 +-
src/mailman/rules/administrivia.py | 2 +-
src/mailman/rules/any.py | 2 +-
src/mailman/rules/approved.py | 2 +-
src/mailman/rules/banned_address.py | 2 +-
src/mailman/rules/emergency.py | 2 +-
src/mailman/rules/implicit_dest.py | 2 +-
src/mailman/rules/loop.py | 2 +-
src/mailman/rules/max_recipients.py | 2 +-
src/mailman/rules/max_size.py | 2 +-
src/mailman/rules/moderation.py | 2 +-
src/mailman/rules/news_moderation.py | 2 +-
src/mailman/rules/no_subject.py | 2 +-
src/mailman/rules/suspicious.py | 2 +-
src/mailman/rules/truth.py | 2 +-
src/mailman/runners/archive.py | 2 +-
src/mailman/runners/bounce.py | 2 +-
src/mailman/runners/command.py | 2 +-
src/mailman/runners/digest.py | 2 +-
src/mailman/runners/incoming.py | 2 +-
src/mailman/runners/lmtp.py | 2 +-
src/mailman/runners/nntp.py | 2 +-
src/mailman/runners/outgoing.py | 2 +-
src/mailman/runners/pipeline.py | 2 +-
src/mailman/runners/rest.py | 2 +-
src/mailman/runners/retry.py | 2 +-
src/mailman/runners/virgin.py | 2 +-
src/mailman/styles/base.py | 2 +-
src/mailman/styles/default.py | 2 +-
src/mailman/styles/manager.py | 2 +-
src/mailman/testing/documentation.py | 2 +-
src/mailman/testing/helpers.py | 2 +-
src/mailman/testing/i18n.py | 2 +-
src/mailman/testing/layers.py | 2 +-
src/mailman/testing/mta.py | 2 +-
src/mailman/testing/nose.py | 2 +-
src/mailman/utilities/datetime.py | 2 +-
src/mailman/utilities/email.py | 2 +-
src/mailman/utilities/filesystem.py | 2 +-
src/mailman/utilities/i18n.py | 2 +-
src/mailman/utilities/importer.py | 2 +-
src/mailman/utilities/interact.py | 2 +-
src/mailman/utilities/mailbox.py | 3 ++-
src/mailman/utilities/modules.py | 2 +-
src/mailman/utilities/options.py | 2 +-
src/mailman/utilities/passwords.py | 2 +-
src/mailman/utilities/protocols.py | 2 +-
src/mailman/utilities/queries.py | 2 +-
src/mailman/utilities/string.py | 2 +-
src/mailman/utilities/tests/test_modules.py | 4 ++--
src/mailman/utilities/uid.py | 2 +-
242 files changed, 243 insertions(+), 255 deletions(-)
diff --git a/setup.py b/setup.py
index 2d182cdc7..080c83925 100644
--- a/setup.py
+++ b/setup.py
@@ -106,6 +106,7 @@ case second `m'. Any other spelling is incorrect.""",
install_requires = [
'aiosmtpd',
'alembic',
+ 'atpublic',
'falcon>=1.0.0rc1',
'flufl.bounce',
'flufl.i18n',
diff --git a/src/mailman/__init__.py b/src/mailman/__init__.py
index c54830915..15ce69608 100644
--- a/src/mailman/__init__.py
+++ b/src/mailman/__init__.py
@@ -29,20 +29,6 @@ except ImportError: # pragma: no cover
__path__ = pkgutil.extend_path(__path__, __name__)
-# I hate myself: http://bugs.python.org/issue26632
-def public(thing=None, **kws):
- mdict = (sys._getframe(1).f_globals
- if thing is None
- else sys.modules[thing.__module__].__dict__)
- dunder_all = mdict.setdefault('__all__', [])
- if thing is not None:
- dunder_all.append(thing.__name__)
- for key, value in kws.items():
- dunder_all.append(key)
- mdict[key] = value
- return thing
-
-
# We have to initialize the i18n subsystem before anything else happens,
# however, we'll initialize it differently for tests. We have to do it this
# early so that module contents is set up before anything that needs it is
diff --git a/src/mailman/app/bounces.py b/src/mailman/app/bounces.py
index 98076dc9b..7fcbe4c2a 100644
--- a/src/mailman/app/bounces.py
+++ b/src/mailman/app/bounces.py
@@ -24,7 +24,6 @@ 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
@@ -35,6 +34,7 @@ from mailman.interfaces.subscriptions import ISubscriptionService
from mailman.interfaces.template import ITemplateLoader
from mailman.utilities.email import split_email
from mailman.utilities.string import expand, oneline, wrap
+from public import public
from string import Template
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/app/commands.py b/src/mailman/app/commands.py
index 4c484bc0b..093156d78 100644
--- a/src/mailman/app/commands.py
+++ b/src/mailman/app/commands.py
@@ -17,10 +17,10 @@
"""Initialize the email commands."""
-from mailman import public
from mailman.config import config
from mailman.interfaces.command import IEmailCommand
from mailman.utilities.modules import find_components
+from public import public
from zope.interface.verify import verifyObject
diff --git a/src/mailman/app/digests.py b/src/mailman/app/digests.py
index 0d47df328..409c22125 100644
--- a/src/mailman/app/digests.py
+++ b/src/mailman/app/digests.py
@@ -19,11 +19,11 @@
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
+from public import public
@public
diff --git a/src/mailman/app/domain.py b/src/mailman/app/domain.py
index 66abf9c3e..33546d34a 100644
--- a/src/mailman/app/domain.py
+++ b/src/mailman/app/domain.py
@@ -17,9 +17,9 @@
"""Application level domain support."""
-from mailman import public
from mailman.interfaces.domain import DomainDeletingEvent
from mailman.interfaces.listmanager import IListManager
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/app/events.py b/src/mailman/app/events.py
index f3323b6ce..c7d4857cb 100644
--- a/src/mailman/app/events.py
+++ b/src/mailman/app/events.py
@@ -17,12 +17,12 @@
"""Global events."""
-from mailman import public
from mailman.app import domain, membership, moderator, subscriptions
from mailman.core import i18n, switchboard
from mailman.languages import manager as language_manager
from mailman.styles import manager as style_manager
from mailman.utilities import passwords
+from public import public
from zope import event
diff --git a/src/mailman/app/inject.py b/src/mailman/app/inject.py
index decc0fd0e..ca03942ea 100644
--- a/src/mailman/app/inject.py
+++ b/src/mailman/app/inject.py
@@ -19,10 +19,10 @@
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
+from public import public
@public
diff --git a/src/mailman/app/lifecycle.py b/src/mailman/app/lifecycle.py
index 50145ce8f..ccd3e4b35 100644
--- a/src/mailman/app/lifecycle.py
+++ b/src/mailman/app/lifecycle.py
@@ -21,7 +21,6 @@ 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 (
@@ -31,6 +30,7 @@ from mailman.interfaces.member import MemberRole
from mailman.interfaces.styles import IStyleManager
from mailman.interfaces.usermanager import IUserManager
from mailman.utilities.modules import call_name
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/app/membership.py b/src/mailman/app/membership.py
index 534eed15d..5eb15cf30 100644
--- a/src/mailman/app/membership.py
+++ b/src/mailman/app/membership.py
@@ -18,7 +18,6 @@
"""Application support for membership management."""
from email.utils import formataddr
-from mailman import public
from mailman.app.notifications import (
send_admin_subscription_notice, send_goodbye_message,
send_welcome_message)
@@ -33,6 +32,7 @@ from mailman.interfaces.template import ITemplateLoader
from mailman.interfaces.user import IUser
from mailman.interfaces.usermanager import IUserManager
from mailman.utilities.string import expand
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/app/moderator.py b/src/mailman/app/moderator.py
index 9d3856f33..fe7a81383 100644
--- a/src/mailman/app/moderator.py
+++ b/src/mailman/app/moderator.py
@@ -21,7 +21,6 @@ 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 _
@@ -34,6 +33,7 @@ from mailman.interfaces.requests import IListRequests, RequestType
from mailman.interfaces.template import ITemplateLoader
from mailman.utilities.datetime import now
from mailman.utilities.string import expand, wrap
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/app/notifications.py b/src/mailman/app/notifications.py
index 31a15d820..4d5c1be12 100644
--- a/src/mailman/app/notifications.py
+++ b/src/mailman/app/notifications.py
@@ -21,13 +21,13 @@ 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
from mailman.interfaces.member import DeliveryMode
from mailman.interfaces.template import ITemplateLoader
from mailman.utilities.string import expand, wrap
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/app/replybot.py b/src/mailman/app/replybot.py
index fc911c5a1..f707fec89 100644
--- a/src/mailman/app/replybot.py
+++ b/src/mailman/app/replybot.py
@@ -17,7 +17,7 @@
"""Application level auto-reply code."""
-from mailman import public
+from public import public
@public
diff --git a/src/mailman/app/subscriptions.py b/src/mailman/app/subscriptions.py
index f88a967c2..a38b3061d 100644
--- a/src/mailman/app/subscriptions.py
+++ b/src/mailman/app/subscriptions.py
@@ -23,7 +23,6 @@ import logging
from datetime import timedelta
from email.utils import formataddr
from enum import Enum
-from mailman import public
from mailman.app.membership import delete_member
from mailman.app.workflow import Workflow
from mailman.core.i18n import _
@@ -45,6 +44,7 @@ from mailman.interfaces.usermanager import IUserManager
from mailman.interfaces.workflow import IWorkflowStateManager
from mailman.utilities.datetime import now
from mailman.utilities.string import expand, wrap
+from public import public
from zope.component import getUtility
from zope.event import notify
from zope.interface import implementer
diff --git a/src/mailman/app/workflow.py b/src/mailman/app/workflow.py
index cd9124993..e11ae03cf 100644
--- a/src/mailman/app/workflow.py
+++ b/src/mailman/app/workflow.py
@@ -22,8 +22,8 @@ import json
import logging
from collections import deque
-from mailman import public
from mailman.interfaces.workflow import IWorkflowStateManager
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/archiving/mailarchive.py b/src/mailman/archiving/mailarchive.py
index 782cec29a..bd1a34580 100644
--- a/src/mailman/archiving/mailarchive.py
+++ b/src/mailman/archiving/mailarchive.py
@@ -17,10 +17,10 @@
"""The Mail-Archive.com archiver."""
-from mailman import public
from mailman.config import config
from mailman.config.config import external_configuration
from mailman.interfaces.archiver import ArchivePolicy, IArchiver
+from public import public
from urllib.parse import quote, urljoin
from zope.interface import implementer
diff --git a/src/mailman/archiving/mhonarc.py b/src/mailman/archiving/mhonarc.py
index 857a61e06..80cba043b 100644
--- a/src/mailman/archiving/mhonarc.py
+++ b/src/mailman/archiving/mhonarc.py
@@ -19,11 +19,11 @@
import logging
-from mailman import public
from mailman.config import config
from mailman.config.config import external_configuration
from mailman.interfaces.archiver import IArchiver
from mailman.utilities.string import expand
+from public import public
from subprocess import PIPE, Popen
from urllib.parse import urljoin
from zope.interface import implementer
diff --git a/src/mailman/archiving/prototype.py b/src/mailman/archiving/prototype.py
index 9790129da..b37bfa61e 100644
--- a/src/mailman/archiving/prototype.py
+++ b/src/mailman/archiving/prototype.py
@@ -24,9 +24,9 @@ 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 public import public
from zope.interface import implementer
diff --git a/src/mailman/bin/mailman.py b/src/mailman/bin/mailman.py
index b4d144b7c..3f8f66d6e 100644
--- a/src/mailman/bin/mailman.py
+++ b/src/mailman/bin/mailman.py
@@ -21,13 +21,13 @@ import os
import argparse
from functools import cmp_to_key
-from mailman import public
from mailman.core.i18n import _
from mailman.core.initialize import initialize
from mailman.database.transaction import transaction
from mailman.interfaces.command import ICLISubCommand
from mailman.utilities.modules import find_components
from mailman.version import MAILMAN_VERSION_FULL
+from public import public
from zope.interface.verify import verifyObject
diff --git a/src/mailman/bin/master.py b/src/mailman/bin/master.py
index 8e0b1265f..3acff1fc8 100644
--- a/src/mailman/bin/master.py
+++ b/src/mailman/bin/master.py
@@ -28,11 +28,11 @@ from datetime import timedelta
from enum import Enum
from flufl.lock import Lock, NotLockedError, TimeOutError
from lazr.config import as_boolean
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.core.logging import reopen
from mailman.utilities.options import Options
+from public import public
DOT = '.'
diff --git a/src/mailman/bin/runner.py b/src/mailman/bin/runner.py
index 591f5ee31..39e1e9105 100644
--- a/src/mailman/bin/runner.py
+++ b/src/mailman/bin/runner.py
@@ -24,12 +24,12 @@ import logging
import argparse
import traceback
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.core.initialize import initialize
from mailman.utilities.modules import find_name
from mailman.version import MAILMAN_VERSION_FULL
+from public import public
log = None
diff --git a/src/mailman/chains/accept.py b/src/mailman/chains/accept.py
index 8b0a0507e..c245927bf 100644
--- a/src/mailman/chains/accept.py
+++ b/src/mailman/chains/accept.py
@@ -19,11 +19,11 @@
import logging
-from mailman import public
from mailman.chains.base import TerminalChainBase
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.chain import AcceptEvent
+from public import public
from zope.event import notify
diff --git a/src/mailman/chains/base.py b/src/mailman/chains/base.py
index 677ec501c..d54baf8b6 100644
--- a/src/mailman/chains/base.py
+++ b/src/mailman/chains/base.py
@@ -17,11 +17,11 @@
"""Base class for terminal chains."""
-from mailman import public
from mailman.config import config
from mailman.interfaces.chain import (
IChain, IChainIterator, IChainLink, IMutableChain, LinkAction)
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/chains/builtin.py b/src/mailman/chains/builtin.py
index b805fca0f..16de1043a 100644
--- a/src/mailman/chains/builtin.py
+++ b/src/mailman/chains/builtin.py
@@ -19,10 +19,10 @@
import logging
-from mailman import public
from mailman.chains.base import Link
from mailman.core.i18n import _
from mailman.interfaces.chain import IChain, LinkAction
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/chains/discard.py b/src/mailman/chains/discard.py
index f77c7eb0f..e9fc8d05d 100644
--- a/src/mailman/chains/discard.py
+++ b/src/mailman/chains/discard.py
@@ -19,10 +19,10 @@
import logging
-from mailman import public
from mailman.chains.base import TerminalChainBase
from mailman.core.i18n import _
from mailman.interfaces.chain import DiscardEvent
+from public import public
from zope.event import notify
diff --git a/src/mailman/chains/headers.py b/src/mailman/chains/headers.py
index 5698740d3..56ac179e9 100644
--- a/src/mailman/chains/headers.py
+++ b/src/mailman/chains/headers.py
@@ -21,12 +21,12 @@ import re
import logging
from itertools import count
-from mailman import public
from mailman.chains.base import Chain, Link
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.chain import LinkAction
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/chains/hold.py b/src/mailman/chains/hold.py
index 42fed66a6..0b50964b7 100644
--- a/src/mailman/chains/hold.py
+++ b/src/mailman/chains/hold.py
@@ -22,7 +22,6 @@ import logging
from email.mime.message import MIMEMessage
from email.mime.text import MIMEText
from email.utils import formatdate, make_msgid
-from mailman import public
from mailman.app.moderator import hold_message
from mailman.app.replybot import can_acknowledge
from mailman.chains.base import TerminalChainBase
@@ -36,6 +35,7 @@ from mailman.interfaces.pending import IPendable, IPendings
from mailman.interfaces.template import ITemplateLoader
from mailman.interfaces.usermanager import IUserManager
from mailman.utilities.string import expand, oneline, wrap
+from public import public
from zope.component import getUtility
from zope.event import notify
from zope.interface import implementer
diff --git a/src/mailman/chains/moderation.py b/src/mailman/chains/moderation.py
index 9bb4bf0d5..e8f507603 100644
--- a/src/mailman/chains/moderation.py
+++ b/src/mailman/chains/moderation.py
@@ -34,11 +34,11 @@ made as to the disposition of the message. `defer` is the default for
members, while `hold` is the default for nonmembers.
"""
-from mailman import public
from mailman.chains.base import Link
from mailman.core.i18n import _
from mailman.interfaces.action import Action
from mailman.interfaces.chain import IChain, LinkAction
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/chains/owner.py b/src/mailman/chains/owner.py
index f7454435f..4fb8e1723 100644
--- a/src/mailman/chains/owner.py
+++ b/src/mailman/chains/owner.py
@@ -19,11 +19,11 @@
import logging
-from mailman import public
from mailman.chains.base import TerminalChainBase
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.chain import AcceptOwnerEvent
+from public import public
from zope.event import notify
diff --git a/src/mailman/chains/reject.py b/src/mailman/chains/reject.py
index 27fce8d4e..96be8f2de 100644
--- a/src/mailman/chains/reject.py
+++ b/src/mailman/chains/reject.py
@@ -19,12 +19,12 @@
import logging
-from mailman import public
from mailman.app.bounces import bounce_message
from mailman.chains.base import TerminalChainBase
from mailman.core.i18n import _
from mailman.interfaces.chain import RejectEvent
from mailman.interfaces.pipeline import RejectMessage
+from public import public
from zope.event import notify
diff --git a/src/mailman/commands/cli_aliases.py b/src/mailman/commands/cli_aliases.py
index 76713555a..f48814854 100644
--- a/src/mailman/commands/cli_aliases.py
+++ b/src/mailman/commands/cli_aliases.py
@@ -17,11 +17,11 @@
"""Generate Mailman alias files for your MTA."""
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
from mailman.utilities.modules import call_name
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_conf.py b/src/mailman/commands/cli_conf.py
index 67db4ac53..0a00f5006 100644
--- a/src/mailman/commands/cli_conf.py
+++ b/src/mailman/commands/cli_conf.py
@@ -21,10 +21,10 @@ import sys
from contextlib import closing
from lazr.config._config import Section
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_control.py b/src/mailman/commands/cli_control.py
index 5ba0b5427..846f4a5c6 100644
--- a/src/mailman/commands/cli_control.py
+++ b/src/mailman/commands/cli_control.py
@@ -23,11 +23,11 @@ import errno
import signal
import logging
-from mailman import public
from mailman.bin.master import WatcherState, master_state
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_digests.py b/src/mailman/commands/cli_digests.py
index 3a4d6614f..151a9332c 100644
--- a/src/mailman/commands/cli_digests.py
+++ b/src/mailman/commands/cli_digests.py
@@ -19,12 +19,12 @@
import sys
-from mailman import public
from mailman.app.digests import (
bump_digest_number_and_volume, maybe_send_digest_now)
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
from mailman.interfaces.listmanager import IListManager
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_help.py b/src/mailman/commands/cli_help.py
index 9222cd00f..5d6372e51 100644
--- a/src/mailman/commands/cli_help.py
+++ b/src/mailman/commands/cli_help.py
@@ -17,8 +17,8 @@
"""The 'help' subcommand."""
-from mailman import public
from mailman.interfaces.command import ICLISubCommand
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_import.py b/src/mailman/commands/cli_import.py
index 126c026d0..d9384b5bc 100644
--- a/src/mailman/commands/cli_import.py
+++ b/src/mailman/commands/cli_import.py
@@ -21,12 +21,12 @@ import sys
import pickle
from contextlib import ExitStack, contextmanager
-from mailman import public
from mailman.core.i18n import _
from mailman.database.transaction import transactional
from mailman.interfaces.command import ICLISubCommand
from mailman.interfaces.listmanager import IListManager
from mailman.utilities.importer import Import21Error, import_config_pck
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_info.py b/src/mailman/commands/cli_info.py
index fd6c83f88..46643ae1d 100644
--- a/src/mailman/commands/cli_info.py
+++ b/src/mailman/commands/cli_info.py
@@ -20,12 +20,12 @@
import sys
from lazr.config import as_boolean
-from mailman import public
from mailman.config import config
from mailman.core.api import API30, API31
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
from mailman.version import MAILMAN_VERSION_FULL
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_inject.py b/src/mailman/commands/cli_inject.py
index acbc37d67..0255b71d2 100644
--- a/src/mailman/commands/cli_inject.py
+++ b/src/mailman/commands/cli_inject.py
@@ -19,12 +19,12 @@
import sys
-from mailman import public
from mailman.app.inject import inject_text
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
from mailman.interfaces.listmanager import IListManager
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_lists.py b/src/mailman/commands/cli_lists.py
index f5e6d724a..3a598ab05 100644
--- a/src/mailman/commands/cli_lists.py
+++ b/src/mailman/commands/cli_lists.py
@@ -17,7 +17,6 @@
"""The 'lists' subcommand."""
-from mailman import public
from mailman.app.lifecycle import create_list, remove_list
from mailman.core.constants import system_preferences
from mailman.core.i18n import _
@@ -32,6 +31,7 @@ from mailman.interfaces.languages import ILanguageManager
from mailman.interfaces.listmanager import IListManager, ListAlreadyExistsError
from mailman.interfaces.template import ITemplateLoader
from mailman.utilities.string import expand, wrap
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_members.py b/src/mailman/commands/cli_members.py
index 476d1f77d..1eb6550d6 100644
--- a/src/mailman/commands/cli_members.py
+++ b/src/mailman/commands/cli_members.py
@@ -21,7 +21,6 @@ import sys
from contextlib import ExitStack
from email.utils import formataddr, parseaddr
-from mailman import public
from mailman.app.membership import add_member
from mailman.core.i18n import _
from mailman.database.transaction import transactional
@@ -31,6 +30,7 @@ from mailman.interfaces.member import (
AlreadySubscribedError, DeliveryMode, DeliveryStatus, MemberRole)
from mailman.interfaces.subscriptions import RequestRecord
from operator import attrgetter
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_qfile.py b/src/mailman/commands/cli_qfile.py
index f6502f14a..c8d3ec84b 100644
--- a/src/mailman/commands/cli_qfile.py
+++ b/src/mailman/commands/cli_qfile.py
@@ -19,11 +19,11 @@
import pickle
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
from mailman.utilities.interact import interact
from pprint import PrettyPrinter
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_status.py b/src/mailman/commands/cli_status.py
index 6b4abe45e..b60ba8841 100644
--- a/src/mailman/commands/cli_status.py
+++ b/src/mailman/commands/cli_status.py
@@ -19,10 +19,10 @@
import socket
-from mailman import public
from mailman.bin.master import WatcherState, master_state
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_unshunt.py b/src/mailman/commands/cli_unshunt.py
index 6bb1a9800..49b9c6e26 100644
--- a/src/mailman/commands/cli_unshunt.py
+++ b/src/mailman/commands/cli_unshunt.py
@@ -19,10 +19,10 @@
import sys
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_version.py b/src/mailman/commands/cli_version.py
index 4660087de..bc26d0115 100644
--- a/src/mailman/commands/cli_version.py
+++ b/src/mailman/commands/cli_version.py
@@ -17,9 +17,9 @@
"""The Mailman version."""
-from mailman import public
from mailman.interfaces.command import ICLISubCommand
from mailman.version import MAILMAN_VERSION_FULL
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/cli_withlist.py b/src/mailman/commands/cli_withlist.py
index 23250c1a5..42eb57cfc 100644
--- a/src/mailman/commands/cli_withlist.py
+++ b/src/mailman/commands/cli_withlist.py
@@ -23,13 +23,13 @@ import sys
from contextlib import ExitStack, suppress
from functools import partial
from lazr.config import as_boolean
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
from mailman.interfaces.listmanager import IListManager
from mailman.utilities.interact import DEFAULT_BANNER, interact
from mailman.utilities.modules import call_name
+from public import public
from string import Template
from traceback import print_exc
from zope.component import getUtility
diff --git a/src/mailman/commands/eml_confirm.py b/src/mailman/commands/eml_confirm.py
index 6787b0987..425bb00e8 100644
--- a/src/mailman/commands/eml_confirm.py
+++ b/src/mailman/commands/eml_confirm.py
@@ -17,10 +17,10 @@
"""The 'confirm' email command."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.command import ContinueProcessing, IEmailCommand
from mailman.interfaces.subscriptions import ISubscriptionManager, TokenOwner
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/eml_echo.py b/src/mailman/commands/eml_echo.py
index 67f917d3e..db340fda9 100644
--- a/src/mailman/commands/eml_echo.py
+++ b/src/mailman/commands/eml_echo.py
@@ -17,9 +17,9 @@
"""The email command 'echo'."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.command import ContinueProcessing, IEmailCommand
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/eml_end.py b/src/mailman/commands/eml_end.py
index 82b66a1a6..c280cc52f 100644
--- a/src/mailman/commands/eml_end.py
+++ b/src/mailman/commands/eml_end.py
@@ -17,9 +17,9 @@
"""The email commands 'end' and 'stop'."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.command import ContinueProcessing, IEmailCommand
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/eml_help.py b/src/mailman/commands/eml_help.py
index 4ca2d72a4..b4a39009a 100644
--- a/src/mailman/commands/eml_help.py
+++ b/src/mailman/commands/eml_help.py
@@ -17,11 +17,11 @@
"""The email command 'help'."""
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.command import ContinueProcessing, IEmailCommand
from mailman.utilities.string import wrap
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/commands/eml_membership.py b/src/mailman/commands/eml_membership.py
index e658e7b58..22f26e24d 100644
--- a/src/mailman/commands/eml_membership.py
+++ b/src/mailman/commands/eml_membership.py
@@ -18,13 +18,13 @@
"""The email commands 'join' and 'subscribe'."""
from email.utils import formataddr, parseaddr
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.command import ContinueProcessing, IEmailCommand
from mailman.interfaces.member import DeliveryMode, MemberRole
from mailman.interfaces.subscriptions import (
ISubscriptionManager, ISubscriptionService)
from mailman.interfaces.usermanager import IUserManager
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/config/__init__.py b/src/mailman/config/__init__.py
index 5c45d6599..66b298217 100644
--- a/src/mailman/config/__init__.py
+++ b/src/mailman/config/__init__.py
@@ -17,8 +17,8 @@
"""Mailman configuration package."""
-from mailman import public
from mailman.config.config import Configuration
+from public import public
public(config=Configuration())
diff --git a/src/mailman/config/config.py b/src/mailman/config/config.py
index 5454c5e5a..1f4384eb7 100644
--- a/src/mailman/config/config.py
+++ b/src/mailman/config/config.py
@@ -24,13 +24,13 @@ import mailman.templates
from configparser import ConfigParser
from flufl.lock import Lock
from lazr.config import ConfigSchema, as_boolean
-from mailman import public, version
from mailman.interfaces.configuration import (
ConfigurationUpdatedEvent, IConfiguration, MissingConfigurationFileError)
from mailman.interfaces.languages import ILanguageManager
from mailman.utilities.filesystem import makedirs
from mailman.utilities.modules import call_name, expand_path
from pkg_resources import resource_filename, resource_string as resource_bytes
+from public import public, version
from string import Template
from zope.component import getUtility
from zope.event import notify
diff --git a/src/mailman/core/api.py b/src/mailman/core/api.py
index e6e013af0..c9e377bbf 100644
--- a/src/mailman/core/api.py
+++ b/src/mailman/core/api.py
@@ -18,9 +18,9 @@
"""REST web service API contexts."""
from lazr.config import as_boolean
-from mailman import public
from mailman.config import config
from mailman.interfaces.api import IAPI
+from public import public
from uuid import UUID
from zope.interface import implementer
diff --git a/src/mailman/core/chains.py b/src/mailman/core/chains.py
index ec84db2c4..0af61fd2a 100644
--- a/src/mailman/core/chains.py
+++ b/src/mailman/core/chains.py
@@ -17,11 +17,11 @@
"""Application support for chain processing."""
-from mailman import public
from mailman.chains.base import Chain, TerminalChainBase
from mailman.config import config
from mailman.interfaces.chain import IChain, LinkAction
from mailman.utilities.modules import find_components
+from public import public
from zope.interface.verify import verifyObject
diff --git a/src/mailman/core/constants.py b/src/mailman/core/constants.py
index f82783e9f..e5d265256 100644
--- a/src/mailman/core/constants.py
+++ b/src/mailman/core/constants.py
@@ -17,11 +17,11 @@
"""Various constants and enumerations."""
-from mailman import public
from mailman.config import config
from mailman.interfaces.languages import ILanguageManager
from mailman.interfaces.member import DeliveryMode, DeliveryStatus
from mailman.interfaces.preferences import IPreferences
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/core/i18n.py b/src/mailman/core/i18n.py
index 5536fcdaf..345020a13 100644
--- a/src/mailman/core/i18n.py
+++ b/src/mailman/core/i18n.py
@@ -20,8 +20,8 @@
import mailman.messages
from flufl.i18n import PackageStrategy, registry
-from mailman import public
from mailman.interfaces.configuration import ConfigurationUpdatedEvent
+from public import public
public(_=None)
diff --git a/src/mailman/core/initialize.py b/src/mailman/core/initialize.py
index 7b39465c5..6bd1d6777 100644
--- a/src/mailman/core/initialize.py
+++ b/src/mailman/core/initialize.py
@@ -29,10 +29,10 @@ import sys
import mailman.config.config
import mailman.core.logging
-from mailman import public
from mailman.interfaces.database import IDatabaseFactory
from mailman.utilities.modules import call_name
from pkg_resources import resource_string as resource_bytes
+from public import public
from zope.component import getUtility
from zope.configuration import xmlconfig
diff --git a/src/mailman/core/logging.py b/src/mailman/core/logging.py
index a7e8b2554..53bb2cf1c 100644
--- a/src/mailman/core/logging.py
+++ b/src/mailman/core/logging.py
@@ -23,8 +23,8 @@ import codecs
import logging
from lazr.config import as_boolean, as_log_level
-from mailman import public
from mailman.config import config
+from public import public
_handlers = {}
diff --git a/src/mailman/core/pipelines.py b/src/mailman/core/pipelines.py
index 5df21ed15..fb663cee9 100644
--- a/src/mailman/core/pipelines.py
+++ b/src/mailman/core/pipelines.py
@@ -19,7 +19,6 @@
import logging
-from mailman import public
from mailman.app.bounces import bounce_message
from mailman.config import config
from mailman.core.i18n import _
@@ -27,6 +26,7 @@ from mailman.interfaces.handler import IHandler
from mailman.interfaces.pipeline import (
DiscardMessage, IPipeline, RejectMessage)
from mailman.utilities.modules import find_components
+from public import public
from zope.interface import implementer
from zope.interface.verify import verifyObject
diff --git a/src/mailman/core/rules.py b/src/mailman/core/rules.py
index f6ca87726..680d4f007 100644
--- a/src/mailman/core/rules.py
+++ b/src/mailman/core/rules.py
@@ -17,10 +17,10 @@
"""Various rule helpers"""
-from mailman import public
from mailman.config import config
from mailman.interfaces.rules import IRule
from mailman.utilities.modules import find_components
+from public import public
from zope.interface.verify import verifyObject
diff --git a/src/mailman/core/runner.py b/src/mailman/core/runner.py
index d0ff6f5ce..ed1c26d38 100644
--- a/src/mailman/core/runner.py
+++ b/src/mailman/core/runner.py
@@ -25,7 +25,6 @@ import traceback
from contextlib import suppress
from io import StringIO
from lazr.config import as_boolean, as_timedelta
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.core.logging import reopen
@@ -34,6 +33,7 @@ from mailman.interfaces.languages import ILanguageManager
from mailman.interfaces.listmanager import IListManager
from mailman.interfaces.runner import IRunner, RunnerCrashEvent
from mailman.utilities.string import expand
+from public import public
from zope.component import getUtility
from zope.event import notify
from zope.interface import implementer
diff --git a/src/mailman/core/switchboard.py b/src/mailman/core/switchboard.py
index cfbb371ba..f03ee11e5 100644
--- a/src/mailman/core/switchboard.py
+++ b/src/mailman/core/switchboard.py
@@ -31,13 +31,13 @@ import pickle
import hashlib
import logging
-from mailman import public
from mailman.config import config
from mailman.email.message import Message
from mailman.interfaces.configuration import ConfigurationUpdatedEvent
from mailman.interfaces.switchboard import ISwitchboard
from mailman.utilities.filesystem import makedirs
from mailman.utilities.string import expand
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/core/system.py b/src/mailman/core/system.py
index ee88c5adf..2d76f0c97 100644
--- a/src/mailman/core/system.py
+++ b/src/mailman/core/system.py
@@ -19,8 +19,8 @@
import sys
-from mailman import public, version
from mailman.interfaces.system import ISystem
+from public import public, version
from zope.interface import implementer
diff --git a/src/mailman/database/alembic/__init__.py b/src/mailman/database/alembic/__init__.py
index af2596f04..ff74113d7 100644
--- a/src/mailman/database/alembic/__init__.py
+++ b/src/mailman/database/alembic/__init__.py
@@ -18,8 +18,8 @@
"""Alembic configuration initization."""
from alembic.config import Config
-from mailman import public
from mailman.utilities.modules import expand_path
+from public import public
public(alembic_cfg=Config(expand_path('python:mailman.config.alembic')))
diff --git a/src/mailman/database/alembic/env.py b/src/mailman/database/alembic/env.py
index c7a5e151d..e359b201d 100644
--- a/src/mailman/database/alembic/env.py
+++ b/src/mailman/database/alembic/env.py
@@ -19,11 +19,11 @@
from alembic import context
from contextlib import closing
-from mailman import public
from mailman.config import config
from mailman.core.initialize import initialize_1
from mailman.database.model import Model
from mailman.utilities.string import expand
+from public import public
from sqlalchemy import create_engine
diff --git a/src/mailman/database/base.py b/src/mailman/database/base.py
index f57228029..586e1b20d 100644
--- a/src/mailman/database/base.py
+++ b/src/mailman/database/base.py
@@ -19,10 +19,10 @@
import logging
-from mailman import public
from mailman.config import config
from mailman.interfaces.database import IDatabase
from mailman.utilities.string import expand
+from public import public
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from zope.interface import implementer
diff --git a/src/mailman/database/factory.py b/src/mailman/database/factory.py
index ff7fa59a9..4d003c39c 100644
--- a/src/mailman/database/factory.py
+++ b/src/mailman/database/factory.py
@@ -24,13 +24,13 @@ import alembic.command
from alembic.migration import MigrationContext
from alembic.script import ScriptDirectory
from flufl.lock import Lock
-from mailman import public
from mailman.config import config
from mailman.database.alembic import alembic_cfg
from mailman.database.model import Model
from mailman.interfaces.database import (
DatabaseError, IDatabase, IDatabaseFactory)
from mailman.utilities.modules import call_name
+from public import public
from sqlalchemy import MetaData
from zope.interface import implementer
from zope.interface.verify import verifyObject
diff --git a/src/mailman/database/helpers.py b/src/mailman/database/helpers.py
index b1dc381df..27c870058 100644
--- a/src/mailman/database/helpers.py
+++ b/src/mailman/database/helpers.py
@@ -19,7 +19,7 @@
import sqlalchemy as sa
-from mailman import public
+from public import public
@public
diff --git a/src/mailman/database/model.py b/src/mailman/database/model.py
index c2ee90491..098f62d4b 100644
--- a/src/mailman/database/model.py
+++ b/src/mailman/database/model.py
@@ -18,8 +18,8 @@
"""Base class for all database classes."""
from contextlib import closing
-from mailman import public
from mailman.config import config
+from public import public
from sqlalchemy.ext.declarative import declarative_base
diff --git a/src/mailman/database/mysql.py b/src/mailman/database/mysql.py
index 0c0de54a9..cff16e208 100644
--- a/src/mailman/database/mysql.py
+++ b/src/mailman/database/mysql.py
@@ -17,9 +17,9 @@
"""MySQL database support"""
-from mailman import public
from mailman.database.base import SABaseDatabase
from mailman.database.model import Model
+from public import public
@public
diff --git a/src/mailman/database/postgresql.py b/src/mailman/database/postgresql.py
index b1095e45f..d0c208a50 100644
--- a/src/mailman/database/postgresql.py
+++ b/src/mailman/database/postgresql.py
@@ -17,9 +17,9 @@
"""PostgreSQL database support."""
-from mailman import public
from mailman.database.base import SABaseDatabase
from mailman.database.model import Model
+from public import public
from sqlalchemy import Integer
diff --git a/src/mailman/database/sqlite.py b/src/mailman/database/sqlite.py
index 08700bfb2..3659efaff 100644
--- a/src/mailman/database/sqlite.py
+++ b/src/mailman/database/sqlite.py
@@ -19,8 +19,8 @@
import os
-from mailman import public
from mailman.database.base import SABaseDatabase
+from public import public
from urllib.parse import urlparse
diff --git a/src/mailman/database/transaction.py b/src/mailman/database/transaction.py
index 09dfda8e3..1b5368a39 100644
--- a/src/mailman/database/transaction.py
+++ b/src/mailman/database/transaction.py
@@ -18,8 +18,8 @@
"""Transactional support."""
from contextlib import contextmanager
-from mailman import public
from mailman.config import config
+from public import public
@public
diff --git a/src/mailman/database/types.py b/src/mailman/database/types.py
index bbd040d96..10b826e7c 100644
--- a/src/mailman/database/types.py
+++ b/src/mailman/database/types.py
@@ -19,7 +19,7 @@
import uuid
-from mailman import public
+from public import public
from sqlalchemy import Integer
from sqlalchemy.dialects import postgresql
from sqlalchemy.ext.compiler import compiles
diff --git a/src/mailman/docs/__init__.py b/src/mailman/docs/__init__.py
index 68c7bb4cf..939c1e6e6 100644
--- a/src/mailman/docs/__init__.py
+++ b/src/mailman/docs/__init__.py
@@ -17,8 +17,8 @@
"""General Mailman doc tests."""
-from mailman import public
from mailman.testing.layers import ConfigLayer
+from public import public
public(layer=ConfigLayer)
diff --git a/src/mailman/email/message.py b/src/mailman/email/message.py
index 26bc35b78..da2ce837f 100644
--- a/src/mailman/email/message.py
+++ b/src/mailman/email/message.py
@@ -29,9 +29,9 @@ import email.utils
from email.header import Header
from email.mime.multipart import MIMEMultipart
-from mailman import public
from mailman.config import config
from mailman.interfaces.member import DeliveryStatus
+from public import public
COMMASPACE = ', '
diff --git a/src/mailman/email/validate.py b/src/mailman/email/validate.py
index 99371d9e5..be8ba775a 100644
--- a/src/mailman/email/validate.py
+++ b/src/mailman/email/validate.py
@@ -19,10 +19,10 @@
import re
-from mailman import public
from mailman.interfaces.address import (
IEmailValidator, InvalidEmailAddressError)
from mailman.utilities.email import split_email
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/acknowledge.py b/src/mailman/handlers/acknowledge.py
index c7035de67..56608a3e9 100644
--- a/src/mailman/handlers/acknowledge.py
+++ b/src/mailman/handlers/acknowledge.py
@@ -20,13 +20,13 @@
This only happens if the sender has set their AcknowledgePosts attribute.
"""
-from mailman import public
from mailman.core.i18n import _
from mailman.email.message import UserNotification
from mailman.interfaces.handler import IHandler
from mailman.interfaces.languages import ILanguageManager
from mailman.interfaces.template import ITemplateLoader
from mailman.utilities.string import expand, oneline
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/handlers/after_delivery.py b/src/mailman/handlers/after_delivery.py
index efe38ec63..928f90f76 100644
--- a/src/mailman/handlers/after_delivery.py
+++ b/src/mailman/handlers/after_delivery.py
@@ -17,10 +17,10 @@
"""Perform some bookkeeping after a successful post."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
from mailman.utilities.datetime import now
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/avoid_duplicates.py b/src/mailman/handlers/avoid_duplicates.py
index 59cb568de..7fe2136da 100644
--- a/src/mailman/handlers/avoid_duplicates.py
+++ b/src/mailman/handlers/avoid_duplicates.py
@@ -24,9 +24,9 @@ warning header, or pass it through, depending on the user's preferences.
"""
from email.utils import getaddresses, formataddr
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/cleanse.py b/src/mailman/handlers/cleanse.py
index 56add9ef7..8704491f6 100644
--- a/src/mailman/handlers/cleanse.py
+++ b/src/mailman/handlers/cleanse.py
@@ -20,10 +20,10 @@
import logging
from email.utils import formataddr
-from mailman import public
from mailman.core.i18n import _
from mailman.handlers.cook_headers import uheader
from mailman.interfaces.handler import IHandler
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/cleanse_dkim.py b/src/mailman/handlers/cleanse_dkim.py
index 72a9c5e81..cc04858be 100644
--- a/src/mailman/handlers/cleanse_dkim.py
+++ b/src/mailman/handlers/cleanse_dkim.py
@@ -26,10 +26,10 @@ originating at the Mailman server for the outgoing message.
"""
from lazr.config import as_boolean
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/cook_headers.py b/src/mailman/handlers/cook_headers.py
index 5f203fcbd..672738bf9 100644
--- a/src/mailman/handlers/cook_headers.py
+++ b/src/mailman/handlers/cook_headers.py
@@ -22,11 +22,11 @@ import logging
from email.header import Header
from email.utils import formataddr, getaddresses, parseaddr
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
from mailman.interfaces.mailinglist import Personalization, ReplyToMunging
from mailman.version import VERSION
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/decorate.py b/src/mailman/handlers/decorate.py
index 7f5519fd0..6a16dfc76 100644
--- a/src/mailman/handlers/decorate.py
+++ b/src/mailman/handlers/decorate.py
@@ -22,13 +22,13 @@ import logging
from email.mime.text import MIMEText
from email.utils import formataddr
-from mailman import public
from mailman.core.i18n import _
from mailman.email.message import Message
from mailman.interfaces.handler import IHandler
from mailman.interfaces.mailinglist import IListArchiverSet
from mailman.interfaces.template import ITemplateLoader
from mailman.utilities.string import expand
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/handlers/file_recipients.py b/src/mailman/handlers/file_recipients.py
index 95160706a..e283d936e 100644
--- a/src/mailman/handlers/file_recipients.py
+++ b/src/mailman/handlers/file_recipients.py
@@ -20,9 +20,9 @@
import os
import errno
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/member_recipients.py b/src/mailman/handlers/member_recipients.py
index ffcecfb18..309603ef0 100644
--- a/src/mailman/handlers/member_recipients.py
+++ b/src/mailman/handlers/member_recipients.py
@@ -23,13 +23,13 @@ on the `recipients' attribute of the message. This attribute is used by the
SendmailDeliver and BulkDeliver modules.
"""
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
from mailman.interfaces.member import DeliveryStatus
from mailman.interfaces.pipeline import RejectMessage
from mailman.utilities.string import wrap
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/mime_delete.py b/src/mailman/handlers/mime_delete.py
index b88c40b0c..ac56e5dd6 100644
--- a/src/mailman/handlers/mime_delete.py
+++ b/src/mailman/handlers/mime_delete.py
@@ -36,7 +36,6 @@ from email.mime.message import MIMEMessage
from email.mime.text import MIMEText
from itertools import count
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
@@ -45,6 +44,7 @@ from mailman.interfaces.handler import IHandler
from mailman.interfaces.pipeline import DiscardMessage, RejectMessage
from mailman.utilities.string import oneline
from mailman.version import VERSION
+from public import public
from string import Template
from zope.interface import implementer
diff --git a/src/mailman/handlers/owner_recipients.py b/src/mailman/handlers/owner_recipients.py
index 9ef2568f5..4a4ee9a24 100644
--- a/src/mailman/handlers/owner_recipients.py
+++ b/src/mailman/handlers/owner_recipients.py
@@ -17,11 +17,11 @@
"""Calculate the list owner recipients (includes moderators)."""
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
from mailman.interfaces.member import DeliveryStatus
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/replybot.py b/src/mailman/handlers/replybot.py
index a86ccbbf3..e8b9e4fc6 100644
--- a/src/mailman/handlers/replybot.py
+++ b/src/mailman/handlers/replybot.py
@@ -19,7 +19,6 @@
import logging
-from mailman import public
from mailman.core.i18n import _
from mailman.email.message import UserNotification
from mailman.interfaces.autorespond import (
@@ -28,6 +27,7 @@ from mailman.interfaces.handler import IHandler
from mailman.interfaces.usermanager import IUserManager
from mailman.utilities.datetime import today
from mailman.utilities.string import expand, wrap
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/handlers/rfc_2369.py b/src/mailman/handlers/rfc_2369.py
index e042bc5e3..7f36dd057 100644
--- a/src/mailman/handlers/rfc_2369.py
+++ b/src/mailman/handlers/rfc_2369.py
@@ -20,12 +20,12 @@
import logging
from email.utils import formataddr
-from mailman import public
from mailman.core.i18n import _
from mailman.handlers.cook_headers import uheader
from mailman.interfaces.archiver import ArchivePolicy
from mailman.interfaces.handler import IHandler
from mailman.interfaces.mailinglist import IListArchiverSet
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/subject_prefix.py b/src/mailman/handlers/subject_prefix.py
index 20f47fc5d..7bb1a3e5d 100644
--- a/src/mailman/handlers/subject_prefix.py
+++ b/src/mailman/handlers/subject_prefix.py
@@ -21,9 +21,9 @@ import re
from contextlib import suppress
from email.header import Header, decode_header, make_header
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/tagger.py b/src/mailman/handlers/tagger.py
index fb0a24ba5..f7c637085 100644
--- a/src/mailman/handlers/tagger.py
+++ b/src/mailman/handlers/tagger.py
@@ -21,9 +21,9 @@ import re
import email.iterators
import email.parser
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/to_archive.py b/src/mailman/handlers/to_archive.py
index d5b980ab4..d2805ea3e 100644
--- a/src/mailman/handlers/to_archive.py
+++ b/src/mailman/handlers/to_archive.py
@@ -17,11 +17,11 @@
"""Add the message to the archives."""
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.archiver import ArchivePolicy
from mailman.interfaces.handler import IHandler
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/to_digest.py b/src/mailman/handlers/to_digest.py
index 671a2197c..2de911f46 100644
--- a/src/mailman/handlers/to_digest.py
+++ b/src/mailman/handlers/to_digest.py
@@ -19,11 +19,11 @@
import os
-from mailman import public
from mailman.app.digests import maybe_send_digest_now
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
from mailman.utilities.mailbox import Mailbox
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/to_outgoing.py b/src/mailman/handlers/to_outgoing.py
index b9fae912c..4726973f2 100644
--- a/src/mailman/handlers/to_outgoing.py
+++ b/src/mailman/handlers/to_outgoing.py
@@ -22,10 +22,10 @@ posted to the list membership. Anything else that needs to go out to some
recipient should just be placed in the out queue directly.
"""
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/handlers/to_usenet.py b/src/mailman/handlers/to_usenet.py
index 4bfa00c5f..f5e01ef6e 100644
--- a/src/mailman/handlers/to_usenet.py
+++ b/src/mailman/handlers/to_usenet.py
@@ -19,10 +19,10 @@
import logging
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.handler import IHandler
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/interfaces/action.py b/src/mailman/interfaces/action.py
index dcff41cbd..08dc9c5ca 100644
--- a/src/mailman/interfaces/action.py
+++ b/src/mailman/interfaces/action.py
@@ -18,7 +18,7 @@
"""Message actions."""
from enum import Enum
-from mailman import public
+from public import public
@public
diff --git a/src/mailman/interfaces/address.py b/src/mailman/interfaces/address.py
index 8a1ac81d5..d460e96ca 100644
--- a/src/mailman/interfaces/address.py
+++ b/src/mailman/interfaces/address.py
@@ -17,8 +17,8 @@
"""Interface for email address related information."""
-from mailman import public
from mailman.interfaces.errors import MailmanError
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/api.py b/src/mailman/interfaces/api.py
index 3ba158b35..e2c6645db 100644
--- a/src/mailman/interfaces/api.py
+++ b/src/mailman/interfaces/api.py
@@ -17,7 +17,7 @@
"""REST web service API context."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/archiver.py b/src/mailman/interfaces/archiver.py
index cd10b22e3..eb9227dd8 100644
--- a/src/mailman/interfaces/archiver.py
+++ b/src/mailman/interfaces/archiver.py
@@ -18,7 +18,7 @@
"""Interface for archiving schemes."""
from enum import Enum
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/autorespond.py b/src/mailman/interfaces/autorespond.py
index 645a6c76b..b9f3f0e3a 100644
--- a/src/mailman/interfaces/autorespond.py
+++ b/src/mailman/interfaces/autorespond.py
@@ -19,7 +19,7 @@
from datetime import timedelta
from enum import Enum
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/bans.py b/src/mailman/interfaces/bans.py
index 055ad69a3..59928ff8e 100644
--- a/src/mailman/interfaces/bans.py
+++ b/src/mailman/interfaces/bans.py
@@ -17,7 +17,7 @@
"""Manager of email address bans."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/bounce.py b/src/mailman/interfaces/bounce.py
index 0e39ca3b9..368657c47 100644
--- a/src/mailman/interfaces/bounce.py
+++ b/src/mailman/interfaces/bounce.py
@@ -18,7 +18,7 @@
"""Interface to bounce detection components."""
from enum import Enum
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/cache.py b/src/mailman/interfaces/cache.py
index 74fb2084a..39d3e7c73 100644
--- a/src/mailman/interfaces/cache.py
+++ b/src/mailman/interfaces/cache.py
@@ -17,7 +17,7 @@
"""File caches."""
-from mailman import public
+from public import public
from zope.interface import Interface
diff --git a/src/mailman/interfaces/chain.py b/src/mailman/interfaces/chain.py
index 0af9bf8e5..146abafd7 100644
--- a/src/mailman/interfaces/chain.py
+++ b/src/mailman/interfaces/chain.py
@@ -18,7 +18,7 @@
"""Interfaces describing the basics of chains and links."""
from enum import Enum
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/command.py b/src/mailman/interfaces/command.py
index 95719b504..be3fd5bb2 100644
--- a/src/mailman/interfaces/command.py
+++ b/src/mailman/interfaces/command.py
@@ -18,7 +18,7 @@
"""Interfaces defining email commands."""
from enum import Enum
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/configuration.py b/src/mailman/interfaces/configuration.py
index 2e38e614c..b4f9d696c 100644
--- a/src/mailman/interfaces/configuration.py
+++ b/src/mailman/interfaces/configuration.py
@@ -17,8 +17,8 @@
"""Configuration system interface."""
-from mailman import public
from mailman.interfaces.errors import MailmanError
+from public import public
from zope.interface import Interface
diff --git a/src/mailman/interfaces/database.py b/src/mailman/interfaces/database.py
index 1f658c556..052c7d4bb 100644
--- a/src/mailman/interfaces/database.py
+++ b/src/mailman/interfaces/database.py
@@ -17,8 +17,8 @@
"""Interfaces for database interaction."""
-from mailman import public
from mailman.interfaces.errors import MailmanError
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/digests.py b/src/mailman/interfaces/digests.py
index cff838284..fd38b374a 100644
--- a/src/mailman/interfaces/digests.py
+++ b/src/mailman/interfaces/digests.py
@@ -18,7 +18,7 @@
"""One last digest."""
from enum import Enum
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/domain.py b/src/mailman/interfaces/domain.py
index b1940f400..6318e9551 100644
--- a/src/mailman/interfaces/domain.py
+++ b/src/mailman/interfaces/domain.py
@@ -17,8 +17,8 @@
"""Interface representing domains."""
-from mailman import public
from mailman.interfaces.errors import MailmanError
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/errors.py b/src/mailman/interfaces/errors.py
index dbf74c035..b21d07418 100644
--- a/src/mailman/interfaces/errors.py
+++ b/src/mailman/interfaces/errors.py
@@ -22,7 +22,7 @@ components. More specific exceptions will be located in the relevant
interfaces.
"""
-from mailman import public
+from public import public
@public
diff --git a/src/mailman/interfaces/handler.py b/src/mailman/interfaces/handler.py
index f6b2aea66..29061c369 100644
--- a/src/mailman/interfaces/handler.py
+++ b/src/mailman/interfaces/handler.py
@@ -17,7 +17,7 @@
"""Interface describing a pipeline handler."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/languages.py b/src/mailman/interfaces/languages.py
index b45083575..18f928be9 100644
--- a/src/mailman/interfaces/languages.py
+++ b/src/mailman/interfaces/languages.py
@@ -17,7 +17,7 @@
"""Interfaces for managing languages."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/listmanager.py b/src/mailman/interfaces/listmanager.py
index 2c7208496..dde23ab1f 100644
--- a/src/mailman/interfaces/listmanager.py
+++ b/src/mailman/interfaces/listmanager.py
@@ -17,8 +17,8 @@
"""Interface for list storage, deleting, and finding."""
-from mailman import public
from mailman.interfaces.errors import MailmanError
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/mailinglist.py b/src/mailman/interfaces/mailinglist.py
index 877016f41..359cd5069 100644
--- a/src/mailman/interfaces/mailinglist.py
+++ b/src/mailman/interfaces/mailinglist.py
@@ -18,8 +18,8 @@
"""Interface for a mailing list."""
from enum import Enum
-from mailman import public
from mailman.interfaces.member import MemberRole
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/member.py b/src/mailman/interfaces/member.py
index 094652521..a2a9c7cbd 100644
--- a/src/mailman/interfaces/member.py
+++ b/src/mailman/interfaces/member.py
@@ -18,8 +18,8 @@
"""Interface describing the basics of a member."""
from enum import Enum
-from mailman import public
from mailman.interfaces.errors import MailmanError
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/messages.py b/src/mailman/interfaces/messages.py
index 2ea2aa312..29f92fdc7 100644
--- a/src/mailman/interfaces/messages.py
+++ b/src/mailman/interfaces/messages.py
@@ -17,7 +17,7 @@
"""The message storage service."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/mime.py b/src/mailman/interfaces/mime.py
index c1a6e050f..94a98b58e 100644
--- a/src/mailman/interfaces/mime.py
+++ b/src/mailman/interfaces/mime.py
@@ -18,7 +18,7 @@
"""MIME content filtering."""
from enum import Enum
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/mlistrequest.py b/src/mailman/interfaces/mlistrequest.py
index 45712ed86..ca83f77c1 100644
--- a/src/mailman/interfaces/mlistrequest.py
+++ b/src/mailman/interfaces/mlistrequest.py
@@ -17,7 +17,7 @@
"""Interface for a web request accessing a mailing list."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/mta.py b/src/mailman/interfaces/mta.py
index 47436ead5..2917c0f79 100644
--- a/src/mailman/interfaces/mta.py
+++ b/src/mailman/interfaces/mta.py
@@ -17,8 +17,8 @@
"""Interface for mail transport agent integration."""
-from mailman import public
from mailman.interfaces.errors import MailmanError
+from public import public
from zope.interface import Interface
diff --git a/src/mailman/interfaces/nntp.py b/src/mailman/interfaces/nntp.py
index 72a74fe90..2bb9c45b1 100644
--- a/src/mailman/interfaces/nntp.py
+++ b/src/mailman/interfaces/nntp.py
@@ -18,7 +18,7 @@
"""NNTP and newsgroup interfaces."""
from enum import Enum
-from mailman import public
+from public import public
@public
diff --git a/src/mailman/interfaces/pending.py b/src/mailman/interfaces/pending.py
index cf92fed9e..c630e2133 100644
--- a/src/mailman/interfaces/pending.py
+++ b/src/mailman/interfaces/pending.py
@@ -22,7 +22,7 @@ maps these events to a unique hash that can be used as a token for end user
confirmation.
"""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/pipeline.py b/src/mailman/interfaces/pipeline.py
index cdef6a768..a41e9b6f7 100644
--- a/src/mailman/interfaces/pipeline.py
+++ b/src/mailman/interfaces/pipeline.py
@@ -17,7 +17,7 @@
"""Interface for describing pipelines."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/preferences.py b/src/mailman/interfaces/preferences.py
index 024fdea3c..0d830bdd7 100644
--- a/src/mailman/interfaces/preferences.py
+++ b/src/mailman/interfaces/preferences.py
@@ -17,7 +17,7 @@
"""Interface for preferences."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/requests.py b/src/mailman/interfaces/requests.py
index 3098772a9..8b316e79f 100644
--- a/src/mailman/interfaces/requests.py
+++ b/src/mailman/interfaces/requests.py
@@ -22,7 +22,7 @@ moderators, such as subscription requests and held messages.
"""
from enum import Enum
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/roster.py b/src/mailman/interfaces/roster.py
index 2993e4fc4..bf8489e33 100644
--- a/src/mailman/interfaces/roster.py
+++ b/src/mailman/interfaces/roster.py
@@ -17,7 +17,7 @@
"""Interface for a roster of members."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/rules.py b/src/mailman/interfaces/rules.py
index 9f5f1365e..cca8cf565 100644
--- a/src/mailman/interfaces/rules.py
+++ b/src/mailman/interfaces/rules.py
@@ -17,7 +17,7 @@
"""Interface describing the basics of rules."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/runner.py b/src/mailman/interfaces/runner.py
index e39efb097..06caf0e95 100644
--- a/src/mailman/interfaces/runner.py
+++ b/src/mailman/interfaces/runner.py
@@ -17,7 +17,7 @@
"""Interface for runners."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/styles.py b/src/mailman/interfaces/styles.py
index a183933f7..e4b5288c1 100644
--- a/src/mailman/interfaces/styles.py
+++ b/src/mailman/interfaces/styles.py
@@ -17,8 +17,8 @@
"""Interfaces for list styles."""
-from mailman import public
from mailman.interfaces.errors import MailmanError
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/subscriptions.py b/src/mailman/interfaces/subscriptions.py
index 284261de5..dc3563def 100644
--- a/src/mailman/interfaces/subscriptions.py
+++ b/src/mailman/interfaces/subscriptions.py
@@ -19,9 +19,9 @@
from collections import namedtuple
from enum import Enum
-from mailman import public
from mailman.interfaces.errors import MailmanError
from mailman.interfaces.member import DeliveryMode, MembershipError
+from public import public
from zope.interface import Interface
diff --git a/src/mailman/interfaces/switchboard.py b/src/mailman/interfaces/switchboard.py
index 4428f4b12..d9e2f9aab 100644
--- a/src/mailman/interfaces/switchboard.py
+++ b/src/mailman/interfaces/switchboard.py
@@ -17,7 +17,7 @@
"""Interface for switchboards."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/system.py b/src/mailman/interfaces/system.py
index 1b0a9a2de..440611537 100644
--- a/src/mailman/interfaces/system.py
+++ b/src/mailman/interfaces/system.py
@@ -17,7 +17,7 @@
"""System information."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/template.py b/src/mailman/interfaces/template.py
index 24f956b78..6b6bcd7a3 100644
--- a/src/mailman/interfaces/template.py
+++ b/src/mailman/interfaces/template.py
@@ -17,7 +17,7 @@
"""Template downloader with cache."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/user.py b/src/mailman/interfaces/user.py
index a6c470b6e..e103f38fd 100644
--- a/src/mailman/interfaces/user.py
+++ b/src/mailman/interfaces/user.py
@@ -17,8 +17,8 @@
"""Interface describing the basics of a user."""
-from mailman import public
from mailman.interfaces.address import AddressError
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/usermanager.py b/src/mailman/interfaces/usermanager.py
index 87d4bf6e2..4cd8af7aa 100644
--- a/src/mailman/interfaces/usermanager.py
+++ b/src/mailman/interfaces/usermanager.py
@@ -17,7 +17,7 @@
"""Interface describing the user management service."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/interfaces/workflow.py b/src/mailman/interfaces/workflow.py
index 9846f4683..b0b5a23da 100644
--- a/src/mailman/interfaces/workflow.py
+++ b/src/mailman/interfaces/workflow.py
@@ -17,7 +17,7 @@
"""Interfaces describing the state of a workflow."""
-from mailman import public
+from public import public
from zope.interface import Attribute, Interface
diff --git a/src/mailman/languages/language.py b/src/mailman/languages/language.py
index 014852c5c..afe217048 100644
--- a/src/mailman/languages/language.py
+++ b/src/mailman/languages/language.py
@@ -18,8 +18,8 @@
"""The representation of a language."""
-from mailman import public
from mailman.interfaces.languages import ILanguage
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/languages/manager.py b/src/mailman/languages/manager.py
index 9832eb3eb..5e56ec0e0 100644
--- a/src/mailman/languages/manager.py
+++ b/src/mailman/languages/manager.py
@@ -17,10 +17,10 @@
"""Language manager."""
-from mailman import public
from mailman.interfaces.configuration import ConfigurationUpdatedEvent
from mailman.interfaces.languages import ILanguageManager
from mailman.languages.language import Language
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/model/address.py b/src/mailman/model/address.py
index a31e9a429..63896c728 100644
--- a/src/mailman/model/address.py
+++ b/src/mailman/model/address.py
@@ -18,12 +18,12 @@
"""Model for addresses."""
from email.utils import formataddr
-from mailman import public
from mailman.database.model import Model
from mailman.database.types import SAUnicode
from mailman.interfaces.address import (
AddressVerificationEvent, IAddress, IEmailValidator)
from mailman.utilities.datetime import now
+from public import public
from sqlalchemy import Column, DateTime, ForeignKey, Integer
from sqlalchemy.orm import backref, relationship
from zope.component import getUtility
diff --git a/src/mailman/model/autorespond.py b/src/mailman/model/autorespond.py
index 20c19889f..e9509c4f8 100644
--- a/src/mailman/model/autorespond.py
+++ b/src/mailman/model/autorespond.py
@@ -17,13 +17,13 @@
"""Autoresponder records."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import Enum
from mailman.interfaces.autorespond import (
IAutoResponseRecord, IAutoResponseSet, Response)
from mailman.utilities.datetime import today
+from public import public
from sqlalchemy import Column, Date, ForeignKey, Integer, desc
from sqlalchemy.orm import relationship
from zope.interface import implementer
diff --git a/src/mailman/model/bans.py b/src/mailman/model/bans.py
index c8d43c5ae..1c4cbde8c 100644
--- a/src/mailman/model/bans.py
+++ b/src/mailman/model/bans.py
@@ -19,12 +19,12 @@
import re
-from mailman import public
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import SAUnicode
from mailman.interfaces.bans import IBan, IBanManager
from mailman.utilities.queries import QuerySequence
+from public import public
from sqlalchemy import Column, Integer
from zope.interface import implementer
diff --git a/src/mailman/model/bounce.py b/src/mailman/model/bounce.py
index 856d91f20..6db55a3c7 100644
--- a/src/mailman/model/bounce.py
+++ b/src/mailman/model/bounce.py
@@ -17,13 +17,13 @@
"""Bounce support."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import Enum, SAUnicode
from mailman.interfaces.bounce import (
BounceContext, IBounceEvent, IBounceProcessor)
from mailman.utilities.datetime import now
+from public import public
from sqlalchemy import Boolean, Column, DateTime, Integer
from zope.interface import implementer
diff --git a/src/mailman/model/cache.py b/src/mailman/model/cache.py
index 6be5fbc9d..d1ef9f05c 100644
--- a/src/mailman/model/cache.py
+++ b/src/mailman/model/cache.py
@@ -22,13 +22,13 @@ import hashlib
from contextlib import ExitStack
from lazr.config import as_timedelta
-from mailman import public
from mailman.config import config
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import SAUnicode
from mailman.interfaces.cache import ICacheManager
from mailman.utilities.datetime import now
+from public import public
from sqlalchemy import Boolean, Column, DateTime, Integer
from zope.interface import implementer
diff --git a/src/mailman/model/digests.py b/src/mailman/model/digests.py
index ac49249cc..a0daaebbc 100644
--- a/src/mailman/model/digests.py
+++ b/src/mailman/model/digests.py
@@ -17,11 +17,11 @@
"""One last digest."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.types import Enum
from mailman.interfaces.digests import IOneLastDigest
from mailman.interfaces.member import DeliveryMode
+from public import public
from sqlalchemy import Column, ForeignKey, Integer
from sqlalchemy.orm import relationship
from zope.interface import implementer
diff --git a/src/mailman/model/domain.py b/src/mailman/model/domain.py
index 5bb569585..2622ba80b 100644
--- a/src/mailman/model/domain.py
+++ b/src/mailman/model/domain.py
@@ -17,7 +17,6 @@
"""Domains."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import SAUnicode
@@ -27,6 +26,7 @@ from mailman.interfaces.domain import (
from mailman.interfaces.user import IUser
from mailman.interfaces.usermanager import IUserManager
from mailman.model.mailinglist import MailingList
+from public import public
from sqlalchemy import Column, Integer
from sqlalchemy.orm import relationship
from zope.component import getUtility
diff --git a/src/mailman/model/language.py b/src/mailman/model/language.py
index 596e580e1..c762b9715 100644
--- a/src/mailman/model/language.py
+++ b/src/mailman/model/language.py
@@ -17,10 +17,10 @@
"""Model for languages."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.types import SAUnicode
from mailman.interfaces.languages import ILanguage
+from public import public
from sqlalchemy import Column, Integer
from zope.interface import implementer
diff --git a/src/mailman/model/listmanager.py b/src/mailman/model/listmanager.py
index e2519af5b..bd07e6c27 100644
--- a/src/mailman/model/listmanager.py
+++ b/src/mailman/model/listmanager.py
@@ -17,7 +17,6 @@
"""A mailing list manager."""
-from mailman import public
from mailman.database.transaction import dbconnection
from mailman.interfaces.address import InvalidEmailAddressError
from mailman.interfaces.listmanager import (
@@ -30,6 +29,7 @@ from mailman.model.mailinglist import (
from mailman.model.mime import ContentFilter
from mailman.utilities.datetime import now
from mailman.utilities.queries import QuerySequence
+from public import public
from zope.event import notify
from zope.interface import implementer
diff --git a/src/mailman/model/mailinglist.py b/src/mailman/model/mailinglist.py
index eec58ad04..bd6538aaf 100644
--- a/src/mailman/model/mailinglist.py
+++ b/src/mailman/model/mailinglist.py
@@ -19,7 +19,6 @@
import os
-from mailman import public
from mailman.config import config
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
@@ -49,6 +48,7 @@ from mailman.model.mime import ContentFilter
from mailman.model.preferences import Preferences
from mailman.utilities.filesystem import makedirs
from mailman.utilities.string import expand
+from public import public
from sqlalchemy import (
Boolean, Column, DateTime, Float, ForeignKey, Integer, Interval,
LargeBinary, PickleType)
diff --git a/src/mailman/model/member.py b/src/mailman/model/member.py
index aacaa73b6..93d0c7feb 100644
--- a/src/mailman/model/member.py
+++ b/src/mailman/model/member.py
@@ -17,7 +17,6 @@
"""Model for members."""
-from mailman import public
from mailman.core.constants import system_preferences
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
@@ -30,6 +29,7 @@ from mailman.interfaces.member import (
from mailman.interfaces.user import IUser, UnverifiedAddressError
from mailman.interfaces.usermanager import IUserManager
from mailman.utilities.uid import UIDFactory
+from public import public
from sqlalchemy import Column, ForeignKey, Integer
from sqlalchemy.orm import relationship
from zope.component import getUtility
diff --git a/src/mailman/model/message.py b/src/mailman/model/message.py
index 576baab5c..233e8b5b5 100644
--- a/src/mailman/model/message.py
+++ b/src/mailman/model/message.py
@@ -17,11 +17,11 @@
"""Model for messages."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import SAUnicode
from mailman.interfaces.messages import IMessage
+from public import public
from sqlalchemy import Column, Integer
from zope.interface import implementer
diff --git a/src/mailman/model/messagestore.py b/src/mailman/model/messagestore.py
index 8949c56c6..dc037c44f 100644
--- a/src/mailman/model/messagestore.py
+++ b/src/mailman/model/messagestore.py
@@ -21,13 +21,13 @@ import os
import errno
import pickle
-from mailman import public
from mailman.config import config
from mailman.database.transaction import dbconnection
from mailman.interfaces.messages import IMessageStore
from mailman.model.message import Message
from mailman.utilities.email import add_message_hash
from mailman.utilities.filesystem import makedirs, safe_remove
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/model/mime.py b/src/mailman/model/mime.py
index da5f11f05..a21cfb35d 100644
--- a/src/mailman/model/mime.py
+++ b/src/mailman/model/mime.py
@@ -17,10 +17,10 @@
"""The content filter."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.types import Enum, SAUnicode
from mailman.interfaces.mime import FilterType, IContentFilter
+from public import public
from sqlalchemy import Column, ForeignKey, Integer
from sqlalchemy.orm import relationship
from zope.interface import implementer
diff --git a/src/mailman/model/pending.py b/src/mailman/model/pending.py
index 7e7f0b2eb..5889f9cc1 100644
--- a/src/mailman/model/pending.py
+++ b/src/mailman/model/pending.py
@@ -20,7 +20,6 @@
import json
from lazr.config import as_timedelta
-from mailman import public
from mailman.config import config
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
@@ -29,6 +28,7 @@ from mailman.interfaces.pending import (
IPendable, IPended, IPendedKeyValue, IPendings)
from mailman.utilities.datetime import now
from mailman.utilities.uid import TokenFactory
+from public import public
from sqlalchemy import Column, DateTime, ForeignKey, Integer, and_
from sqlalchemy.orm import aliased, relationship
from zope.interface import implementer
diff --git a/src/mailman/model/preferences.py b/src/mailman/model/preferences.py
index 366ed97c2..4e57ce659 100644
--- a/src/mailman/model/preferences.py
+++ b/src/mailman/model/preferences.py
@@ -17,13 +17,13 @@
"""Model for preferences."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import Enum, SAUnicode
from mailman.interfaces.languages import ILanguageManager
from mailman.interfaces.member import DeliveryMode, DeliveryStatus
from mailman.interfaces.preferences import IPreferences
+from public import public
from sqlalchemy import Boolean, Column, Integer
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/model/requests.py b/src/mailman/model/requests.py
index 0f0f96dfe..04717f49a 100644
--- a/src/mailman/model/requests.py
+++ b/src/mailman/model/requests.py
@@ -18,7 +18,6 @@
"""Implementations of the pending requests interfaces."""
from datetime import timedelta
-from mailman import public
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import Enum, SAUnicode
@@ -26,6 +25,7 @@ from mailman.interfaces.pending import IPendable, IPendings
from mailman.interfaces.requests import IListRequests, RequestType
from mailman.utilities.queries import QuerySequence
from pickle import dumps, loads
+from public import public
from sqlalchemy import Column, ForeignKey, Integer
from sqlalchemy.orm import relationship
from zope.component import getUtility
diff --git a/src/mailman/model/roster.py b/src/mailman/model/roster.py
index 5dc0423b2..d3dc1b661 100644
--- a/src/mailman/model/roster.py
+++ b/src/mailman/model/roster.py
@@ -22,12 +22,12 @@ the ones that fit a particular role. These are used as the member, owner,
moderator, and administrator roster filters.
"""
-from mailman import public
from mailman.database.transaction import dbconnection
from mailman.interfaces.member import DeliveryMode, MemberRole
from mailman.interfaces.roster import IRoster
from mailman.model.address import Address
from mailman.model.member import Member
+from public import public
from sqlalchemy import or_
from zope.interface import implementer
diff --git a/src/mailman/model/subscriptions.py b/src/mailman/model/subscriptions.py
index d3fdc3a8a..485524a68 100644
--- a/src/mailman/model/subscriptions.py
+++ b/src/mailman/model/subscriptions.py
@@ -17,7 +17,6 @@
"""Subscription services."""
-from mailman import public
from mailman.app.membership import delete_member
from mailman.database.transaction import dbconnection
from mailman.interfaces.listmanager import IListManager, NoSuchListError
@@ -30,6 +29,7 @@ from mailman.model.member import Member
from mailman.model.user import User
from mailman.utilities.queries import QuerySequence
from operator import attrgetter
+from public import public
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/model/template.py b/src/mailman/model/template.py
index b09c644bb..eb776293f 100644
--- a/src/mailman/model/template.py
+++ b/src/mailman/model/template.py
@@ -19,7 +19,6 @@
import logging
-from mailman import public
from mailman.config import config
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
@@ -32,6 +31,7 @@ from mailman.interfaces.template import (
from mailman.utilities import protocols
from mailman.utilities.i18n import find
from mailman.utilities.string import expand
+from public import public
from requests import HTTPError
from sqlalchemy import Column, Integer
from urllib.error import URLError
diff --git a/src/mailman/model/uid.py b/src/mailman/model/uid.py
index 2cf61668f..9daefa318 100644
--- a/src/mailman/model/uid.py
+++ b/src/mailman/model/uid.py
@@ -17,10 +17,10 @@
"""Unique IDs."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import UUID
+from public import public
from sqlalchemy import Column, Integer
diff --git a/src/mailman/model/user.py b/src/mailman/model/user.py
index edda2a9e8..dc9c097d5 100644
--- a/src/mailman/model/user.py
+++ b/src/mailman/model/user.py
@@ -17,7 +17,6 @@
"""Model for users."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import SAUnicode, UUID
@@ -31,6 +30,7 @@ from mailman.model.preferences import Preferences
from mailman.model.roster import Memberships
from mailman.utilities.datetime import factory as date_factory
from mailman.utilities.uid import UIDFactory
+from public import public
from sqlalchemy import (
Boolean, Column, DateTime, ForeignKey, Integer)
from sqlalchemy.orm import backref, relationship
diff --git a/src/mailman/model/usermanager.py b/src/mailman/model/usermanager.py
index fba8e2ec0..2a62e0cf1 100644
--- a/src/mailman/model/usermanager.py
+++ b/src/mailman/model/usermanager.py
@@ -17,7 +17,6 @@
"""A user manager."""
-from mailman import public
from mailman.database.transaction import dbconnection
from mailman.interfaces.address import ExistingAddressError
from mailman.interfaces.usermanager import IUserManager
@@ -27,6 +26,7 @@ from mailman.model.digests import OneLastDigest
from mailman.model.member import Member
from mailman.model.preferences import Preferences
from mailman.model.user import User
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/model/workflow.py b/src/mailman/model/workflow.py
index 53763a0e8..8b782b5e0 100644
--- a/src/mailman/model/workflow.py
+++ b/src/mailman/model/workflow.py
@@ -17,11 +17,11 @@
"""Model for workflow states."""
-from mailman import public
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import SAUnicode
from mailman.interfaces.workflow import IWorkflowState, IWorkflowStateManager
+from public import public
from sqlalchemy import Column
from zope.interface import implementer
diff --git a/src/mailman/mta/aliases.py b/src/mailman/mta/aliases.py
index dc434c613..889375c04 100644
--- a/src/mailman/mta/aliases.py
+++ b/src/mailman/mta/aliases.py
@@ -17,8 +17,8 @@
"""Utility for generating all the aliases of a mailing list."""
-from mailman import public
from mailman.interfaces.mta import IMailTransportAgentAliases
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/mta/base.py b/src/mailman/mta/base.py
index 679faefd5..4f5bb1d58 100644
--- a/src/mailman/mta/base.py
+++ b/src/mailman/mta/base.py
@@ -22,10 +22,10 @@ import socket
import logging
import smtplib
-from mailman import public
from mailman.config import config
from mailman.interfaces.mta import IMailTransportAgentDelivery
from mailman.mta.connection import Connection
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/mta/bulk.py b/src/mailman/mta/bulk.py
index 1741e0d4c..91b04957a 100644
--- a/src/mailman/mta/bulk.py
+++ b/src/mailman/mta/bulk.py
@@ -17,8 +17,8 @@
"""Bulk message delivery."""
-from mailman import public
from mailman.mta.base import BaseDelivery
+from public import public
# A mapping of top-level domains to bucket numbers. The zeroth bucket is
diff --git a/src/mailman/mta/connection.py b/src/mailman/mta/connection.py
index 44cc31d86..318bc5e8e 100644
--- a/src/mailman/mta/connection.py
+++ b/src/mailman/mta/connection.py
@@ -22,8 +22,8 @@ import smtplib
from contextlib import suppress
from lazr.config import as_boolean
-from mailman import public
from mailman.config import config
+from public import public
log = logging.getLogger('mailman.smtp')
diff --git a/src/mailman/mta/decorating.py b/src/mailman/mta/decorating.py
index e9d6f5785..32db852da 100644
--- a/src/mailman/mta/decorating.py
+++ b/src/mailman/mta/decorating.py
@@ -17,9 +17,9 @@
"""Individualized delivery with header/footer decorations."""
-from mailman import public
from mailman.config import config
from mailman.mta.verp import VERPDelivery
+from public import public
@public
diff --git a/src/mailman/mta/deliver.py b/src/mailman/mta/deliver.py
index a5a4e2433..7624979bf 100644
--- a/src/mailman/mta/deliver.py
+++ b/src/mailman/mta/deliver.py
@@ -20,7 +20,6 @@
import time
import logging
-from mailman import public
from mailman.config import config
from mailman.interfaces.mailinglist import Personalization
from mailman.interfaces.mta import SomeRecipientsFailed
@@ -30,6 +29,7 @@ from mailman.mta.decorating import DecoratingMixin
from mailman.mta.personalized import PersonalizedMixin
from mailman.mta.verp import VERPMixin
from mailman.utilities.string import expand
+from public import public
COMMA = ','
diff --git a/src/mailman/mta/exim4.py b/src/mailman/mta/exim4.py
index 7151768a8..ec2e77708 100644
--- a/src/mailman/mta/exim4.py
+++ b/src/mailman/mta/exim4.py
@@ -17,8 +17,8 @@
"""Creation/deletion hooks for the Exim4 MTA."""
-from mailman import public
from mailman.interfaces.mta import IMailTransportAgentLifecycle
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/mta/null.py b/src/mailman/mta/null.py
index 165c5f0ee..e5368e689 100644
--- a/src/mailman/mta/null.py
+++ b/src/mailman/mta/null.py
@@ -20,8 +20,8 @@
Exim one example of an MTA that Just Works.
"""
-from mailman import public
from mailman.interfaces.mta import IMailTransportAgentLifecycle
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/mta/personalized.py b/src/mailman/mta/personalized.py
index 7cfbfff43..01ba686f3 100644
--- a/src/mailman/mta/personalized.py
+++ b/src/mailman/mta/personalized.py
@@ -19,10 +19,10 @@
from email.header import Header
from email.utils import formataddr
-from mailman import public
from mailman.interfaces.mailinglist import Personalization
from mailman.interfaces.usermanager import IUserManager
from mailman.mta.verp import VERPDelivery
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/mta/postfix.py b/src/mailman/mta/postfix.py
index ff4b92117..07bf17a22 100644
--- a/src/mailman/mta/postfix.py
+++ b/src/mailman/mta/postfix.py
@@ -21,7 +21,6 @@ import os
import logging
from flufl.lock import Lock
-from mailman import public
from mailman.config import config
from mailman.config.config import external_configuration
from mailman.interfaces.listmanager import IListManager
@@ -29,6 +28,7 @@ from mailman.interfaces.mta import (
IMailTransportAgentAliases, IMailTransportAgentLifecycle)
from mailman.utilities.datetime import now
from operator import attrgetter
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/mta/verp.py b/src/mailman/mta/verp.py
index 8ede6cb67..6ce80c795 100644
--- a/src/mailman/mta/verp.py
+++ b/src/mailman/mta/verp.py
@@ -19,11 +19,11 @@
import logging
-from mailman import public
from mailman.config import config
from mailman.mta.base import IndividualDelivery
from mailman.utilities.email import split_email
from mailman.utilities.string import expand
+from public import public
DOT = '.'
diff --git a/src/mailman/rest/addresses.py b/src/mailman/rest/addresses.py
index f0cb8edef..8e8b543b9 100644
--- a/src/mailman/rest/addresses.py
+++ b/src/mailman/rest/addresses.py
@@ -17,7 +17,6 @@
"""REST for addresses."""
-from mailman import public
from mailman.interfaces.address import (
ExistingAddressError, InvalidEmailAddressError)
from mailman.interfaces.usermanager import IUserManager
@@ -29,6 +28,7 @@ from mailman.rest.preferences import Preferences
from mailman.rest.validator import Validator
from mailman.utilities.datetime import now
from operator import attrgetter
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/bans.py b/src/mailman/rest/bans.py
index ce575885b..981c1b549 100644
--- a/src/mailman/rest/bans.py
+++ b/src/mailman/rest/bans.py
@@ -17,12 +17,12 @@
"""REST for banned emails."""
-from mailman import public
from mailman.interfaces.bans import IBanManager
from mailman.rest.helpers import (
CollectionMixin, bad_request, child, created, etag, no_content, not_found,
okay)
from mailman.rest.validator import Validator
+from public import public
class _BannedBase:
diff --git a/src/mailman/rest/docs/__init__.py b/src/mailman/rest/docs/__init__.py
index 5a039ac3d..dc27a6525 100644
--- a/src/mailman/rest/docs/__init__.py
+++ b/src/mailman/rest/docs/__init__.py
@@ -20,9 +20,9 @@
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
-from mailman import public
from mailman.testing.helpers import wait_for_webservice
from mailman.testing.layers import RESTLayer
+from public import public
# New in Python 3.5.
diff --git a/src/mailman/rest/domains.py b/src/mailman/rest/domains.py
index c6b8daa7c..ce96204b4 100644
--- a/src/mailman/rest/domains.py
+++ b/src/mailman/rest/domains.py
@@ -17,7 +17,6 @@
"""REST for domains."""
-from mailman import public
from mailman.interfaces.domain import (
BadDomainSpecificationError, IDomainManager)
from mailman.rest.helpers import (
@@ -27,6 +26,7 @@ from mailman.rest.lists import ListsForDomain
from mailman.rest.uris import ADomainURI, AllDomainURIs
from mailman.rest.users import ListOfDomainOwners, OwnersForDomain
from mailman.rest.validator import Validator, list_of_strings_validator
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/header_matches.py b/src/mailman/rest/header_matches.py
index 25c519ef3..13dad97ad 100644
--- a/src/mailman/rest/header_matches.py
+++ b/src/mailman/rest/header_matches.py
@@ -17,13 +17,13 @@
"""REST API for a mailing list's header matches."""
-from mailman import public
from mailman.interfaces.action import Action
from mailman.interfaces.mailinglist import IHeaderMatchList
from mailman.rest.helpers import (
CollectionMixin, bad_request, child, created, etag, no_content, not_found,
okay)
from mailman.rest.validator import Validator, enum_validator
+from public import public
def lowercase(value):
diff --git a/src/mailman/rest/helpers.py b/src/mailman/rest/helpers.py
index a4b072408..6b45eb78a 100644
--- a/src/mailman/rest/helpers.py
+++ b/src/mailman/rest/helpers.py
@@ -27,9 +27,9 @@ from email.header import Header
from email.message import Message
from enum import Enum
from lazr.config import as_boolean
-from mailman import public
from mailman.config import config
from pprint import pformat
+from public import public
class ExtendedEncoder(json.JSONEncoder):
diff --git a/src/mailman/rest/listconf.py b/src/mailman/rest/listconf.py
index 861e54dd1..94598b0ab 100644
--- a/src/mailman/rest/listconf.py
+++ b/src/mailman/rest/listconf.py
@@ -18,7 +18,6 @@
"""Mailing list configuration via REST API."""
from lazr.config import as_boolean, as_timedelta
-from mailman import public
from mailman.config import config
from mailman.interfaces.action import Action
from mailman.interfaces.archiver import ArchivePolicy
@@ -32,6 +31,7 @@ from mailman.rest.helpers import (
from mailman.rest.validator import (
PatchValidator, ReadOnlyPATCHRequestError, UnknownPATCHRequestError,
Validator, enum_validator, list_of_strings_validator)
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/lists.py b/src/mailman/rest/lists.py
index 1fdf595fb..cdebdebd9 100644
--- a/src/mailman/rest/lists.py
+++ b/src/mailman/rest/lists.py
@@ -18,7 +18,6 @@
"""REST for mailing lists."""
from lazr.config import as_boolean
-from mailman import public
from mailman.app.digests import (
bump_digest_number_and_volume, maybe_send_digest_now)
from mailman.app.lifecycle import create_list, remove_list
@@ -41,6 +40,7 @@ from mailman.rest.post_moderation import HeldMessages
from mailman.rest.sub_moderation import SubscriptionRequests
from mailman.rest.uris import AListURI, AllListURIs
from mailman.rest.validator import Validator, list_of_strings_validator
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/members.py b/src/mailman/rest/members.py
index b35440af4..ea7eaa394 100644
--- a/src/mailman/rest/members.py
+++ b/src/mailman/rest/members.py
@@ -17,7 +17,6 @@
"""REST for members."""
-from mailman import public
from mailman.app.membership import add_member, delete_member
from mailman.interfaces.action import Action
from mailman.interfaces.address import IAddress
@@ -36,6 +35,7 @@ from mailman.rest.helpers import (
from mailman.rest.preferences import Preferences, ReadOnlyPreferences
from mailman.rest.validator import (
Validator, enum_validator, subscriber_validator)
+from public import public
from uuid import UUID
from zope.component import getUtility
diff --git a/src/mailman/rest/post_moderation.py b/src/mailman/rest/post_moderation.py
index 33a32de20..9a56ada00 100644
--- a/src/mailman/rest/post_moderation.py
+++ b/src/mailman/rest/post_moderation.py
@@ -17,7 +17,6 @@
"""REST API for held message moderation."""
-from mailman import public
from mailman.app.moderator import handle_message
from mailman.interfaces.action import Action
from mailman.interfaces.messages import IMessageStore
@@ -25,6 +24,7 @@ from mailman.interfaces.requests import IListRequests, RequestType
from mailman.rest.helpers import (
CollectionMixin, bad_request, child, etag, no_content, not_found, okay)
from mailman.rest.validator import Validator, enum_validator
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/preferences.py b/src/mailman/rest/preferences.py
index cf26380fe..549751d1e 100644
--- a/src/mailman/rest/preferences.py
+++ b/src/mailman/rest/preferences.py
@@ -18,12 +18,12 @@
"""Preferences."""
from lazr.config import as_boolean
-from mailman import public
from mailman.interfaces.member import DeliveryMode, DeliveryStatus
from mailman.rest.helpers import (
GetterSetter, bad_request, etag, no_content, not_found, okay)
from mailman.rest.validator import (
Validator, enum_validator, language_validator)
+from public import public
PREFERENCES = (
diff --git a/src/mailman/rest/queues.py b/src/mailman/rest/queues.py
index 9fa5b9dc6..27e9c698e 100644
--- a/src/mailman/rest/queues.py
+++ b/src/mailman/rest/queues.py
@@ -17,13 +17,13 @@
"""/queues."""
-from mailman import public
from mailman.app.inject import inject_text
from mailman.config import config
from mailman.interfaces.listmanager import IListManager
from mailman.rest.helpers import (
CollectionMixin, bad_request, created, etag, no_content, not_found, okay)
from mailman.rest.validator import Validator
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/root.py b/src/mailman/rest/root.py
index 7f6be0353..c4c0b865f 100644
--- a/src/mailman/rest/root.py
+++ b/src/mailman/rest/root.py
@@ -17,7 +17,6 @@
"""The root of the REST API."""
-from mailman import public
from mailman.config import config
from mailman.core.api import API30, API31
from mailman.core.constants import system_preferences
@@ -36,6 +35,7 @@ from mailman.rest.queues import AQueue, AQueueFile, AllQueues
from mailman.rest.templates import TemplateFinder
from mailman.rest.uris import ASiteURI, AllSiteURIs
from mailman.rest.users import AUser, AllUsers, ServerOwners
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/sub_moderation.py b/src/mailman/rest/sub_moderation.py
index 55b6a7609..39976826c 100644
--- a/src/mailman/rest/sub_moderation.py
+++ b/src/mailman/rest/sub_moderation.py
@@ -17,7 +17,6 @@
"""REST API for held subscription requests."""
-from mailman import public
from mailman.app.moderator import send_rejection
from mailman.core.i18n import _
from mailman.interfaces.action import Action
@@ -28,6 +27,7 @@ from mailman.rest.helpers import (
CollectionMixin, bad_request, child, conflict, etag, no_content,
not_found, okay)
from mailman.rest.validator import Validator, enum_validator
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/templates.py b/src/mailman/rest/templates.py
index fe5e34a8e..7f4e5a3af 100644
--- a/src/mailman/rest/templates.py
+++ b/src/mailman/rest/templates.py
@@ -17,9 +17,9 @@
"""Template finder."""
-from mailman import public
from mailman.rest.helpers import not_found
from mailman.utilities.i18n import TemplateNotFoundError, find
+from public import public
# Use mimetypes.guess_all_extensions()?
diff --git a/src/mailman/rest/uris.py b/src/mailman/rest/uris.py
index 2fc062262..d94b3b237 100644
--- a/src/mailman/rest/uris.py
+++ b/src/mailman/rest/uris.py
@@ -17,12 +17,12 @@
"""URI templates."""
-from mailman import public
from mailman.interfaces.template import ALL_TEMPLATES, ITemplateManager
from mailman.rest.helpers import (
CollectionMixin, bad_request, etag, no_content, not_found, okay)
from mailman.rest.validator import Validator
from operator import attrgetter
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/users.py b/src/mailman/rest/users.py
index f9ce9b132..c50bfe3d0 100644
--- a/src/mailman/rest/users.py
+++ b/src/mailman/rest/users.py
@@ -19,7 +19,6 @@
from functools import lru_cache
from lazr.config import as_boolean
-from mailman import public
from mailman.config import config
from mailman.interfaces.address import ExistingAddressError
from mailman.interfaces.usermanager import IUserManager
@@ -32,6 +31,7 @@ from mailman.rest.validator import (
PatchValidator, ReadOnlyPATCHRequestError, UnknownPATCHRequestError,
Validator, list_of_strings_validator)
from passlib.utils import generate_password as generate
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/validator.py b/src/mailman/rest/validator.py
index 19e8d684a..439c25b8e 100644
--- a/src/mailman/rest/validator.py
+++ b/src/mailman/rest/validator.py
@@ -17,10 +17,10 @@
"""REST web form validation."""
-from mailman import public
from mailman.interfaces.address import IEmailValidator
from mailman.interfaces.errors import MailmanError
from mailman.interfaces.languages import ILanguageManager
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/rest/wsgiapp.py b/src/mailman/rest/wsgiapp.py
index 3ba122c00..b2dbc7409 100644
--- a/src/mailman/rest/wsgiapp.py
+++ b/src/mailman/rest/wsgiapp.py
@@ -23,10 +23,10 @@ import logging
from base64 import b64decode
from falcon import API, HTTPUnauthorized
from falcon.routing import create_http_method_map
-from mailman import public
from mailman.config import config
from mailman.database.transaction import transactional
from mailman.rest.root import Root
+from public import public
from wsgiref.simple_server import (
WSGIRequestHandler, WSGIServer, make_server as wsgi_server)
diff --git a/src/mailman/rules/administrivia.py b/src/mailman/rules/administrivia.py
index e5defee6e..6dc6c38b4 100644
--- a/src/mailman/rules/administrivia.py
+++ b/src/mailman/rules/administrivia.py
@@ -18,10 +18,10 @@
"""The administrivia rule."""
from email.iterators import typed_subpart_iterator
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
# The list of email commands we search for in the Subject header and payload.
diff --git a/src/mailman/rules/any.py b/src/mailman/rules/any.py
index 466735ebe..6d3bbe21f 100644
--- a/src/mailman/rules/any.py
+++ b/src/mailman/rules/any.py
@@ -17,9 +17,9 @@
"""Check if any previous rules have matched."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/approved.py b/src/mailman/rules/approved.py
index a4ea1145e..66f21c8eb 100644
--- a/src/mailman/rules/approved.py
+++ b/src/mailman/rules/approved.py
@@ -20,10 +20,10 @@
import re
from email.iterators import typed_subpart_iterator
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/banned_address.py b/src/mailman/rules/banned_address.py
index 8ed33a5e6..850f101db 100644
--- a/src/mailman/rules/banned_address.py
+++ b/src/mailman/rules/banned_address.py
@@ -17,10 +17,10 @@
"""Banned addresses rule."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.bans import IBanManager
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/emergency.py b/src/mailman/rules/emergency.py
index 442ccf136..59c0c6a84 100644
--- a/src/mailman/rules/emergency.py
+++ b/src/mailman/rules/emergency.py
@@ -17,9 +17,9 @@
"""The emergency hold rule."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/implicit_dest.py b/src/mailman/rules/implicit_dest.py
index c0e116d1c..88429a6ac 100644
--- a/src/mailman/rules/implicit_dest.py
+++ b/src/mailman/rules/implicit_dest.py
@@ -21,10 +21,10 @@ import re
from contextlib import suppress
from email.utils import getaddresses
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.mailinglist import IAcceptableAliasSet
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/loop.py b/src/mailman/rules/loop.py
index 0f8047e76..d9b7c299d 100644
--- a/src/mailman/rules/loop.py
+++ b/src/mailman/rules/loop.py
@@ -17,9 +17,9 @@
"""Look for a posting loop."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/max_recipients.py b/src/mailman/rules/max_recipients.py
index 61df613cb..1d38e28c1 100644
--- a/src/mailman/rules/max_recipients.py
+++ b/src/mailman/rules/max_recipients.py
@@ -18,9 +18,9 @@
"""The maximum number of recipients rule."""
from email.utils import getaddresses
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/max_size.py b/src/mailman/rules/max_size.py
index 8911e97fd..c5c492347 100644
--- a/src/mailman/rules/max_size.py
+++ b/src/mailman/rules/max_size.py
@@ -17,9 +17,9 @@
"""The maximum message size rule."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/moderation.py b/src/mailman/rules/moderation.py
index 20b238eab..b52ecff3e 100644
--- a/src/mailman/rules/moderation.py
+++ b/src/mailman/rules/moderation.py
@@ -19,13 +19,13 @@
import re
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.action import Action
from mailman.interfaces.bans import IBanManager
from mailman.interfaces.member import MemberRole
from mailman.interfaces.rules import IRule
from mailman.interfaces.usermanager import IUserManager
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/rules/news_moderation.py b/src/mailman/rules/news_moderation.py
index 63a7e93b0..8d0fe3402 100644
--- a/src/mailman/rules/news_moderation.py
+++ b/src/mailman/rules/news_moderation.py
@@ -17,10 +17,10 @@
"""The news moderation rule."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.nntp import NewsgroupModeration
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/no_subject.py b/src/mailman/rules/no_subject.py
index ed020b81e..f3eba625a 100644
--- a/src/mailman/rules/no_subject.py
+++ b/src/mailman/rules/no_subject.py
@@ -17,9 +17,9 @@
"""The no-Subject header rule."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/suspicious.py b/src/mailman/rules/suspicious.py
index 679605fd6..049df0a61 100644
--- a/src/mailman/rules/suspicious.py
+++ b/src/mailman/rules/suspicious.py
@@ -20,9 +20,9 @@
import re
import logging
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/rules/truth.py b/src/mailman/rules/truth.py
index 9883a0e60..224ceeaad 100644
--- a/src/mailman/rules/truth.py
+++ b/src/mailman/rules/truth.py
@@ -17,9 +17,9 @@
"""A rule which always matches."""
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.rules import IRule
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/runners/archive.py b/src/mailman/runners/archive.py
index 23b7b164d..073f72d52 100644
--- a/src/mailman/runners/archive.py
+++ b/src/mailman/runners/archive.py
@@ -23,12 +23,12 @@ import logging
from datetime import datetime
from email.utils import mktime_tz, parsedate_tz
from lazr.config import as_timedelta
-from mailman import public
from mailman.config import config
from mailman.core.runner import Runner
from mailman.interfaces.archiver import ClobberDate
from mailman.interfaces.mailinglist import IListArchiverSet
from mailman.utilities.datetime import RFC822_DATE_FMT, now
+from public import public
log = logging.getLogger('mailman.archiver')
diff --git a/src/mailman/runners/bounce.py b/src/mailman/runners/bounce.py
index 4150dc9b5..40ea840e7 100644
--- a/src/mailman/runners/bounce.py
+++ b/src/mailman/runners/bounce.py
@@ -20,10 +20,10 @@
import logging
from flufl.bounce import all_failures, scan_message
-from mailman import public
from mailman.app.bounces import ProbeVERP, StandardVERP, maybe_forward
from mailman.core.runner import Runner
from mailman.interfaces.bounce import BounceContext, IBounceProcessor
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/runners/command.py b/src/mailman/runners/command.py
index ba10988e3..a52dd541d 100644
--- a/src/mailman/runners/command.py
+++ b/src/mailman/runners/command.py
@@ -30,13 +30,13 @@ from email.errors import HeaderParseError
from email.header import decode_header, make_header
from email.iterators import typed_subpart_iterator
from io import StringIO
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.core.runner import Runner
from mailman.email.message import UserNotification
from mailman.interfaces.command import ContinueProcessing, IEmailResults
from mailman.interfaces.languages import ILanguageManager
+from public import public
from zope.component import getUtility
from zope.interface import implementer
diff --git a/src/mailman/runners/digest.py b/src/mailman/runners/digest.py
index 4971965fa..284056e3a 100644
--- a/src/mailman/runners/digest.py
+++ b/src/mailman/runners/digest.py
@@ -27,7 +27,6 @@ from email.mime.message import MIMEMessage
from email.mime.text import MIMEText
from email.utils import formatdate, getaddresses, make_msgid
from io import StringIO
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.core.runner import Runner
@@ -37,6 +36,7 @@ from mailman.interfaces.member import DeliveryMode, DeliveryStatus
from mailman.interfaces.template import ITemplateLoader
from mailman.utilities.mailbox import Mailbox
from mailman.utilities.string import expand, oneline, wrap
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/runners/incoming.py b/src/mailman/runners/incoming.py
index 62b12dab1..9461e59bc 100644
--- a/src/mailman/runners/incoming.py
+++ b/src/mailman/runners/incoming.py
@@ -27,12 +27,12 @@ immediately.
"""
from contextlib import suppress
-from mailman import public
from mailman.core.chains import process
from mailman.core.runner import Runner
from mailman.database.transaction import transaction
from mailman.interfaces.address import ExistingAddressError
from mailman.interfaces.usermanager import IUserManager
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/runners/lmtp.py b/src/mailman/runners/lmtp.py
index 21fb44c5e..0fa13a611 100644
--- a/src/mailman/runners/lmtp.py
+++ b/src/mailman/runners/lmtp.py
@@ -43,7 +43,6 @@ import aiosmtpd.smtp
from aiosmtpd.controller import Controller
from aiosmtpd.lmtp import LMTP
from email.utils import parseaddr
-from mailman import public
from mailman.config import config
from mailman.core.runner import Runner
from mailman.database.transaction import transactional
@@ -51,6 +50,7 @@ from mailman.email.message import Message
from mailman.interfaces.listmanager import IListManager
from mailman.utilities.datetime import now
from mailman.utilities.email import add_message_hash
+from public import public
from zope.component import getUtility
diff --git a/src/mailman/runners/nntp.py b/src/mailman/runners/nntp.py
index b125fe4f9..38f67c453 100644
--- a/src/mailman/runners/nntp.py
+++ b/src/mailman/runners/nntp.py
@@ -24,10 +24,10 @@ import logging
import nntplib
from io import StringIO
-from mailman import public
from mailman.config import config
from mailman.core.runner import Runner
from mailman.interfaces.nntp import NewsgroupModeration
+from public import public
COMMA = ','
diff --git a/src/mailman/runners/outgoing.py b/src/mailman/runners/outgoing.py
index 3f21e3813..61b6e0b99 100644
--- a/src/mailman/runners/outgoing.py
+++ b/src/mailman/runners/outgoing.py
@@ -22,7 +22,6 @@ import logging
from datetime import datetime
from lazr.config import as_boolean, as_timedelta
-from mailman import public
from mailman.config import config
from mailman.core.runner import Runner
from mailman.interfaces.bounce import BounceContext, IBounceProcessor
@@ -32,6 +31,7 @@ from mailman.interfaces.pending import IPendings
from mailman.interfaces.subscriptions import ISubscriptionService
from mailman.utilities.datetime import now
from mailman.utilities.modules import find_name
+from public import public
from uuid import UUID
from zope.component import getUtility
diff --git a/src/mailman/runners/pipeline.py b/src/mailman/runners/pipeline.py
index 3ec7499f2..caa68763c 100644
--- a/src/mailman/runners/pipeline.py
+++ b/src/mailman/runners/pipeline.py
@@ -22,9 +22,9 @@ through the 'preparation pipeline'. This pipeline adds, deletes and modifies
headers, calculates message recipients, and more.
"""
-from mailman import public
from mailman.core.pipelines import process
from mailman.core.runner import Runner
+from public import public
@public
diff --git a/src/mailman/runners/rest.py b/src/mailman/runners/rest.py
index 037b6adf8..dd7eae245 100644
--- a/src/mailman/runners/rest.py
+++ b/src/mailman/runners/rest.py
@@ -21,9 +21,9 @@ import signal
import logging
import threading
-from mailman import public
from mailman.core.runner import Runner
from mailman.rest.wsgiapp import make_server
+from public import public
log = logging.getLogger('mailman.http')
diff --git a/src/mailman/runners/retry.py b/src/mailman/runners/retry.py
index f1af4f73c..2be89e8b0 100644
--- a/src/mailman/runners/retry.py
+++ b/src/mailman/runners/retry.py
@@ -19,9 +19,9 @@
import time
-from mailman import public
from mailman.config import config
from mailman.core.runner import Runner
+from public import public
@public
diff --git a/src/mailman/runners/virgin.py b/src/mailman/runners/virgin.py
index a69d07bf7..50ef3dcce 100644
--- a/src/mailman/runners/virgin.py
+++ b/src/mailman/runners/virgin.py
@@ -23,9 +23,9 @@ to go through some minimal processing before they can be sent out to the
recipient.
"""
-from mailman import public
from mailman.core.pipelines import process
from mailman.core.runner import Runner
+from public import public
@public
diff --git a/src/mailman/styles/base.py b/src/mailman/styles/base.py
index 7226d762a..02a17d54d 100644
--- a/src/mailman/styles/base.py
+++ b/src/mailman/styles/base.py
@@ -24,7 +24,6 @@ methods in your compositional derived class.
from datetime import timedelta
-from mailman import public
from mailman.core.i18n import _
from mailman.interfaces.action import Action, FilterAction
from mailman.interfaces.archiver import ArchivePolicy
@@ -34,6 +33,7 @@ from mailman.interfaces.digests import DigestFrequency
from mailman.interfaces.mailinglist import (
Personalization, ReplyToMunging, SubscriptionPolicy)
from mailman.interfaces.nntp import NewsgroupModeration
+from public import public
@public
diff --git a/src/mailman/styles/default.py b/src/mailman/styles/default.py
index 2df075a6f..c7632fe8e 100644
--- a/src/mailman/styles/default.py
+++ b/src/mailman/styles/default.py
@@ -17,11 +17,11 @@
"""Application of list styles to new and existing lists."""
-from mailman import public
from mailman.interfaces.styles import IStyle
from mailman.styles.base import (
Announcement, BasicOperation, Bounces, Discussion, Identity, Moderation,
Public)
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/styles/manager.py b/src/mailman/styles/manager.py
index 1b3130581..ae60dc3c6 100644
--- a/src/mailman/styles/manager.py
+++ b/src/mailman/styles/manager.py
@@ -17,11 +17,11 @@
"""Style manager."""
-from mailman import public
from mailman.interfaces.configuration import ConfigurationUpdatedEvent
from mailman.interfaces.styles import (
DuplicateStyleError, IStyle, IStyleManager)
from mailman.utilities.modules import find_components
+from public import public
from zope.component import getUtility
from zope.interface import implementer
from zope.interface.verify import verifyObject
diff --git a/src/mailman/testing/documentation.py b/src/mailman/testing/documentation.py
index 29629fe1b..97e30e900 100644
--- a/src/mailman/testing/documentation.py
+++ b/src/mailman/testing/documentation.py
@@ -22,12 +22,12 @@ distributions. doctest discovery currently requires file system traversal.
"""
from inspect import isfunction, ismethod
-from mailman import public
from mailman.app.lifecycle import create_list
from mailman.config import config
from mailman.testing.helpers import (
call_api, get_queue_messages, specialized_message_from_string, subscribe)
from mailman.testing.layers import SMTPLayer
+from public import public
DOT = '.'
diff --git a/src/mailman/testing/helpers.py b/src/mailman/testing/helpers.py
index 2ce6956b7..01b362192 100644
--- a/src/mailman/testing/helpers.py
+++ b/src/mailman/testing/helpers.py
@@ -35,7 +35,6 @@ from contextlib import contextmanager, suppress
from email import message_from_string
from httplib2 import Http
from lazr.config import as_timedelta
-from mailman import public
from mailman.bin.master import Loop as Master
from mailman.config import config
from mailman.database.transaction import transaction
@@ -46,6 +45,7 @@ from mailman.interfaces.styles import IStyleManager
from mailman.interfaces.usermanager import IUserManager
from mailman.runners.digest import DigestRunner
from mailman.utilities.mailbox import Mailbox
+from public import public
from unittest import mock
from urllib.error import HTTPError
from urllib.parse import urlencode
diff --git a/src/mailman/testing/i18n.py b/src/mailman/testing/i18n.py
index 2031be307..ade8584b1 100644
--- a/src/mailman/testing/i18n.py
+++ b/src/mailman/testing/i18n.py
@@ -20,8 +20,8 @@
from contextlib import closing
from flufl.i18n import registry
from gettext import GNUTranslations, NullTranslations
-from mailman import public
from pkg_resources import resource_stream
+from public import public
class TestingStrategy:
diff --git a/src/mailman/testing/layers.py b/src/mailman/testing/layers.py
index 3157809e6..67fb4f5e1 100644
--- a/src/mailman/testing/layers.py
+++ b/src/mailman/testing/layers.py
@@ -32,7 +32,6 @@ import datetime
import tempfile
from lazr.config import as_boolean
-from mailman import public
from mailman.config import config
from mailman.core import initialize
from mailman.core.initialize import INHIBIT_CONFIG_FILE
@@ -44,6 +43,7 @@ from mailman.testing.helpers import (
from mailman.testing.mta import ConnectionCountingController
from mailman.utilities.string import expand
from pkg_resources import resource_string as resource_bytes
+from public import public
from textwrap import dedent
from zope.component import getUtility
diff --git a/src/mailman/testing/mta.py b/src/mailman/testing/mta.py
index 81e4b8a62..d94466428 100644
--- a/src/mailman/testing/mta.py
+++ b/src/mailman/testing/mta.py
@@ -24,8 +24,8 @@ import smtplib
from aiosmtpd.controller import Controller
from aiosmtpd.handlers import Message as MessageHandler
from aiosmtpd.smtp import SMTP
-from mailman import public
from mailman.interfaces.mta import IMailTransportAgentLifecycle
+from public import public
from queue import Empty, Queue
from zope.interface import implementer
diff --git a/src/mailman/testing/nose.py b/src/mailman/testing/nose.py
index bbd361390..1a9830da5 100644
--- a/src/mailman/testing/nose.py
+++ b/src/mailman/testing/nose.py
@@ -22,11 +22,11 @@ import re
import doctest
import importlib
-from mailman import public
from mailman.testing.documentation import setup, teardown
from mailman.testing.layers import ConfigLayer, MockAndMonkeyLayer, SMTPLayer
from nose2.events import Plugin
from pkg_resources import resource_filename
+from public import public
DOT = '.'
diff --git a/src/mailman/utilities/datetime.py b/src/mailman/utilities/datetime.py
index 9bb772b3f..2915080e8 100644
--- a/src/mailman/utilities/datetime.py
+++ b/src/mailman/utilities/datetime.py
@@ -24,8 +24,8 @@ instrumented for testing purposes.
import datetime
-from mailman import public
from mailman.testing import layers
+from public import public
# Python always sets the locale to 'C' locale unless the user explicitly calls
diff --git a/src/mailman/utilities/email.py b/src/mailman/utilities/email.py
index e870117ac..546a7de61 100644
--- a/src/mailman/utilities/email.py
+++ b/src/mailman/utilities/email.py
@@ -19,7 +19,7 @@
from base64 import b32encode
from hashlib import sha1
-from mailman import public
+from public import public
@public
diff --git a/src/mailman/utilities/filesystem.py b/src/mailman/utilities/filesystem.py
index e89f2abb8..7dcf2bb80 100644
--- a/src/mailman/utilities/filesystem.py
+++ b/src/mailman/utilities/filesystem.py
@@ -20,7 +20,7 @@
import os
from contextlib import suppress
-from mailman import public
+from public import public
@public
diff --git a/src/mailman/utilities/i18n.py b/src/mailman/utilities/i18n.py
index 1df8ede7e..a658c231b 100644
--- a/src/mailman/utilities/i18n.py
+++ b/src/mailman/utilities/i18n.py
@@ -21,11 +21,11 @@ import os
import sys
from itertools import product
-from mailman import public
from mailman.config import config
from mailman.core.constants import system_preferences
from mailman.interfaces.errors import MailmanError
from pkg_resources import resource_filename
+from public import public
@public
diff --git a/src/mailman/utilities/importer.py b/src/mailman/utilities/importer.py
index cf14fa73a..c8348a681 100644
--- a/src/mailman/utilities/importer.py
+++ b/src/mailman/utilities/importer.py
@@ -23,7 +23,6 @@ import sys
import logging
import datetime
-from mailman import public
from mailman.config import config
from mailman.handlers.decorate import decorate_template
from mailman.interfaces.action import Action, FilterAction
@@ -44,6 +43,7 @@ from mailman.interfaces.template import ITemplateManager
from mailman.interfaces.usermanager import IUserManager
from mailman.utilities.filesystem import makedirs
from mailman.utilities.i18n import search
+from public import public
from sqlalchemy import Boolean
from zope.component import getUtility
diff --git a/src/mailman/utilities/interact.py b/src/mailman/utilities/interact.py
index ac1612156..48f3ae358 100644
--- a/src/mailman/utilities/interact.py
+++ b/src/mailman/utilities/interact.py
@@ -23,7 +23,7 @@ import code
from contextlib import suppress
from inspect import signature
-from mailman import public
+from public import public
DEFAULT_BANNER = object()
diff --git a/src/mailman/utilities/mailbox.py b/src/mailman/utilities/mailbox.py
index b799babea..19146e036 100644
--- a/src/mailman/utilities/mailbox.py
+++ b/src/mailman/utilities/mailbox.py
@@ -23,8 +23,9 @@
# get its size. MMDF is slightly more sane than mbox; it's primary advantage
# for us is that it does no 'From' mangling.
# mangling.
+
from mailbox import MMDF
-from mailman import public
+from public import public
@public
diff --git a/src/mailman/utilities/modules.py b/src/mailman/utilities/modules.py
index b16aa45e5..83063a3f0 100644
--- a/src/mailman/utilities/modules.py
+++ b/src/mailman/utilities/modules.py
@@ -20,8 +20,8 @@
import os
import sys
-from mailman import public
from pkg_resources import resource_filename, resource_listdir
+from public import public
@public
diff --git a/src/mailman/utilities/options.py b/src/mailman/utilities/options.py
index 1c0064260..9e1e698a7 100644
--- a/src/mailman/utilities/options.py
+++ b/src/mailman/utilities/options.py
@@ -21,12 +21,12 @@ import os
import sys
from copy import copy
-from mailman import public
from mailman.config import config
from mailman.core.i18n import _
from mailman.core.initialize import initialize
from mailman.version import MAILMAN_VERSION
from optparse import Option, OptionParser, OptionValueError
+from public import public
def check_unicode(option, opt, value):
diff --git a/src/mailman/utilities/passwords.py b/src/mailman/utilities/passwords.py
index 5597e2556..7bf18b93a 100644
--- a/src/mailman/utilities/passwords.py
+++ b/src/mailman/utilities/passwords.py
@@ -17,10 +17,10 @@
"""A wrapper around passlib."""
-from mailman import public
from mailman.config.config import load_external
from mailman.interfaces.configuration import ConfigurationUpdatedEvent
from passlib.context import CryptContext
+from public import public
class PasswordContext:
diff --git a/src/mailman/utilities/protocols.py b/src/mailman/utilities/protocols.py
index 5f447c465..43d43a8bc 100644
--- a/src/mailman/utilities/protocols.py
+++ b/src/mailman/utilities/protocols.py
@@ -19,10 +19,10 @@
import requests
-from mailman import public
from mailman.interfaces.languages import ILanguageManager
from mailman.interfaces.listmanager import IListManager
from mailman.utilities.i18n import TemplateNotFoundError, find
+from public import public
from urllib.error import URLError
from urllib.parse import urlparse
from zope.component import getUtility
diff --git a/src/mailman/utilities/queries.py b/src/mailman/utilities/queries.py
index e27ae9a17..cd6542270 100644
--- a/src/mailman/utilities/queries.py
+++ b/src/mailman/utilities/queries.py
@@ -18,7 +18,7 @@
"""Some helpers for queries."""
from collections.abc import Sequence
-from mailman import public
+from public import public
@public
diff --git a/src/mailman/utilities/string.py b/src/mailman/utilities/string.py
index 2694877ee..fecadc444 100644
--- a/src/mailman/utilities/string.py
+++ b/src/mailman/utilities/string.py
@@ -21,8 +21,8 @@ import logging
from email.errors import HeaderParseError
from email.header import decode_header, make_header
-from mailman import public
from mailman.config import config
+from public import public
from string import Template, whitespace
from textwrap import TextWrapper, dedent
diff --git a/src/mailman/utilities/tests/test_modules.py b/src/mailman/utilities/tests/test_modules.py
index 8e144e60b..d34a99910 100644
--- a/src/mailman/utilities/tests/test_modules.py
+++ b/src/mailman/utilities/tests/test_modules.py
@@ -67,7 +67,7 @@ class TestModuleImports(unittest.TestCase):
Path(init_file).touch()
with open(good_file, 'w', encoding='utf-8') as fp:
print("""\
-from mailman import public
+from public import public
from mailman.interfaces.styles import IStyle
from zope.interface import implementer
@@ -80,7 +80,7 @@ class GoodStyle:
""", file=fp)
with open(bad_file, 'w', encoding='utf-8') as fp:
print("""\
-from mailman import public
+from public import public
from mailman.interfaces.styles import IStyle
from zope.interface import implementer
diff --git a/src/mailman/utilities/uid.py b/src/mailman/utilities/uid.py
index 4389bcd92..9abf92e90 100644
--- a/src/mailman/utilities/uid.py
+++ b/src/mailman/utilities/uid.py
@@ -29,10 +29,10 @@ import hashlib
from contextlib import suppress
from flufl.lock import Lock
-from mailman import public
from mailman.config import config
from mailman.model.uid import UID
from mailman.testing import layers
+from public import public
class _PredictableIDGenerator:
--
cgit v1.3.1
From c44c48e1447b54f2f8673a930b343767f0b917fb Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 29 Nov 2016 19:19:13 -0500
Subject: Use flufl.testing's flake8 plugin.
---
setup.py | 1 -
src/mailman/testing/flake8.py | 141 ------------------------------------------
tox.ini | 2 +
3 files changed, 2 insertions(+), 142 deletions(-)
delete mode 100644 src/mailman/testing/flake8.py
diff --git a/setup.py b/setup.py
index 080c83925..378bc989a 100644
--- a/setup.py
+++ b/setup.py
@@ -101,7 +101,6 @@ case second `m'. Any other spelling is incorrect.""",
include_package_data = True,
entry_points = {
'console_scripts' : list(scripts),
- 'flake8.extension': ['B4 = mailman.testing.flake8:ImportOrder'],
},
install_requires = [
'aiosmtpd',
diff --git a/src/mailman/testing/flake8.py b/src/mailman/testing/flake8.py
deleted file mode 100644
index 68bd37761..000000000
--- a/src/mailman/testing/flake8.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# Copyright (C) 2016 by the Free Software Foundation, Inc.
-#
-# This file is part of GNU Mailman.
-#
-# GNU Mailman is free software: you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free
-# Software Foundation, either version 3 of the License, or (at your option)
-# any later version.
-#
-# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-# more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# GNU Mailman. If not, see .
-
-"""Flake8 extensions for Mailman coding style."""
-
-
-from ast import NodeVisitor
-from collections import namedtuple
-from enum import Enum
-
-
-class ImportType(Enum):
- non_from = 0
- from_import = 1
-
-
-ImportRecord = namedtuple('ImportRecord', 'itype lineno colno, module, names')
-
-
-NONFROM_FOLLOWS_FROM = 'B401 Non-from import follows from-import'
-NONFROM_MULTIPLE_NAMES = 'B402 Multiple names on non-from import'
-NONFROM_SHORTER_FOLLOWS = 'B403 Shorter non-from import follows longer'
-NONFROM_ALPHA_UNSORTED = (
- 'B404 Same-length non-from imports not sorted alphabetically')
-NONFROM_EXTRA_BLANK_LINE = (
- 'B405 Unexpected blank line since last non-from import')
-NONFROM_DOTTED_UNSORTED = (
- 'B406 Dotted non-from import not sorted alphabetically')
-
-FROMIMPORT_MISSING_BLANK_LINE = (
- 'B411 Expected one blank line since last non-from import')
-FROMIMPORT_ALPHA_UNSORTED = 'B412 from-import not sorted alphabetically'
-FROMIMPORT_MULTIPLE = 'B413 Multiple from-imports of same module'
-FROMIMPORT_NAMES_UNSORTED = (
- 'B414 from-imported names are not sorted alphabetically')
-
-
-class ImportVisitor(NodeVisitor):
- def __init__(self):
- self.imports = []
-
- def visit_Import(self, node):
- if node.col_offset != 0:
- # Ignore nested imports.
- return
- names = [alias.name for alias in node.names]
- self.imports.append(
- ImportRecord(ImportType.non_from, node.lineno, node.col_offset,
- None, names))
-
- def visit_ImportFrom(self, node):
- if node.col_offset != 0:
- # Ignore nested imports.
- return
- names = [alias.name for alias in node.names]
- self.imports.append(
- ImportRecord(ImportType.from_import, node.lineno, node.col_offset,
- node.module, names))
-
-
-class ImportOrder:
- name = 'flufl-import-order'
- version = '0.1'
-
- def __init__(self, tree, filename):
- self.tree = tree
- self.filename = filename
-
- def _error(self, record, error):
- code, space, text = error.partition(' ')
- return (record.lineno, record.colno,
- '{} {}'.format(code, text), ImportOrder)
-
- def run(self):
- visitor = ImportVisitor()
- visitor.visit(self.tree)
- last_import = None
- for record in visitor.imports:
- if last_import is None:
- last_import = record
- continue
- if record.itype is ImportType.non_from:
- if len(record.names) != 1:
- yield self._error(record, NONFROM_MULTIPLE_NAMES)
- if last_import.itype is ImportType.from_import:
- yield self._error(record, NONFROM_FOLLOWS_FROM)
- # Shorter imports should always precede longer import *except*
- # when they are dotted imports and everything but the last
- # path component are the same. In that case, they should be
- # sorted alphabetically.
- last_name = last_import.names[0]
- this_name = record.names[0]
- if '.' in last_name and '.' in this_name:
- last_parts = last_name.split('.')
- this_parts = this_name.split('.')
- if (last_parts[:-1] == this_parts[:-1] and
- last_parts[-1] > this_parts[-1]):
- yield self._error(record, NONFROM_DOTTED_UNSORTED)
- elif len(last_name) > len(this_name):
- yield self._error(record, NONFROM_SHORTER_FOLLOWS)
- # It's also possible that the imports are the same length, in
- # which case they must be sorted alphabetically.
- if (len(last_import.names[0]) == len(record.names[0]) and
- last_import.names[0] > record.names[0]):
- yield self._error(record, NONFROM_ALPHA_UNSORTED)
- if last_import.lineno + 1 != record.lineno:
- yield self._error(record, NONFROM_DOTTED_UNSORTED)
- else:
- assert record.itype is ImportType.from_import
- if (last_import.itype is ImportType.non_from and
- record.lineno != last_import.lineno + 2):
- yield self._error(record, FROMIMPORT_MISSING_BLANK_LINE)
- if last_import.itype is ImportType.non_from:
- last_import = record
- continue
- if last_import.module > record.module:
- yield self._error(record, FROMIMPORT_ALPHA_UNSORTED)
- # All imports from the same module should show up in the same
- # multiline import.
- if last_import.module == record.module:
- yield self._error(record, FROMIMPORT_MULTIPLE)
- # Check the sort order of the imported names.
- if sorted(record.names) != record.names:
- yield self._error(record, FROMIMPORT_NAMES_UNSORTED)
- # How to check for no blank lines between from imports?
- # Update the last import.
- last_import = record
diff --git a/tox.ini b/tox.ini
index 7892b557a..34bd367d1 100644
--- a/tox.ini
+++ b/tox.ini
@@ -35,6 +35,7 @@ commands =
python -m flake8 src
deps =
flake8>3.0
+ flufl.testing
[testenv:docs]
basepython = python3
@@ -51,3 +52,4 @@ rc = --rcfile={[coverage]rcfile}
max-line-length = 79
exclude = src/mailman/compat/*.py
jobs = 1
+enable-extensions = U4
--
cgit v1.3.1
From 5d73d057854191637b248da0875cf7ce005bbffb Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 29 Nov 2016 19:25:25 -0500
Subject: Fix an import.
---
src/mailman/config/config.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/mailman/config/config.py b/src/mailman/config/config.py
index 1f4384eb7..a274aa3b9 100644
--- a/src/mailman/config/config.py
+++ b/src/mailman/config/config.py
@@ -24,13 +24,14 @@ import mailman.templates
from configparser import ConfigParser
from flufl.lock import Lock
from lazr.config import ConfigSchema, as_boolean
+from mailman import version
from mailman.interfaces.configuration import (
ConfigurationUpdatedEvent, IConfiguration, MissingConfigurationFileError)
from mailman.interfaces.languages import ILanguageManager
from mailman.utilities.filesystem import makedirs
from mailman.utilities.modules import call_name, expand_path
from pkg_resources import resource_filename, resource_string as resource_bytes
-from public import public, version
+from public import public
from string import Template
from zope.component import getUtility
from zope.event import notify
--
cgit v1.3.1
From cdd24f88bd36aa2bd87252618e98b80aa7cc1bf1 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 29 Nov 2016 19:58:16 -0500
Subject: More fixes & flufl.testing.
---
setup.py | 1 +
src/mailman/core/system.py | 3 +-
src/mailman/testing/nose.py | 118 --------------------------------------------
unittest.cfg | 5 +-
4 files changed, 7 insertions(+), 120 deletions(-)
delete mode 100644 src/mailman/testing/nose.py
diff --git a/setup.py b/setup.py
index 378bc989a..c31817b9a 100644
--- a/setup.py
+++ b/setup.py
@@ -110,6 +110,7 @@ case second `m'. Any other spelling is incorrect.""",
'flufl.bounce',
'flufl.i18n',
'flufl.lock',
+ 'flufl.testing',
'httplib2',
'lazr.config',
'nose2',
diff --git a/src/mailman/core/system.py b/src/mailman/core/system.py
index 2d76f0c97..41ddced95 100644
--- a/src/mailman/core/system.py
+++ b/src/mailman/core/system.py
@@ -19,8 +19,9 @@
import sys
+from mailman import version
from mailman.interfaces.system import ISystem
-from public import public, version
+from public import public
from zope.interface import implementer
diff --git a/src/mailman/testing/nose.py b/src/mailman/testing/nose.py
deleted file mode 100644
index 1a9830da5..000000000
--- a/src/mailman/testing/nose.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# Copyright (C) 2013-2016 by the Free Software Foundation, Inc.
-#
-# This file is part of GNU Mailman.
-#
-# GNU Mailman is free software: you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free
-# Software Foundation, either version 3 of the License, or (at your option)
-# any later version.
-#
-# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-# more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# GNU Mailman. If not, see .
-
-"""nose2 test infrastructure."""
-
-import os
-import re
-import doctest
-import importlib
-
-from mailman.testing.documentation import setup, teardown
-from mailman.testing.layers import ConfigLayer, MockAndMonkeyLayer, SMTPLayer
-from nose2.events import Plugin
-from pkg_resources import resource_filename
-from public import public
-
-
-DOT = '.'
-FLAGS = doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE | doctest.REPORT_NDIFF
-TOPDIR = os.path.dirname(resource_filename('mailman', '__init__.py'))
-
-
-@public
-class NosePlugin(Plugin):
- configSection = 'mailman'
-
- def __init__(self):
- super().__init__()
- self.patterns = []
- self.stderr = False
- def set_stderr(ignore): # noqa: E306
- self.stderr = True
- self.addArgument(self.patterns, 'P', 'pattern',
- 'Add a test matching pattern')
- self.addFlag(set_stderr, 'E', 'stderr',
- 'Enable stderr logging to sub-runners')
-
- def startTestRun(self, event):
- MockAndMonkeyLayer.testing_mode = True
- if (self.stderr or
- len(os.environ.get('MM_VERBOSE_TESTLOG', '').strip()) > 0):
- ConfigLayer.stderr = True
-
- def getTestCaseNames(self, event):
- if len(self.patterns) == 0:
- # No filter patterns, so everything should be tested.
- return
- # Does the pattern match the fully qualified class name?
- for pattern in self.patterns:
- full_class_name = '{}.{}'.format(
- event.testCase.__module__, event.testCase.__name__)
- if re.search(pattern, full_class_name):
- # Don't suppress this test class.
- return
- names = filter(event.isTestMethod, dir(event.testCase))
- for name in names:
- full_test_name = '{}.{}.{}'.format(
- event.testCase.__module__,
- event.testCase.__name__,
- name)
- for pattern in self.patterns:
- if re.search(pattern, full_test_name):
- break
- else:
- event.excludedNames.append(name)
-
- def handleFile(self, event):
- path = event.path[len(TOPDIR)+1:]
- if len(self.patterns) > 0:
- for pattern in self.patterns:
- if re.search(pattern, path):
- break
- else:
- # Skip this doctest.
- return
- base, ext = os.path.splitext(path)
- if ext != '.rst':
- return
- # Look to see if the package defines a test layer, otherwise use the
- # default layer. First turn the file system path into a dotted Python
- # module path.
- parent = os.path.dirname(path)
- dotted = 'mailman.' + DOT.join(parent.split(os.path.sep))
- try:
- module = importlib.import_module(dotted)
- except ImportError:
- layer = SMTPLayer
- else:
- layer = getattr(module, 'layer', SMTPLayer)
- test = doctest.DocFileTest(
- path, package='mailman',
- optionflags=FLAGS,
- setUp=setup,
- tearDown=teardown)
- test.layer = layer
- # Suppress the extra "Doctest: ..." line.
- test.shortDescription = lambda: None
- event.extraTests.append(test)
-
- # def startTest(self, event):
- # import sys; print('vvvvv', event.test, file=sys.stderr)
-
- # def stopTest(self, event):
- # import sys; print('^^^^^', event.test, file=sys.stderr)
diff --git a/unittest.cfg b/unittest.cfg
index d639a8ae3..4b080f22e 100644
--- a/unittest.cfg
+++ b/unittest.cfg
@@ -1,6 +1,6 @@
[unittest]
verbose = 2
-plugins = mailman.testing.nose
+plugins = flufl.testing.nose
nose2.plugins.layers
[mailman]
@@ -8,3 +8,6 @@ always-on = True
[log-capture]
always-on = False
+
+[flufl.testing]
+package = mailman
--
cgit v1.3.1
From 7d172db85b7bee4731853471528a612980be5611 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Tue, 29 Nov 2016 22:24:22 -0500
Subject: Enable the flufl.testing extension.
---
unittest.cfg | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/unittest.cfg b/unittest.cfg
index 4b080f22e..9fc0912a9 100644
--- a/unittest.cfg
+++ b/unittest.cfg
@@ -3,11 +3,9 @@ verbose = 2
plugins = flufl.testing.nose
nose2.plugins.layers
-[mailman]
-always-on = True
-
[log-capture]
always-on = False
[flufl.testing]
+always-on = True
package = mailman
--
cgit v1.3.1
From b0f5e43046c6b4be473e1d98623e3157221719af Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Wed, 30 Nov 2016 15:03:35 -0500
Subject: Finish configuring flufl.testing.
Also, use the better way to set the LMTP ident.
---
src/mailman/runners/lmtp.py | 7 +++----
src/mailman/testing/helpers.py | 8 ++++++++
unittest.cfg | 4 ++++
3 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/src/mailman/runners/lmtp.py b/src/mailman/runners/lmtp.py
index 0fa13a611..b0f473c0b 100644
--- a/src/mailman/runners/lmtp.py
+++ b/src/mailman/runners/lmtp.py
@@ -93,9 +93,6 @@ ERR_502 = '502 Error: command HELO not implemented'
ERR_550 = '550 Requested action not taken: mailbox unavailable'
ERR_550_MID = '550 No Message-ID header provided'
-# XXX Blech
-aiosmtpd.smtp.__version__ = 'GNU Mailman LMTP runner 2.0'
-
def split_recipient(address):
"""Split an address into listname, subaddress and domain parts.
@@ -218,7 +215,9 @@ class LMTPHandler:
class LMTPController(Controller):
def factory(self):
- return LMTP(self.handler)
+ server = LMTP(self.handler)
+ server.__ident__ = 'GNU Mailman LMTP runner 2.0'
+ return server
def make_socket(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
diff --git a/src/mailman/testing/helpers.py b/src/mailman/testing/helpers.py
index 01b362192..233b03cf8 100644
--- a/src/mailman/testing/helpers.py
+++ b/src/mailman/testing/helpers.py
@@ -568,3 +568,11 @@ def hackenv(envar, new_value):
del os.environ[envar]
else:
os.environ[envar] = old_value
+
+
+def nose2_start_test_run_callback(plugin):
+ from mailman.testing.layers import ConfigLayer, MockAndMonkeyLayer
+ MockAndMonkeyLayer.testing_mode = True
+ if (plugin.stderr or
+ len(os.environ.get('MM_VERBOSE_TESTLOG', '').strip()) > 0):
+ ConfigLayer.stderr = True
diff --git a/unittest.cfg b/unittest.cfg
index 9fc0912a9..ba479fdf8 100644
--- a/unittest.cfg
+++ b/unittest.cfg
@@ -9,3 +9,7 @@ always-on = False
[flufl.testing]
always-on = True
package = mailman
+start_run = mailman.testing.helpers.nose2_start_test_run_callback
+default_layer = mailman.testing.layers.SMTPLayer
+setup = mailman.testing.documentation.setup
+teardown = mailman.testing.documentation.teardown
--
cgit v1.3.1
From 4a8b154e92acc76cdb437f2dc57543f67e1390a3 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Wed, 30 Nov 2016 15:12:01 -0500
Subject: Remove some unused imports.
---
src/mailman/runners/lmtp.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/mailman/runners/lmtp.py b/src/mailman/runners/lmtp.py
index b0f473c0b..25d531da4 100644
--- a/src/mailman/runners/lmtp.py
+++ b/src/mailman/runners/lmtp.py
@@ -37,8 +37,6 @@ so that the peer mail server can provide better diagnostics.
import email
import socket
import logging
-import aiosmtpd
-import aiosmtpd.smtp
from aiosmtpd.controller import Controller
from aiosmtpd.lmtp import LMTP
--
cgit v1.3.1
From a30bbdf0d483150dc4259b8d149679d38b6030f1 Mon Sep 17 00:00:00 2001
From: Barry Warsaw
Date: Sat, 3 Dec 2016 11:08:18 -0500
Subject: Prevent the occasional CI/testsuite hang.
This doesn't solve the underlying problem of why child processes (both
runners and master) occasionally don't exit, but it prevents ugly
timeouts in the CI infrastructure when that happens.
---
src/mailman/commands/tests/test_control.py | 58 ++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 3 deletions(-)
diff --git a/src/mailman/commands/tests/test_control.py b/src/mailman/commands/tests/test_control.py
index 7377c4666..4425b3411 100644
--- a/src/mailman/commands/tests/test_control.py
+++ b/src/mailman/commands/tests/test_control.py
@@ -64,6 +64,59 @@ def find_master():
return None
+def kill_with_extreme_prejudice(pid=None):
+ # 2016-12-03 barry: We have intermittent hangs during both local and CI
+ # test suite runs where killing a runner or master process doesn't
+ # terminate the process. In those cases, wait()ing on the child can
+ # suspend the test process indefinitely. Locally, you have to C-c the
+ # test process, but that still doesn't kill it; the process continues to
+ # run in the background. If you then search for the process's pid and
+ # SIGTERM it, it will usually exit, which is why I don't understand why
+ # the above SIGTERM doesn't kill it sometimes. However, when run under
+ # CI, the test suite will just hang until the CI runner times it out. It
+ # would be better to figure out the underlying cause, because we have
+ # definitely seen other situations where a runner process won't exit, but
+ # for testing purposes we're just trying to clean up some resources so
+ # after a brief attempt at SIGTERMing it, let's SIGKILL it and warn.
+ if pid is not None:
+ os.kill(pid, signal.SIGTERM)
+ until = timedelta(seconds=10) + datetime.now()
+ while datetime.now() < until:
+ try:
+ if pid is None:
+ os.wait3(os.WNOHANG)
+ else:
+ os.waitpid(pid, os.WNOHANG)
+ except ChildProcessError:
+ # This basically means we went one too many times around the
+ # loop. The previous iteration successfully reaped the child.
+ # Because the return status of wait3() and waitpid() are different
+ # in those cases, it's easier just to catch the exception for
+ # either call and exit.
+ return
+ time.sleep(0.1)
+ else:
+ if pid is None:
+ # There's really not much more we can do because we have no pid to
+ # SIGKILL. Just report the problem and continue.
+ print('WARNING: NO CHANGE IN CHILD PROCESS STATES',
+ file=sys.stderr)
+ return
+ print('WARNING: SIGTERM DID NOT EXIT PROCESS; SIGKILLing',
+ file=sys.stderr)
+ if pid is not None:
+ os.kill(pid, signal.SIGKILL)
+ until = timedelta(seconds=10) + datetime.now()
+ while datetime.now() < until:
+ status = os.waitpid(pid, os.WNOHANG)
+ if status == (0, 0):
+ # The child was reaped.
+ return
+ time.sleep(0.1)
+ else:
+ print('WARNING: SIGKILL DID NOT EXIT PROCESS!', file=sys.stderr)
+
+
class FakeArgs:
force = None
run_as_user = None
@@ -171,7 +224,7 @@ class TestBinDir(unittest.TestCase):
args_config = Configuration()
args_config.load(self.args.config)
self.assertFalse(os.path.exists(args_config.PID_FILE))
- os.wait()
+ kill_with_extreme_prejudice()
def test_master_is_elsewhere_and_findable(self):
with ExitStack() as resources:
@@ -188,5 +241,4 @@ class TestBinDir(unittest.TestCase):
# killable. We might have to wait until the process has started.
master_pid = find_master()
self.assertIsNotNone(master_pid, 'master did not start')
- os.kill(master_pid, signal.SIGTERM)
- os.waitpid(master_pid, 0)
+ kill_with_extreme_prejudice(master_pid)
--
cgit v1.3.1