summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Defaults.py14
-rw-r--r--Mailman/app/styles.py22
-rw-r--r--Mailman/database/listmanager.py6
-rw-r--r--Mailman/database/model/mailinglist.py2
-rw-r--r--Mailman/database/model/requests.py16
-rw-r--r--Mailman/docs/digests.txt4
-rw-r--r--Mailman/docs/news-runner.txt10
-rw-r--r--Mailman/docs/replybot.txt47
-rw-r--r--Mailman/docs/requests.txt52
-rw-r--r--Mailman/docs/runner.txt12
-rw-r--r--Mailman/docs/scrubber.txt30
-rw-r--r--Mailman/docs/styles.txt8
-rw-r--r--Mailman/docs/subject-munging.txt77
-rw-r--r--Mailman/docs/tagger.txt43
-rw-r--r--Mailman/queue/__init__.py3
15 files changed, 139 insertions, 207 deletions
diff --git a/Mailman/Defaults.py b/Mailman/Defaults.py
index a5234bdd9..7175894bf 100644
--- a/Mailman/Defaults.py
+++ b/Mailman/Defaults.py
@@ -455,7 +455,7 @@ NNTP_USERNAME = None
NNTP_PASSWORD = None
# Set this if you have an NNTP server you prefer gatewayed lists to use.
-DEFAULT_NNTP_HOST = ''
+DEFAULT_NNTP_HOST = u''
# These variables controls how headers must be cleansed in order to be
# accepted by your NNTP server. Some servers like INN reject messages
@@ -809,7 +809,7 @@ MAX_RESTARTS = 10
# The default language for this server. Whenever we can't figure out the list
# context or user context, we'll fall back to using this language. This code
# must be in the list of available language codes.
-DEFAULT_SERVER_LANGUAGE = 'en'
+DEFAULT_SERVER_LANGUAGE = u'en'
# When allowing only members to post to a mailing list, how is the sender of
# the message determined? If this variable is set to Yes, then first the
@@ -909,10 +909,10 @@ DEFAULT_MAX_MESSAGE_SIZE = 40 # KB
# These format strings will be expanded w.r.t. the dictionary for the
# mailing list instance.
-DEFAULT_SUBJECT_PREFIX = "[%(real_name)s] "
+DEFAULT_SUBJECT_PREFIX = u'[%(real_name)s] '
# DEFAULT_SUBJECT_PREFIX = "[%(real_name)s %%d]" # for numbering
-DEFAULT_MSG_HEADER = ""
-DEFAULT_MSG_FOOTER = """\
+DEFAULT_MSG_HEADER = u''
+DEFAULT_MSG_FOOTER = u"""\
_______________________________________________
$real_name mailing list
$fqdn_realname
@@ -978,7 +978,7 @@ DEFAULT_SEND_GOODBYE_MSG = Yes
DEFAULT_ANONYMOUS_LIST = No
# {header-name: regexp} spam filtering - we include some for example sake.
-DEFAULT_BOUNCE_MATCHING_HEADERS = """
+DEFAULT_BOUNCE_MATCHING_HEADERS = u"""
# Lines that *start* with a '#' are comments.
to: friend@public.com
message-id: relay.comanche.denmark.eu
@@ -1098,7 +1098,7 @@ DEFAULT_NONDIGESTABLE = Yes
# Will list be available in digested form?
DEFAULT_DIGESTABLE = Yes
-DEFAULT_DIGEST_HEADER = ""
+DEFAULT_DIGEST_HEADER = u''
DEFAULT_DIGEST_FOOTER = DEFAULT_MSG_FOOTER
DEFAULT_DIGEST_IS_DEFAULT = No
diff --git a/Mailman/app/styles.py b/Mailman/app/styles.py
index 39e8355db..4ca3f1b01 100644
--- a/Mailman/app/styles.py
+++ b/Mailman/app/styles.py
@@ -57,7 +57,7 @@ class DefaultStyle:
mlist.max_num_recipients = config.DEFAULT_MAX_NUM_RECIPIENTS
mlist.max_message_size = config.DEFAULT_MAX_MESSAGE_SIZE
mlist.reply_goes_to_list = config.DEFAULT_REPLY_GOES_TO_LIST
- mlist.reply_to_address = ''
+ mlist.reply_to_address = u''
mlist.first_strip_reply_to = config.DEFAULT_FIRST_STRIP_REPLY_TO
mlist.admin_immed_notify = config.DEFAULT_ADMIN_IMMED_NOTIFY
mlist.admin_notify_mchanges = (
@@ -72,10 +72,10 @@ class DefaultStyle:
config.DEFAULT_BOUNCE_MATCHING_HEADERS)
mlist.header_filter_rules = []
mlist.anonymous_list = config.DEFAULT_ANONYMOUS_LIST
- mlist.description = ''
- mlist.info = ''
- mlist.welcome_msg = ''
- mlist.goodbye_msg = ''
+ mlist.description = u''
+ mlist.info = u''
+ mlist.welcome_msg = u''
+ mlist.goodbye_msg = u''
mlist.subscribe_policy = config.DEFAULT_SUBSCRIBE_POLICY
mlist.subscribe_auto_approval = config.DEFAULT_SUBSCRIBE_AUTO_APPROVAL
mlist.unsubscribe_policy = config.DEFAULT_UNSUBSCRIBE_POLICY
@@ -120,7 +120,7 @@ class DefaultStyle:
config.DEFAULT_ARCHIVE_VOLUME_FREQUENCY)
mlist.emergency = False
mlist.member_moderation_action = Action.hold
- mlist.member_moderation_notice = ''
+ mlist.member_moderation_notice = u''
mlist.accept_these_nonmembers = []
mlist.hold_these_nonmembers = []
mlist.reject_these_nonmembers = []
@@ -128,7 +128,7 @@ class DefaultStyle:
mlist.forward_auto_discards = config.DEFAULT_FORWARD_AUTO_DISCARDS
mlist.generic_nonmember_action = (
config.DEFAULT_GENERIC_NONMEMBER_ACTION)
- mlist.nonmember_rejection_notice = ''
+ mlist.nonmember_rejection_notice = u''
# Ban lists
mlist.ban_list = []
# Max autoresponses per day. A mapping between addresses and a
@@ -157,9 +157,9 @@ class DefaultStyle:
# 1 - autorespond, but discard the original message
# 2 - autorespond, and forward the message on to be processed
mlist.autorespond_requests = 0
- mlist.autoresponse_postings_text = ''
- mlist.autoresponse_admin_text = ''
- mlist.autoresponse_request_text = ''
+ mlist.autoresponse_postings_text = u''
+ mlist.autoresponse_admin_text = u''
+ mlist.autoresponse_request_text = u''
mlist.autoresponse_graceperiod = datetime.timedelta(days=90)
mlist.postings_responses = {}
mlist.admin_responses = {}
@@ -187,7 +187,7 @@ class DefaultStyle:
mlist.delivery_status = {}
# NNTP gateway
mlist.nntp_host = config.DEFAULT_NNTP_HOST
- mlist.linked_newsgroup = ''
+ mlist.linked_newsgroup = u''
mlist.gateway_to_news = False
mlist.gateway_to_mail = False
mlist.news_prefix_subject_too = True
diff --git a/Mailman/database/listmanager.py b/Mailman/database/listmanager.py
index 1a17cb96e..cd1f03fe2 100644
--- a/Mailman/database/listmanager.py
+++ b/Mailman/database/listmanager.py
@@ -49,8 +49,12 @@ class ListManager(object):
mlist.delete()
def get(self, fqdn_listname):
+ # Avoid circular imports.
+ from Mailman.database.model import MailingList
listname, hostname = split_listname(fqdn_listname)
- mlist = MailingList.get_by(list_name=listname, host_name=hostname)
+ mlist = config.db.store.find(MailingList,
+ list_name=listname,
+ host_name=hostname).one()
if mlist is not None:
# XXX Fixme
mlist._restore()
diff --git a/Mailman/database/model/mailinglist.py b/Mailman/database/model/mailinglist.py
index ed34a3aae..3a3396758 100644
--- a/Mailman/database/model/mailinglist.py
+++ b/Mailman/database/model/mailinglist.py
@@ -120,7 +120,7 @@ class MailingList(Model):
max_days_to_hold = Int()
max_message_size = Int()
max_num_recipients = Int()
- member_moderation_action = Bool()
+ member_moderation_action = Enum()
member_moderation_notice = Unicode()
mime_is_default_digest = Bool()
moderator_password = Unicode()
diff --git a/Mailman/database/model/requests.py b/Mailman/database/model/requests.py
index d16e8f49d..5e92e70b2 100644
--- a/Mailman/database/model/requests.py
+++ b/Mailman/database/model/requests.py
@@ -47,21 +47,25 @@ class ListRequests:
@property
def count(self):
- return _Request.query.filter_by(mailing_list=self.mailing_list).count()
+ return config.db.store.find(
+ _Request, mailing_list=self.mailing_list).count()
def count_of(self, request_type):
- return _Request.query.filter_by(mailing_list=self.mailing_list,
- type=request_type).count()
+ return config.db.store.find(
+ _Request,
+ mailing_list=self.mailing_list, type=request_type).count()
@property
def held_requests(self):
- results = _Request.query.filter_by(mailing_list=self.mailing_list)
+ results = config.db.store.find(
+ _Request, mailing_list=self.mailing_list)
for request in results:
yield request
def of_type(self, request_type):
- results = _Request.query.filter_by(mailing_list=self.mailing_list,
- type=request_type)
+ results = config.db.store.find(
+ _Request,
+ mailing_list=self.mailing_list, type=request_type)
for request in results:
yield request
diff --git a/Mailman/docs/digests.txt b/Mailman/docs/digests.txt
index 72c34b372..486d64098 100644
--- a/Mailman/docs/digests.txt
+++ b/Mailman/docs/digests.txt
@@ -417,7 +417,7 @@ XXX We also have to set the default server language to French, otherwise the
English template will be found and the masthead won't be translated.
>>> config.languages.enable_language('fr')
- >>> config.DEFAULT_SERVER_LANGUAGE = 'fr'
+ >>> config.DEFAULT_SERVER_LANGUAGE = u'fr'
>>> mlist.preferred_language = 'fr'
>>> msg = message_from_string("""\
... From: aperson@example.org
@@ -539,4 +539,4 @@ Set the digest threshold to zero so that the digests will be sent immediately.
Clean up
--------
- >>> config.DEFAULT_SERVER_LANGUAGE = 'en'
+ >>> config.DEFAULT_SERVER_LANGUAGE = u'en'
diff --git a/Mailman/docs/news-runner.txt b/Mailman/docs/news-runner.txt
index 7adbc7add..bc6619f50 100644
--- a/Mailman/docs/news-runner.txt
+++ b/Mailman/docs/news-runner.txt
@@ -8,8 +8,8 @@ was originally written to gate to Usenet, which has its own rules).
>>> from Mailman.configuration import config
>>> from Mailman.queue.news import prepare_message
- >>> mlist = config.db.list_manager.create('_xtest@example.com')
- >>> mlist.linked_newsgroup = 'comp.lang.python'
+ >>> mlist = config.db.list_manager.create(u'_xtest@example.com')
+ >>> mlist.linked_newsgroup = u'comp.lang.python'
Some NNTP servers such as INN reject messages containing a set of prohibited
headers, so one of the things that the news runner does is remove these
@@ -128,7 +128,7 @@ address is added for the benefit of the Usenet system.
... """)
>>> prepare_message(mlist, msg, {})
>>> msg['approved']
- '_xtest@example.com'
+ u'_xtest@example.com'
>>> mlist.news_moderation = NewsModeration.moderated
>>> msg = message_from_string("""\
@@ -139,7 +139,7 @@ address is added for the benefit of the Usenet system.
... """)
>>> prepare_message(mlist, msg, {})
>>> msg['approved']
- '_xtest@example.com'
+ u'_xtest@example.com'
But if the newsgroup is not moderated, the Approved: header is not chnaged.
@@ -152,7 +152,7 @@ But if the newsgroup is not moderated, the Approved: header is not chnaged.
... """)
>>> prepare_message(mlist, msg, {})
>>> msg['approved']
- "this doesn't get deleted"
+ u"this doesn't get deleted"
XXX More of the NewsRunner should be tested.
diff --git a/Mailman/docs/replybot.txt b/Mailman/docs/replybot.txt
index 8ca131bf8..424fa2944 100644
--- a/Mailman/docs/replybot.txt
+++ b/Mailman/docs/replybot.txt
@@ -6,15 +6,11 @@ it receives on its posting address, or special robot addresses. Automatic
responses are subject to various conditions, such as headers in the original
message or the amount of time since the last auto-response.
- >>> from email import message_from_string
>>> from Mailman.Handlers.Replybot import process
- >>> from Mailman.Message import Message
>>> from Mailman.configuration import config
- >>> from Mailman.database import flush
- >>> mlist = config.db.list_manager.create('_xtest@example.com')
- >>> mlist.real_name = 'XTest'
- >>> mlist.web_page_url = 'http://www.example.com/'
- >>> flush()
+ >>> mlist = config.db.list_manager.create(u'_xtest@example.com')
+ >>> mlist.real_name = u'XTest'
+ >>> mlist.web_page_url = u'http://www.example.com/'
>>> # Ensure that the virgin queue is empty, since we'll be checking this
>>> # for new auto-response messages.
@@ -36,23 +32,22 @@ will be sent, with 0 meaning "there is no grace period".
>>> import datetime
>>> mlist.autorespond_admin = True
>>> mlist.autoresponse_graceperiod = datetime.timedelta()
- >>> mlist.autoresponse_admin_text = 'admin autoresponse text'
- >>> flush()
- >>> msg = message_from_string("""\
+ >>> mlist.autoresponse_admin_text = u'admin autoresponse text'
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... To: _xtest-owner@example.com
...
... help
- ... """, Message)
+ ... """)
>>> process(mlist, msg, dict(toowner=True))
>>> len(virginq.files)
1
>>> qmsg, qdata = virginq.dequeue(virginq.files[0])
>>> # Print only some of the meta data. The rest is uninteresting.
>>> qdata['listname']
- '_xtest@example.com'
+ u'_xtest@example.com'
>>> sorted(qdata['recips'])
- ['aperson@example.com']
+ [u'aperson@example.com']
>>> # Delete data that is time dependent or random
>>> del qmsg['message-id']
>>> del qmsg['date']
@@ -79,12 +74,12 @@ Several headers in the original message determine whether an autoresponse
should even be sent. For example, if the message has an "X-Ack: No" header,
no auto-response is sent.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... X-Ack: No
...
... help me
- ... """, Message)
+ ... """)
>>> process(mlist, msg, dict(toowner=True))
>>> virginq.files
[]
@@ -92,11 +87,11 @@ no auto-response is sent.
Mailman itself can suppress autoresponses for certain types of internally
crafted messages, by setting the 'noack' metadata key.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: mailman@example.com
...
... help for you
- ... """, Message)
+ ... """)
>>> process(mlist, msg, dict(noack=True, toowner=True))
>>> virginq.files
[]
@@ -104,12 +99,12 @@ crafted messages, by setting the 'noack' metadata key.
If there is a Precedence: header with any of the values 'bulk', 'junk', or
'list', then the autoresponse is also suppressed.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: asystem@example.com
... Precedence: bulk
...
... hey!
- ... """, Message)
+ ... """)
>>> process(mlist, msg, dict(toowner=True))
>>> virginq.files
[]
@@ -155,14 +150,13 @@ with the text set for owner responses. Two other types of email will get
auto-responses: those sent to the -request address...
>>> mlist.autorespond_requests = True
- >>> mlist.autoresponse_request_text = 'robot autoresponse text'
- >>> flush()
- >>> msg = message_from_string("""\
+ >>> mlist.autoresponse_request_text = u'robot autoresponse text'
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... To: _xtest-request@example.com
...
... help me
- ... """, Message)
+ ... """)
>>> process(mlist, msg, dict(torequest=True))
>>> len(virginq.files)
1
@@ -185,14 +179,13 @@ auto-responses: those sent to the -request address...
...and those sent to the posting address.
>>> mlist.autorespond_postings = True
- >>> mlist.autoresponse_postings_text = 'postings autoresponse text'
- >>> flush()
- >>> msg = message_from_string("""\
+ >>> mlist.autoresponse_postings_text = u'postings autoresponse text'
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... To: _xtest@example.com
...
... help me
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> len(virginq.files)
1
diff --git a/Mailman/docs/requests.txt b/Mailman/docs/requests.txt
index 914ce7dfb..febf3e430 100644
--- a/Mailman/docs/requests.txt
+++ b/Mailman/docs/requests.txt
@@ -6,7 +6,6 @@ closed lists, or postings by non-members. The requests database is the low
level interface to these actions requiring approval.
>>> from Mailman.configuration import config
- >>> from Mailman.database import flush
Here is a helper function for printing out held requests.
@@ -42,8 +41,7 @@ mailing list you need to get its requests object.
>>> from zope.interface.verify import verifyObject
>>> verifyObject(IRequests, config.db.requests)
True
- >>> mlist = config.db.list_manager.create('test@example.com')
- >>> flush()
+ >>> mlist = config.db.list_manager.create(u'test@example.com')
>>> requests = config.db.requests.get_list_requests(mlist)
>>> verifyObject(IListRequests, requests)
True
@@ -73,7 +71,6 @@ data, except for the request type. Here we hold some simple bits of data.
>>> id_4 = requests.hold_request(RequestType.held_message, 'hold_4')
>>> id_1, id_2, id_3, id_4
(1, 2, 3, 4)
- >>> flush()
And of course, now we can see that there are four requests being held.
@@ -102,7 +99,6 @@ We can hold requests with additional data.
>>> data = dict(foo='yes', bar='no')
>>> id_5 = requests.hold_request(RequestType.held_message, 'hold_5', data)
- >>> flush()
>>> id_5
5
>>> requests.count
@@ -172,7 +168,6 @@ Once a specific request has been handled, it will be deleted from the requests
database.
>>> requests.delete_request(2)
- >>> flush()
>>> requests.count
4
>>> show_holds(requests)
@@ -194,7 +189,6 @@ For the next section, we first clean up all the current requests.
>>> for request in requests.held_requests:
... requests.delete_request(request.id)
- >>> flush()
>>> requests.count
0
@@ -218,16 +212,14 @@ For this section, we need a mailing list and at least one message.
>>> mlist = config.db.list_manager.create('alist@example.com')
>>> mlist.preferred_language = 'en'
>>> mlist.real_name = 'A Test List'
- >>> flush()
>>> from email import message_from_string
- >>> from Mailman.Message import Message
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.org
... To: alist@example.com
... Subject: Something important
...
... Here's something important about our mailing list.
- ... """, Message)
+ ... """)
Holding a message means keeping a copy of it that a moderator must approve
before the message is posted to the mailing list. To hold the message, you
@@ -235,7 +227,6 @@ must supply the message, message metadata, and a text reason for the hold. In
this case, we won't include any additional metadata.
>>> id_1 = moderator.hold_message(mlist, msg, {}, 'Needs approval')
- >>> flush()
>>> requests.get_request(id_1) is not None
True
@@ -245,7 +236,6 @@ We can also hold a message with some additional metadata.
... approved=True,
... received_time=123.45)
>>> id_2 = moderator.hold_message(mlist, msg, msgdata, 'Feeling ornery')
- >>> flush()
>>> requests.get_request(id_2) is not None
True
@@ -254,7 +244,6 @@ trivial is to simply defer a decision for now.
>>> from Mailman.interfaces import Action
>>> moderator.handle_message(mlist, id_1, Action.defer)
- >>> flush()
>>> requests.get_request(id_1) is not None
True
@@ -262,7 +251,6 @@ The moderator can also discard the message. This is often done with spam.
Bye bye message!
>>> moderator.handle_message(mlist, id_1, Action.discard)
- >>> flush()
>>> print requests.get_request(id_1)
None
>>> virginq.files
@@ -271,7 +259,6 @@ Bye bye message!
The message can be rejected, meaning it is bounced back to the sender.
>>> moderator.handle_message(mlist, id_2, Action.reject, 'Off topic')
- >>> flush()
>>> print requests.get_request(id_2)
None
>>> qmsg, qdata = dequeue()
@@ -314,9 +301,7 @@ the incoming queue for further processing, however the message metadata
indicates that the message has been approved.
>>> id_3 = moderator.hold_message(mlist, msg, msgdata, 'Needs approval')
- >>> flush()
>>> moderator.handle_message(mlist, id_3, Action.accept)
- >>> flush()
>>> inq = Switchboard(config.INQUEUE_DIR)
>>> qmsg, qdata = dequeue(inq)
>>> print qmsg.as_string()
@@ -344,18 +329,16 @@ moderator interface to also preserve a copy, essentially telling it not to
delete the message from the storage. First, without the switch, the message
is deleted.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.org
... To: alist@example.com
... Subject: Something important
... Message-ID: <12345>
...
... Here's something important about our mailing list.
- ... """, Message)
+ ... """)
>>> id_4 = moderator.hold_message(mlist, msg, {}, 'Needs approval')
- >>> flush()
>>> moderator.handle_message(mlist, id_4, Action.discard)
- >>> flush()
>>> msgs = config.db.message_store.get_messages_by_message_id('<12345>')
>>> list(msgs)
[]
@@ -364,9 +347,7 @@ But if we ask to preserve the message when we discard it, it will be held in
the message store after disposition.
>>> id_4 = moderator.hold_message(mlist, msg, {}, 'Needs approval')
- >>> flush()
>>> moderator.handle_message(mlist, id_4, Action.discard, preserve=True)
- >>> flush()
>>> msgs = config.db.message_store.get_messages_by_message_id('<12345>')
>>> msgs = list(msgs)
>>> len(msgs)
@@ -387,10 +368,8 @@ address. This is helpful for getting the message into the inbox of one of the
moderators.
>>> id_4 = moderator.hold_message(mlist, msg, {}, 'Needs approval')
- >>> flush()
>>> moderator.handle_message(mlist, id_4, Action.discard,
... forward=['zperson@example.com'])
- >>> flush()
>>> qmsg, qdata = dequeue()
>>> print qmsg.as_string()
Subject: Forward of moderated message
@@ -429,11 +408,9 @@ chosing and their preferred language.
>>> from Mailman.interfaces import DeliveryMode
>>> mlist.admin_immed_notify = False
- >>> flush()
>>> id_3 = moderator.hold_subscription(mlist,
... 'bperson@example.org', 'Ben Person',
... '{NONE}abcxyz', DeliveryMode.regular, 'en')
- >>> flush()
>>> requests.get_request(id_3) is not None
True
@@ -452,11 +429,9 @@ queue when the message is held.
>>> # XXX This will almost certainly change once we've worked out the web
>>> # space layout for mailing lists now.
>>> mlist.web_page_url = 'http://www.example.com/'
- >>> flush()
>>> id_4 = moderator.hold_subscription(mlist,
... 'cperson@example.org', 'Claire Person',
... '{NONE}zyxcba', DeliveryMode.regular, 'en')
- >>> flush()
>>> requests.get_request(id_4) is not None
True
>>> qmsg, qdata = dequeue()
@@ -496,14 +471,12 @@ Once held, the moderator can select one of several dispositions. The most
trivial is to simply defer a decision for now.
>>> moderator.handle_subscription(mlist, id_3, Action.defer)
- >>> flush()
>>> requests.get_request(id_3) is not None
True
The held subscription can also be discarded.
>>> moderator.handle_subscription(mlist, id_3, Action.discard)
- >>> flush()
>>> print requests.get_request(id_3)
None
@@ -512,7 +485,6 @@ subscriber.
>>> moderator.handle_subscription(mlist, id_4, Action.reject,
... 'This is a closed list')
- >>> flush()
>>> print requests.get_request(id_4)
None
>>> qmsg, qdata = dequeue()
@@ -555,7 +527,6 @@ mailing list.
>>> id_4 = moderator.hold_subscription(mlist,
... 'fperson@example.org', 'Frank Person',
... '{NONE}abcxyz', DeliveryMode.regular, 'en')
- >>> flush()
A message will be sent to the moderators telling them about the held
subscription and the fact that they may need to approve it.
@@ -595,7 +566,6 @@ Accept the subscription request.
>>> mlist.admin_notify_mchanges = True
>>> moderator.handle_subscription(mlist, id_4, Action.accept)
- >>> flush()
There are now two messages in the virgin queue. One is a welcome message
being sent to the user and the other is a subscription notification that is
@@ -709,28 +679,22 @@ In this case, only the unsubscribing address is required. Like subscriptions,
unsubscription holds can send the list's moderators an immediate notification.
>>> mlist.admin_immed_notify = False
- >>> flush()
>>> from Mailman.interfaces import MemberRole
>>> user_1 = config.db.user_manager.create_user('gperson@example.com')
- >>> flush()
>>> address_1 = list(user_1.addresses)[0]
>>> address_1.subscribe(mlist, MemberRole.member)
<Member: gperson@example.com on alist@example.com as MemberRole.member>
>>> user_2 = config.db.user_manager.create_user('hperson@example.com')
- >>> flush()
>>> address_2 = list(user_2.addresses)[0]
>>> address_2.subscribe(mlist, MemberRole.member)
<Member: hperson@example.com on alist@example.com as MemberRole.member>
- >>> flush()
>>> id_5 = moderator.hold_unsubscription(mlist, 'gperson@example.com')
- >>> flush()
>>> requests.get_request(id_5) is not None
True
>>> virginq.files
[]
>>> mlist.admin_immed_notify = True
>>> id_6 = moderator.hold_unsubscription(mlist, 'hperson@example.com')
- >>> flush()
>>> qmsg, qdata = dequeue()
>>> print qmsg.as_string()
MIME-Version: 1.0
@@ -766,7 +730,6 @@ There are now two addresses with held unsubscription requests. As above, one
of the actions we can take is to defer to the decision.
>>> moderator.handle_unsubscription(mlist, id_5, Action.defer)
- >>> flush()
>>> requests.get_request(id_5) is not None
True
@@ -774,7 +737,6 @@ The held unsubscription can also be discarded, and the member will remain
subscribed.
>>> moderator.handle_unsubscription(mlist, id_5, Action.discard)
- >>> flush()
>>> print requests.get_request(id_5)
None
>>> mlist.members.get_member('gperson@example.com')
@@ -785,7 +747,6 @@ and the person remains a member of the mailing list.
>>> moderator.handle_unsubscription(mlist, id_6, Action.reject,
... 'This list is a prison.')
- >>> flush()
>>> print requests.get_request(id_6)
None
>>> qmsg, qdata = dequeue()
@@ -829,11 +790,8 @@ the mailing list.
>>> mlist.send_goodbye_msg = True
>>> mlist.goodbye_msg = 'So long!'
>>> mlist.admin_immed_notify = False
- >>> flush()
>>> id_7 = moderator.hold_unsubscription(mlist, 'gperson@example.com')
- >>> flush()
>>> moderator.handle_unsubscription(mlist, id_7, Action.accept)
- >>> flush()
>>> print mlist.members.get_member('gperson@example.com')
None
diff --git a/Mailman/docs/runner.txt b/Mailman/docs/runner.txt
index 75ec90758..4143c36a6 100644
--- a/Mailman/docs/runner.txt
+++ b/Mailman/docs/runner.txt
@@ -15,14 +15,10 @@ runners inherit from. This base class implements a .run() method that runs
continuously in a loop until the .stop() method is called.
>>> import os
- >>> from email import message_from_string
- >>> from Mailman.Message import Message
>>> from Mailman.queue import Runner, Switchboard
>>> from Mailman.configuration import config
- >>> from Mailman.database import flush
- >>> mlist = config.db.list_manager.create('_xtest@example.com')
- >>> mlist.preferred_language = 'en'
- >>> flush()
+ >>> mlist = config.db.list_manager.create(u'_xtest@example.com')
+ >>> mlist.preferred_language = u'en'
Here is a very simple derived qrunner class. The class attribute QDIR tells
the qrunner which queue directory it is responsible for. Derived classes
@@ -50,12 +46,12 @@ This is about as simple as a qrunner can be.
This qrunner doesn't do much except run once, storing the message and metadata
on instance variables.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... To: _xtest@example.com
...
... A test message.
- ... """, Message)
+ ... """)
>>> filebase = switchboard.enqueue(msg, listname=mlist.fqdn_listname,
... foo='yes', bar='no')
>>> runner.run()
diff --git a/Mailman/docs/scrubber.txt b/Mailman/docs/scrubber.txt
index 0c8c4d94f..e4259361d 100644
--- a/Mailman/docs/scrubber.txt
+++ b/Mailman/docs/scrubber.txt
@@ -7,13 +7,9 @@ scrub attachments from messages so that binary goop doesn't end up in an
archive message.
>>> from Mailman.Handlers.Scrubber import process, save_attachment
- >>> from Mailman.Message import Message
>>> from Mailman.configuration import config
- >>> from Mailman.database import flush
- >>> from email import message_from_string
- >>> mlist = config.db.list_manager.create('_xtest@example.com')
- >>> mlist.preferred_language = 'en'
- >>> flush()
+ >>> mlist = config.db.list_manager.create(u'_xtest@example.com')
+ >>> mlist.preferred_language = u'en'
Helper functions for getting the attachment data.
@@ -56,15 +52,15 @@ enabled, the filename will be used when this header attribute is present (yes,
this is an unfortunate double negative).
>>> config.SCRUBBER_DONT_USE_ATTACHMENT_FILENAME = False
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Content-Type: image/gif; name="xtest.gif"
... Content-Transfer-Encoding: base64
... Content-Disposition: attachment; filename="xtest.gif"
...
... R0lGODdhAQABAIAAAAAAAAAAACwAAAAAAQABAAACAQUAOw==
- ... """, Message)
+ ... """)
>>> save_attachment(mlist, msg, '')
- '<http://www.example.com/pipermail/_xtest@example.com//xtest.gif>'
+ u'<http://www.example.com/pipermail/_xtest@example.com//xtest.gif>'
>>> data = read_attachment('xtest.gif')
>>> data[:6]
'GIF87a'
@@ -85,19 +81,19 @@ Content-Disposition: filename. This is the default for reasons described in
the Defaults.py.in file.
>>> config.SCRUBBER_DONT_USE_ATTACHMENT_FILENAME = True
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Content-Type: image/gif; name="xtest.gif"
... Content-Transfer-Encoding: base64
... Content-Disposition: attachment; filename="xtest.gif"
...
... R0lGODdhAQABAIAAAAAAAAAAACwAAAAAAQABAAACAQUAOw==
- ... """, Message)
+ ... """)
>>> save_attachment(mlist, msg, '')
- '<http://www.example.com/pipermail/_xtest@example.com/.../attachment.gif>'
+ u'<http://www.example.com/pipermail/_xtest@example.com/.../attachment.gif>'
>>> data = read_attachment('xtest.gif')
Traceback (most recent call last):
IOError: [Errno ...] No such file or directory:
- '.../archives/private/_xtest@example.com/xtest.gif'
+ u'.../archives/private/_xtest@example.com/xtest.gif'
>>> data = read_attachment('attachment.gif')
>>> data[:6]
'GIF87a'
@@ -111,7 +107,7 @@ Scrubbing image attachments
When scrubbing image attachments, the original message is modified to include
a reference to the attachment file as available through the on-line archive.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... MIME-Version: 1.0
... Content-Type: multipart/mixed; boundary="BOUNDARY"
...
@@ -126,7 +122,7 @@ a reference to the attachment file as available through the on-line archive.
...
... R0lGODdhAQABAIAAAAAAAAAAACwAAAAAAQABAAACAQUAOw==
... --BOUNDARY--
- ... """, Message)
+ ... """)
>>> msgdata = {}
The Scrubber.process() function is different than other handler process
@@ -186,7 +182,7 @@ Scrubbing text attachments
Similar to image attachments, text attachments will also be scrubbed, but the
placeholder will be slightly different.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... MIME-Version: 1.0
... Content-Type: multipart/mixed; boundary="BOUNDARY"
...
@@ -200,7 +196,7 @@ placeholder will be slightly different.
...
... This is a text attachment.
... --BOUNDARY--
- ... """, Message)
+ ... """)
>>> scrubbed_msg = process(mlist, msg, {})
>>> print scrubbed_msg.as_string()
MIME-Version: 1.0
diff --git a/Mailman/docs/styles.txt b/Mailman/docs/styles.txt
index 12e2744b6..b90302e21 100644
--- a/Mailman/docs/styles.txt
+++ b/Mailman/docs/styles.txt
@@ -14,8 +14,7 @@ modify the mailing list any way it wants.
Let's start with a vanilla mailing list and a default style manager.
>>> from Mailman.configuration import config
- >>> from Mailman.database import flush
- >>> mlist = config.db.list_manager.create('_xtest@example.com')
+ >>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> from Mailman.app.styles import style_manager
@@ -51,7 +50,6 @@ would pick this up and apply it to the mailing list.
None
>>> config.DEFAULT_MSG_FOOTER = u'default footer'
>>> default_style.apply(mlist)
- >>> flush()
>>> mlist.msg_footer
u'default footer'
@@ -87,7 +85,6 @@ styles match the mailing list.
['test']
>>> for style in style_manager.lookup(mlist):
... style.apply(mlist)
- >>> flush()
>>> mlist.msg_footer
u'test footer'
@@ -107,13 +104,11 @@ applied last.
... mailing_list.msg_footer = u'another footer'
>>> mlist.msg_footer = u''
- >>> flush()
>>> mlist.msg_footer
u''
>>> style_manager.register(AnotherTestStyle())
>>> for style in style_manager.lookup(mlist):
... style.apply(mlist)
- >>> flush()
>>> mlist.msg_footer
u'another footer'
@@ -126,7 +121,6 @@ will take effect in the new priority order.
>>> style_2.priority = 10
>>> for style in style_manager.lookup(mlist):
... style.apply(mlist)
- >>> flush()
>>> mlist.msg_footer
u'test footer'
diff --git a/Mailman/docs/subject-munging.txt b/Mailman/docs/subject-munging.txt
index 1ceebd415..388a02564 100644
--- a/Mailman/docs/subject-munging.txt
+++ b/Mailman/docs/subject-munging.txt
@@ -7,14 +7,10 @@ transformations. Some headers get added, others get changed. Some of these
changes depend on mailing list settings and others depend on how the message
is getting sent through the system. We'll take things one-by-one.
- >>> from email import message_from_string
- >>> from Mailman.Message import Message
>>> from Mailman.Handlers.CookHeaders import process
>>> from Mailman.configuration import config
- >>> from Mailman.database import flush
- >>> mlist = config.db.list_manager.create('_xtest@example.com')
+ >>> mlist = config.db.list_manager.create(u'_xtest@example.com')
>>> mlist.subject_prefix = u''
- >>> flush()
Inserting a prefix
@@ -27,12 +23,11 @@ munging, a mailing list must have a preferred language.
>>> mlist.subject_prefix = u'[XTest] '
>>> mlist.preferred_language = u'en'
- >>> flush()
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
...
... A message of great import.
- ... """, Message)
+ ... """)
>>> msgdata = {}
>>> process(mlist, msg, msgdata)
@@ -48,12 +43,12 @@ email.header.Header instance which has an unhelpful repr.
If the original message had a Subject header, then the prefix is inserted at
the beginning of the header's value.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... Subject: Something important
...
... A message of great import.
- ... """, Message)
+ ... """)
>>> msgdata = {}
>>> process(mlist, msg, msgdata)
>>> msgdata['origsubj']
@@ -63,39 +58,39 @@ the beginning of the header's value.
Subject headers are not munged for digest messages.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... Subject: Something important
...
... A message of great import.
- ... """, Message)
+ ... """)
>>> process(mlist, msg, dict(isdigest=True))
>>> msg['subject']
- 'Something important'
+ u'Something important'
Nor are they munged for 'fast tracked' messages, which are generally defined
as messages that Mailman crafts internally.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... Subject: Something important
...
... A message of great import.
- ... """, Message)
+ ... """)
>>> process(mlist, msg, dict(_fasttrack=True))
>>> msg['subject']
- 'Something important'
+ u'Something important'
If a Subject header already has a prefix, usually following a Re: marker,
another one will not be added but the prefix will be moved to the front of the
header text.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... Subject: Re: [XTest] Something important
...
... A message of great import.
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> print msg['subject']
[XTest] Re: Something important
@@ -104,12 +99,12 @@ If the Subjec header has a prefix at the front of the header text, that's
where it will stay. This is called 'new style' prefixing and is the only
option available in Mailman 3.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... Subject: [XTest] Re: Something important
...
... A message of great import.
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> print msg['subject']
[XTest] Re: Something important
@@ -123,10 +118,10 @@ prefixes. Part of what makes this interesting is the encoding of i18n headers
using RFC 2047, and lists whose preferred language is in a different character
set than the encoded header.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: =?iso-2022-jp?b?GyRCJWEhPCVrJV4lcxsoQg==?=
...
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> print msg['subject']
[XTest] =?iso-2022-jp?b?GyRCJWEhPCVrJV4lcxsoQg==?=
@@ -142,13 +137,12 @@ message is posted to the mailing list, a 'post id' gets incremented. This is
a purely sequential integer that increases monotonically. By added a '%d'
placeholder to the subject prefix, this post id can be included in the prefix.
- >>> mlist.subject_prefix = '[XTest %d] '
+ >>> mlist.subject_prefix = u'[XTest %d] '
>>> mlist.post_id = 456
- >>> flush()
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: Something important
...
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> print msg['subject']
[XTest 456] Something important
@@ -157,10 +151,10 @@ This works even when the message is a reply, except that in this case, the
numeric post id in the generated subject prefix is updated with the new post
id.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: [XTest 123] Re: Something important
...
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> print msg['subject']
[XTest 456] Re: Something important
@@ -168,10 +162,10 @@ id.
If the Subject header had old style prefixing, the prefix is moved to the
front of the header text.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: Re: [XTest 123] Something important
...
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> print msg['subject']
[XTest 456] Re: Something important
@@ -180,10 +174,10 @@ front of the header text.
And of course, the proper thing is done when posting id numbers are included
in the subject prefix, and the subject is encoded non-ascii.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: =?iso-2022-jp?b?GyRCJWEhPCVrJV4lcxsoQg==?=
...
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> print msg['subject']
[XTest 456] =?iso-2022-jp?b?GyRCJWEhPCVrJV4lcxsoQg==?=
@@ -193,10 +187,10 @@ in the subject prefix, and the subject is encoded non-ascii.
Even more fun is when the i18n Subject header already has a prefix, possibly
with a different posting number.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: [XTest 123] Re: =?iso-2022-jp?b?GyRCJWEhPCVrJV4lcxsoQg==?=
...
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> print msg['subject']
[XTest 456] Re: =?iso-2022-jp?b?GyRCJWEhPCVrJV4lcxsoQg==?=
@@ -207,10 +201,10 @@ with a different posting number.
As before, old style subject prefixes are re-ordered.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: Re: [XTest 123] =?iso-2022-jp?b?GyRCJWEhPCVrJV4lcxsoQg==?=
...
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> print msg['subject']
[XTest 456] Re:
@@ -225,24 +219,23 @@ In this test case, we get an extra space between the prefix and the original
subject. It's because the original is 'crooked'. Note that a Subject
starting with '\n ' is generated by some version of Eudora Japanese edition.
- >>> mlist.subject_prefix = '[XTest] '
- >>> flush()
- >>> msg = message_from_string("""\
+ >>> mlist.subject_prefix = u'[XTest] '
+ >>> msg = message_from_string(u"""\
... Subject:
... Important message
...
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
>>> print msg['subject']
[XTest] Important message
And again, with an RFC 2047 encoded header.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject:
... =?iso-2022-jp?b?GyRCJWEhPCVrJV4lcxsoQg==?=
...
- ... """, Message)
+ ... """)
>>> process(mlist, msg, {})
# XXX This one does not appear to work the same way as
diff --git a/Mailman/docs/tagger.txt b/Mailman/docs/tagger.txt
index a6b2d8ca8..3792f0f7f 100644
--- a/Mailman/docs/tagger.txt
+++ b/Mailman/docs/tagger.txt
@@ -9,12 +9,9 @@ its Subject: and Keywords: headers compared against these regular
expressions. The message then gets tagged with the topic names of each hit.
>>> from Mailman.Handlers.Tagger import process
- >>> from Mailman.Message import Message
>>> from Mailman.queue import Switchboard
>>> from Mailman.configuration import config
- >>> from Mailman.database import flush
- >>> from email import message_from_string
- >>> mlist = config.db.list_manager.create('_xtest@example.com')
+ >>> mlist = config.db.list_manager.create(u'_xtest@example.com')
Topics must be enabled for Mailman to do any topic matching, even if topics
are defined.
@@ -22,13 +19,12 @@ are defined.
>>> mlist.topics = [('bar fight', '.*bar.*', 'catch any bars', False)]
>>> mlist.topics_enabled = False
>>> mlist.topics_bodylines_limit = 0
- >>> flush()
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: foobar
... Keywords: barbaz
...
- ... """, Message)
+ ... """)
>>> msgdata = {}
>>> process(mlist, msg, msgdata)
>>> print msg.as_string()
@@ -44,12 +40,11 @@ artifacts of tagging; an X-Topics: header is added with the topic name, and
the message metadata gets a key with a list of matching topic names.
>>> mlist.topics_enabled = True
- >>> flush()
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: foobar
... Keywords: barbaz
...
- ... """, Message)
+ ... """)
>>> msgdata = {}
>>> process(mlist, msg, msgdata)
>>> print msg.as_string()
@@ -69,7 +64,7 @@ The tagger can also look at a certain number of body lines, but only for
Subject: and Keyword: header-like lines. When set to zero, no body lines are
scanned.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... Subject: nothing
... Keywords: at all
@@ -77,7 +72,7 @@ scanned.
... X-Ignore: something else
... Subject: foobar
... Keywords: barbaz
- ... """, Message)
+ ... """)
>>> msgdata = {}
>>> process(mlist, msg, msgdata)
>>> print msg.as_string()
@@ -96,8 +91,7 @@ But let the tagger scan a few body lines and the matching headers will be
found.
>>> mlist.topics_bodylines_limit = 5
- >>> flush()
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... Subject: nothing
... Keywords: at all
@@ -105,7 +99,7 @@ found.
... X-Ignore: something else
... Subject: foobar
... Keywords: barbaz
- ... """, Message)
+ ... """)
>>> msgdata = {}
>>> process(mlist, msg, msgdata)
>>> print msg.as_string()
@@ -124,7 +118,7 @@ found.
However, scanning stops at the first body line that doesn't look like a
header.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... Subject: nothing
... Keywords: at all
@@ -132,7 +126,7 @@ header.
... This is not a header
... Subject: foobar
... Keywords: barbaz
- ... """, Message)
+ ... """)
>>> msgdata = {}
>>> process(mlist, msg, msgdata)
>>> print msg.as_string()
@@ -149,9 +143,8 @@ header.
When set to a negative number, all body lines will be scanned.
>>> mlist.topics_bodylines_limit = -1
- >>> flush()
>>> lots_of_headers = '\n'.join(['X-Ignore: zip'] * 100)
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... From: aperson@example.com
... Subject: nothing
... Keywords: at all
@@ -159,13 +152,13 @@ When set to a negative number, all body lines will be scanned.
... %s
... Subject: foobar
... Keywords: barbaz
- ... """ % lots_of_headers, Message)
+ ... """ % lots_of_headers)
>>> msgdata = {}
>>> process(mlist, msg, msgdata)
>>> # Rather than print out 100 X-Ignore: headers, let's just prove that
>>> # the X-Topics: header exists, meaning that the tagger did its job.
>>> msg['x-topics']
- 'bar fight'
+ u'bar fight'
>>> msgdata['topichits']
['bar fight']
@@ -177,7 +170,7 @@ The tagger will also scan the body lines of text subparts in a multipart
message, using the same rules as if all those body lines lived in a single
text payload.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: Was
... Keywords: Raw
... Content-Type: multipart/alternative; boundary="BOUNDARY"
@@ -190,7 +183,7 @@ text payload.
... Keywords: barbaz
...
... --BOUNDARY--
- ... """, Message)
+ ... """)
>>> msgdata = {}
>>> process(mlist, msg, msgdata)
>>> print msg.as_string()
@@ -213,7 +206,7 @@ text payload.
But the tagger will not descend into non-text parts.
- >>> msg = message_from_string("""\
+ >>> msg = message_from_string(u"""\
... Subject: Was
... Keywords: Raw
... Content-Type: multipart/alternative; boundary=BOUNDARY
@@ -235,7 +228,7 @@ But the tagger will not descend into non-text parts.
... Keywords: barbaz
...
... --BOUNDARY--
- ... """, Message)
+ ... """)
>>> msgdata = {}
>>> process(mlist, msg, msgdata)
>>> print msg['x-topics']
diff --git a/Mailman/queue/__init__.py b/Mailman/queue/__init__.py
index 94f747245..c415834ba 100644
--- a/Mailman/queue/__init__.py
+++ b/Mailman/queue/__init__.py
@@ -37,6 +37,7 @@ import logging
import marshal
import traceback
+from cStringIO import StringIO
from zope.interface import implements
from Mailman import i18n
@@ -108,7 +109,7 @@ class Switchboard:
# Always add the metadata schema version number
data['version'] = config.QFILE_SCHEMA_VERSION
# Filter out volatile entries
- for k in data:
+ for k in data.keys():
if k.startswith('_'):
del data[k]
# We have to tell the dequeue() method whether to parse the message