diff options
Diffstat (limited to 'Mailman/docs')
39 files changed, 639 insertions, 960 deletions
diff --git a/Mailman/docs/ack-headers.txt b/Mailman/docs/ack-headers.txt index 156a9d530..4418fc4f8 100644 --- a/Mailman/docs/ack-headers.txt +++ b/Mailman/docs/ack-headers.txt @@ -7,14 +7,9 @@ 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() When the message's metadata has a 'noack' key set, an 'X-Ack: no' header is added. @@ -23,17 +18,12 @@ added. ... From: aperson@example.com ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, dict(noack=True)) >>> print msg.as_string() From: aperson@example.com X-Ack: no - X-BeenThere: _xtest@example.com - X-Mailman-Version: ... - Precedence: list - <BLANKLINE> - A message of great import. - <BLANKLINE> + ... Any existing X-Ack header in the original message is removed. @@ -42,14 +32,9 @@ Any existing X-Ack header in the original message is removed. ... From: aperson@example.com ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, dict(noack=True)) >>> print msg.as_string() From: aperson@example.com X-Ack: no - X-BeenThere: _xtest@example.com - X-Mailman-Version: ... - Precedence: list - <BLANKLINE> - A message of great import. - <BLANKLINE> + ... diff --git a/Mailman/docs/acknowledge.txt b/Mailman/docs/acknowledge.txt index c1280095a..f57ed62a3 100644 --- a/Mailman/docs/acknowledge.txt +++ b/Mailman/docs/acknowledge.txt @@ -5,18 +5,13 @@ When a user posts a message to a mailing list, and that user has chosen to receive acknowledgments of their postings, Mailman will sent them such an acknowledgment. - >>> from email import message_from_string - >>> from Mailman.Message import Message >>> from Mailman.Handlers.Acknowledge import process - >>> from Mailman.configuration import config - >>> from Mailman.database import flush - >>> mlist = config.db.list_manager.create('_xtest@example.com') - >>> mlist.real_name = 'XTest' - >>> mlist.preferred_language = 'en' + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') + >>> mlist.real_name = u'XTest' + >>> mlist.preferred_language = u'en' >>> # XXX This will almost certainly change once we've worked out the web >>> # space layout for mailing lists now. - >>> mlist.web_page_url = 'http://lists.example.com/' - >>> flush() + >>> mlist.web_page_url = u'http://lists.example.com/' >>> # Ensure that the virgin queue is empty, since we'll be checking this >>> # for new auto-response messages. @@ -29,11 +24,10 @@ Subscribe a user to the mailing list. >>> usermgr = config.db.user_manager >>> from Mailman.interfaces import MemberRole - >>> user_1 = usermgr.create_user('aperson@example.com') + >>> user_1 = usermgr.create_user(u'aperson@example.com') >>> address_1 = list(user_1.addresses)[0] >>> address_1.subscribe(mlist, MemberRole.member) <Member: aperson@example.com on _xtest@example.com as MemberRole.member> - >>> flush() Non-member posts @@ -41,10 +35,10 @@ Non-member posts Non-members can't get acknowledgments of their posts to the mailing list. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: bperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> virginq.files [] @@ -55,8 +49,8 @@ person is also not a member, no acknowledgment will be sent either. >>> msg = message_from_string("""\ ... From: bperson@example.com ... - ... """, Message) - >>> process(mlist, msg, dict(original_sender='cperson@example.com')) + ... """) + >>> process(mlist, msg, dict(original_sender=u'cperson@example.com')) >>> virginq.files [] @@ -69,7 +63,7 @@ Unless the user has requested acknowledgments, they will not get one. >>> msg = message_from_string("""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> virginq.files [] @@ -78,13 +72,12 @@ Similarly if the original sender is specified in the message metadata, and that sender is a member but not one who has requested acknowledgments, none will be sent. - >>> user_2 = usermgr.create_user('dperson@example.com') + >>> user_2 = usermgr.create_user(u'dperson@example.com') >>> address_2 = list(user_2.addresses)[0] >>> address_2.subscribe(mlist, MemberRole.member) <Member: dperson@example.com on _xtest@example.com as MemberRole.member> - >>> flush() - >>> process(mlist, msg, dict(original_sender='dperson@example.com')) + >>> process(mlist, msg, dict(original_sender=u'dperson@example.com')) >>> virginq.files [] @@ -96,7 +89,6 @@ If the member requests acknowledgments, Mailman will send them one when they post to the mailing list. >>> user_1.preferences.acknowledge_posts = True - >>> flush() The receipt will include the original message's subject in the response body, @@ -104,27 +96,23 @@ The receipt will include the original message's subject in the response body, ... From: aperson@example.com ... Subject: Something witty and insightful ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> len(virginq.files) 1 >>> qmsg, qdata = virginq.dequeue(virginq.files[0]) >>> virginq.files [] - >>> # Print only some of the meta data. The rest is uninteresting. - >>> qdata['listname'] - '_xtest@example.com' - >>> qdata['recips'] - ['aperson@example.com'] + >>> sorted(qdata.items()) + [..., ('recips', [u'aperson@example.com']), ...] >>> print qmsg.as_string() + ... MIME-Version: 1.0 - Content-Type: text/plain; charset="us-ascii" - Content-Transfer-Encoding: 7bit + ... Subject: XTest post acknowledgment From: _xtest-bounces@example.com To: aperson@example.com - Message-ID: ... - Date: ... + ... Precedence: bulk <BLANKLINE> Your message entitled @@ -142,27 +130,22 @@ If there is no subject, then the receipt will use a generic message. >>> msg = message_from_string("""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> len(virginq.files) 1 >>> qmsg, qdata = virginq.dequeue(virginq.files[0]) >>> virginq.files [] - >>> # Print only some of the meta data. The rest is uninteresting. - >>> qdata['listname'] - '_xtest@example.com' - >>> qdata['recips'] - ['aperson@example.com'] + >>> sorted(qdata.items()) + [..., ('recips', [u'aperson@example.com']), ...] >>> print qmsg.as_string() MIME-Version: 1.0 - Content-Type: text/plain; charset="us-ascii" - Content-Transfer-Encoding: 7bit + ... Subject: XTest post acknowledgment From: _xtest-bounces@example.com To: aperson@example.com - Message-ID: ... - Date: ... + ... Precedence: bulk <BLANKLINE> Your message entitled diff --git a/Mailman/docs/addresses.txt b/Mailman/docs/addresses.txt index 4dd8b44ad..0439eaf33 100644 --- a/Mailman/docs/addresses.txt +++ b/Mailman/docs/addresses.txt @@ -6,7 +6,6 @@ those addresses, such as their registration date, and whether and when they've been validated. Addresses may be linked to the users that Mailman knows about. Addresses are subscribed to mailing lists though members. - >>> from Mailman.database import flush >>> from Mailman.configuration import config >>> usermgr = config.db.user_manager @@ -22,24 +21,23 @@ no addresses. Creating an unlinked email address is straightforward. - >>> address_1 = usermgr.create_address('aperson@example.com') - >>> flush() + >>> address_1 = usermgr.create_address(u'aperson@example.com') >>> sorted(address.address for address in usermgr.addresses) - ['aperson@example.com'] + [u'aperson@example.com'] However, such addresses have no real name. >>> address_1.real_name - '' + u'' You can also create an email address object with a real name. - >>> address_2 = usermgr.create_address('bperson@example.com', 'Ben Person') - >>> flush() + >>> address_2 = usermgr.create_address( + ... u'bperson@example.com', u'Ben Person') >>> sorted(address.address for address in usermgr.addresses) - ['aperson@example.com', 'bperson@example.com'] + [u'aperson@example.com', u'bperson@example.com'] >>> sorted(address.real_name for address in usermgr.addresses) - ['', 'Ben Person'] + [u'', u'Ben Person'] The str() of the address is the RFC 2822 preferred originator format, while the repr() carries more information. @@ -51,38 +49,36 @@ the repr() carries more information. You can assign real names to existing addresses. - >>> address_1.real_name = 'Anne Person' - >>> flush() + >>> address_1.real_name = u'Anne Person' >>> sorted(address.real_name for address in usermgr.addresses) - ['Anne Person', 'Ben Person'] + [u'Anne Person', u'Ben Person'] These addresses are not linked to users, and can be seen by searching the user manager for an associated user. - >>> print usermgr.get_user('aperson@example.com') + >>> print usermgr.get_user(u'aperson@example.com') None - >>> print usermgr.get_user('bperson@example.com') + >>> print usermgr.get_user(u'bperson@example.com') None You can create email addresses that are linked to users by using a different interface. - >>> user_1 = usermgr.create_user('cperson@example.com', 'Claire Person') + >>> user_1 = usermgr.create_user(u'cperson@example.com', u'Claire Person') >>> sorted(address.address for address in user_1.addresses) - ['cperson@example.com'] - >>> flush() + [u'cperson@example.com'] >>> sorted(address.address for address in usermgr.addresses) - ['aperson@example.com', 'bperson@example.com', 'cperson@example.com'] + [u'aperson@example.com', u'bperson@example.com', u'cperson@example.com'] >>> sorted(address.real_name for address in usermgr.addresses) - ['Anne Person', 'Ben Person', 'Claire Person'] + [u'Anne Person', u'Ben Person', u'Claire Person'] And now you can find the associated user. - >>> print usermgr.get_user('aperson@example.com') + >>> print usermgr.get_user(u'aperson@example.com') None - >>> print usermgr.get_user('bperson@example.com') + >>> print usermgr.get_user(u'bperson@example.com') None - >>> usermgr.get_user('cperson@example.com') + >>> usermgr.get_user(u'cperson@example.com') <User "Claire Person" at ...> @@ -92,28 +88,26 @@ Deleting addresses You can remove an unlinked address from the user manager. >>> usermgr.delete_address(address_1) - >>> flush() >>> sorted(address.address for address in usermgr.addresses) - ['bperson@example.com', 'cperson@example.com'] + [u'bperson@example.com', u'cperson@example.com'] >>> sorted(address.real_name for address in usermgr.addresses) - ['Ben Person', 'Claire Person'] + [u'Ben Person', u'Claire Person'] Deleting a linked address does not delete the user, but it does unlink the address from the user. >>> sorted(address.address for address in user_1.addresses) - ['cperson@example.com'] - >>> user_1.controls('cperson@example.com') + [u'cperson@example.com'] + >>> user_1.controls(u'cperson@example.com') True >>> address_3 = list(user_1.addresses)[0] >>> usermgr.delete_address(address_3) - >>> flush() >>> sorted(address.address for address in user_1.addresses) [] - >>> user_1.controls('cperson@example.com') + >>> user_1.controls(u'cperson@example.com') False >>> sorted(address.address for address in usermgr.addresses) - ['bperson@example.com'] + [u'bperson@example.com'] Registration and validation @@ -122,8 +116,8 @@ Registration and validation Addresses have two dates, the date the address was registered on and the date the address was validated on. Neither date is set by default. - >>> address_4 = usermgr.create_address('dperson@example.com', 'Dan Person') - >>> flush() + >>> address_4 = usermgr.create_address( + ... u'dperson@example.com', u'Dan Person') >>> print address_4.registered_on None >>> print address_4.verified_on @@ -133,7 +127,6 @@ The registered date takes a Python datetime object. >>> from datetime import datetime >>> address_4.registered_on = datetime(2007, 5, 8, 22, 54, 1) - >>> flush() >>> print address_4.registered_on 2007-05-08 22:54:01 >>> print address_4.verified_on @@ -142,7 +135,6 @@ The registered date takes a Python datetime object. And of course, you can also set the validation date. >>> address_4.verified_on = datetime(2007, 5, 13, 22, 54, 1) - >>> flush() >>> print address_4.registered_on 2007-05-08 22:54:01 >>> print address_4.verified_on @@ -156,8 +148,8 @@ Addresses get subscribed to mailing lists, not users. When the address is subscribed, a role is specified. >>> address_5 = usermgr.create_address( - ... 'eperson@example.com', 'Elly Person') - >>> mlist = config.db.list_manager.create('_xtext@example.com') + ... u'eperson@example.com', u'Elly Person') + >>> mlist = config.db.list_manager.create(u'_xtext@example.com') >>> from Mailman.interfaces import MemberRole >>> address_5.subscribe(mlist, MemberRole.owner) <Member: Elly Person <eperson@example.com> on @@ -165,7 +157,6 @@ subscribed, a role is specified. >>> address_5.subscribe(mlist, MemberRole.member) <Member: Elly Person <eperson@example.com> on _xtext@example.com as MemberRole.member> - >>> flush() Now Elly is both an owner and a member of the mailing list. @@ -196,8 +187,7 @@ when sending the user a message, but it treats addresses that are different in case equivalently in all other situations. >>> address_6 = usermgr.create_address( - ... 'FPERSON@example.com', 'Frank Person') - >>> flush() + ... u'FPERSON@example.com', u'Frank Person') The str() of such an address prints the RFC 2822 preferred originator format with the original case-preserved address. The repr() contains all the gory @@ -213,22 +203,22 @@ Both the case-insensitive version of the address and the original case-preserved version are available on attributes of the IAddress object. >>> address_6.address - 'fperson@example.com' + u'fperson@example.com' >>> address_6.original_address - 'FPERSON@example.com' + u'FPERSON@example.com' Because addresses are case-insensitive for all other purposes, you cannot create an address that differs only in case. - >>> usermgr.create_address('fperson@example.com') + >>> usermgr.create_address(u'fperson@example.com') Traceback (most recent call last): ... ExistingAddressError: FPERSON@example.com - >>> usermgr.create_address('fperson@EXAMPLE.COM') + >>> usermgr.create_address(u'fperson@EXAMPLE.COM') Traceback (most recent call last): ... ExistingAddressError: FPERSON@example.com - >>> usermgr.create_address('FPERSON@example.com') + >>> usermgr.create_address(u'FPERSON@example.com') Traceback (most recent call last): ... ExistingAddressError: FPERSON@example.com @@ -236,7 +226,7 @@ create an address that differs only in case. You can get the address using either the lower cased version or case-preserved version. In fact, searching for an address is case insensitive. - >>> usermgr.get_address('fperson@example.com').address - 'fperson@example.com' - >>> usermgr.get_address('FPERSON@example.com').address - 'fperson@example.com' + >>> usermgr.get_address(u'fperson@example.com').address + u'fperson@example.com' + >>> usermgr.get_address(u'FPERSON@example.com').address + u'fperson@example.com' diff --git a/Mailman/docs/after-delivery.txt b/Mailman/docs/after-delivery.txt index 4304891e2..f5cbfe0e7 100644 --- a/Mailman/docs/after-delivery.txt +++ b/Mailman/docs/after-delivery.txt @@ -6,27 +6,22 @@ by the rest of the handlers in the incoming queue pipeline, a couple of bookkeeping pieces of information are updated. >>> import datetime - >>> from email import message_from_string - >>> from Mailman.Message import Message >>> from Mailman.Handlers.AfterDelivery 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') >>> post_time = datetime.datetime.now() - datetime.timedelta(minutes=10) >>> mlist.last_post_time = post_time >>> mlist.post_id = 10 - >>> flush() Processing a message with this handler updates the last_post_time and post_id attributes. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... ... Something interesting. - ... """, Message) + ... """) >>> process(mlist, msg, {}) - >>> flush() >>> mlist.last_post_time > post_time True >>> mlist.post_id diff --git a/Mailman/docs/antispam.txt b/Mailman/docs/antispam.txt index b6717c797..3ad5e982e 100644 --- a/Mailman/docs/antispam.txt +++ b/Mailman/docs/antispam.txt @@ -10,13 +10,9 @@ Still, Mailman does employ a small number of rather ham-handed anti-spam measures. >>> from Mailman.Handlers.SpamDetect 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') - >>> flush() + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') Short circuiting @@ -28,7 +24,7 @@ If a message is pre-approved, this handler does nothing. ... From: aperson@example.com ... ... An important message. - ... """, Message) + ... """) >>> msgdata = {'approved': True} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -49,6 +45,7 @@ regular expression. For example, if we wanted to block all message that come from 'aperson' regardless of the domain, we'd do something like the following in our mailman.cfg file: + >>> old_value = config.KNOWN_SPAMMERS[:] >>> config.KNOWN_SPAMMERS.append(('from', 'aperson')) Now if the same message is posted to the mailing list, and that message is not @@ -68,6 +65,9 @@ spam. >>> msgdata {} + # Restore global state + config.KNOWN_SPAMMERS = old_value + Header filter rules ------------------- diff --git a/Mailman/docs/approve.txt b/Mailman/docs/approve.txt index cd928e187..56afc1dd4 100644 --- a/Mailman/docs/approve.txt +++ b/Mailman/docs/approve.txt @@ -9,14 +9,13 @@ approval queue. This has several use cases: - An automated script can be programmed to send a message to an otherwise moderated list. - + In order to support this, a mailing list can be given a 'moderator password' which is shared among all the administrators. >>> from Mailman.Handlers.Approve import process - >>> from Mailman.database import flush >>> from Mailman.configuration import config - >>> mlist = config.db.list_manager.create('_xtest@example.com') + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') Short circuiting @@ -25,13 +24,11 @@ Short circuiting The message may have been approved by some other means, as evident in the message metadata. In this case, the handler returns immediately. - >>> from email import message_from_string - >>> from Mailman.Message import Message - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... ... An important message. - ... """, Message) + ... """) >>> msgdata = {'approved': True} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -51,9 +48,8 @@ gets sent through with no further posting moderation. The Approved header is not stripped in this handler module, but instead in the Cleanse module. This ensures that no moderator approval password in the headers will leak out. - >>> mlist.moderator_password = 'abcxyz' - >>> flush() - >>> msg['Approved'] = 'abcxyz' + >>> mlist.moderator_password = u'abcxyz' + >>> msg['Approved'] = u'abcxyz' >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -69,7 +65,7 @@ But if the wrong password is given, then the message is not marked as being approved. The header is still removed though. >>> del msg['Approved'] - >>> msg['Approved'] = '123456' + >>> msg['Approved'] = u'123456' >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -85,7 +81,7 @@ In the spirit of being liberal in what you accept, using an Approve header is completely synonymous. >>> del msg['Approved'] - >>> msg['Approve'] = 'abcxyz' + >>> msg['Approve'] = u'abcxyz' >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -98,7 +94,7 @@ completely synonymous. [('adminapproved', True), ('approved', True)] >>> del msg['Approve'] - >>> msg['Approve'] = '123456' + >>> msg['Approve'] = u'123456' >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -120,12 +116,12 @@ using a 'pseudo-header', which is really just the first non-whitespace line in the payload of the message of the message. If this pseudo-header looks like a matching Approve or Approved header, the message is similarly allowed to pass. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... ... Approved: abcxyz ... An important message. - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -139,12 +135,12 @@ matching Approve or Approved header, the message is similarly allowed to pass. >>> sorted(msgdata.items()) [('adminapproved', True), ('approved', True)] - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... ... Approve: abcxyz ... An important message. - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -161,12 +157,12 @@ matching Approve or Approved header, the message is similarly allowed to pass. As before, a mismatch in the pseudo-header does not approve the message, but the pseudo-header line is still removed. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... ... Approved: 123456 ... An important message. - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -180,12 +176,12 @@ the pseudo-header line is still removed. >>> msgdata {} - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... ... Approve: 123456 ... An important message. - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -207,7 +203,7 @@ Mailman searches for the pseudo-header as the first non-whitespace line in the first text/plain message part of the message. This allows the feature to be used with MIME documents. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... MIME-Version: 1.0 ... Content-Type: multipart/mixed; boundary="AAA" @@ -224,7 +220,7 @@ used with MIME documents. ... Approved: abcxyz ... An important message. ... --AAA-- - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -249,7 +245,7 @@ used with MIME documents. >>> sorted(msgdata.items()) [('adminapproved', True), ('approved', True)] - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... MIME-Version: 1.0 ... Content-Type: multipart/mixed; boundary="AAA" @@ -266,7 +262,7 @@ used with MIME documents. ... Approve: abcxyz ... An important message. ... --AAA-- - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -293,7 +289,7 @@ used with MIME documents. Here, the correct password is in the non-text/plain part, so it is ignored. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... MIME-Version: 1.0 ... Content-Type: multipart/mixed; boundary="AAA" @@ -310,7 +306,7 @@ Here, the correct password is in the non-text/plain part, so it is ignored. ... Approve: 123456 ... An important message. ... --AAA-- - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -334,7 +330,7 @@ Here, the correct password is in the non-text/plain part, so it is ignored. >>> msgdata {} - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... MIME-Version: 1.0 ... Content-Type: multipart/mixed; boundary="AAA" @@ -351,7 +347,7 @@ Here, the correct password is in the non-text/plain part, so it is ignored. ... Approve: 123456 ... An important message. ... --AAA-- - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -375,7 +371,7 @@ Here, the correct password is in the non-text/plain part, so it is ignored. >>> msgdata {} - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... MIME-Version: 1.0 ... Content-Type: multipart/mixed; boundary="AAA" @@ -392,7 +388,7 @@ Here, the correct password is in the non-text/plain part, so it is ignored. ... Approved: 123456 ... An important message. ... --AAA-- - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() diff --git a/Mailman/docs/archives.txt b/Mailman/docs/archives.txt index a02fdf802..cad602634 100644 --- a/Mailman/docs/archives.txt +++ b/Mailman/docs/archives.txt @@ -8,14 +8,10 @@ archivers to work in a separate process from the main Mailman delivery processes. >>> from Mailman.Handlers.ToArchive 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.preferred_language = 'en' - >>> flush() + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') + >>> mlist.preferred_language = u'en' >>> switchboard = Switchboard(config.ARCHQUEUE_DIR) A helper function. @@ -33,12 +29,11 @@ message should /not/ get archived. For example, no digests should ever get archived. >>> mlist.archive = True - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... Subject: A sample message ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, dict(isdigest=True)) >>> switchboard.files [] @@ -47,7 +42,6 @@ If the mailing list is not configured to archive, then even regular deliveries won't be archived. >>> mlist.archive = False - >>> flush() >>> process(mlist, msg, {}) >>> switchboard.files [] @@ -58,25 +52,24 @@ X-No-Archive: header can be used to indicate that the message should not be archived. Confusingly, this header's value is actually ignored. >>> mlist.archive = True - >>> flush() >>> msg = message_from_string("""\ ... Subject: A sample message ... X-No-Archive: YES ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, dict(isdigest=True)) >>> switchboard.files [] Even a 'no' value will stop the archiving of the message. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... Subject: A sample message ... X-No-Archive: No ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, dict(isdigest=True)) >>> switchboard.files [] @@ -84,24 +77,24 @@ Even a 'no' value will stop the archiving of the message. Another header that's been observed is the X-Archive: header. Here, the header's case folded value must be 'no' in order to prevent archiving. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... Subject: A sample message ... X-Archive: No ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, dict(isdigest=True)) >>> switchboard.files [] But if the value is 'yes', then the message will be archived. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... Subject: A sample message ... X-Archive: Yes ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> len(switchboard.files) 1 @@ -120,11 +113,11 @@ But if the value is 'yes', then the message will be archived. Without either archiving header, and all other things being the same, the message will get archived. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... Subject: A sample message ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> len(switchboard.files) 1 diff --git a/Mailman/docs/avoid-duplicates.txt b/Mailman/docs/avoid-duplicates.txt index b14bdb5bf..6a1b46f77 100644 --- a/Mailman/docs/avoid-duplicates.txt +++ b/Mailman/docs/avoid-duplicates.txt @@ -6,27 +6,22 @@ reduce the reception of duplicate messages. It does this by removing certain recipients from the list of recipients that earlier handler modules (e.g. CalcRecips) calculates. - >>> from email import message_from_string - >>> from Mailman.Message import Message >>> from Mailman.Handlers.AvoidDuplicates import process >>> from Mailman.configuration import config - >>> from Mailman.database import flush - >>> mlist = config.db.list_manager.create('_xtest@example.com') - >>> flush() + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') Create some members we're going to use. >>> from Mailman.interfaces import MemberRole >>> address_a = config.db.user_manager.create_address( - ... 'aperson@example.com') + ... u'aperson@example.com') >>> address_b = config.db.user_manager.create_address( - ... 'bperson@example.com') + ... u'bperson@example.com') >>> member_a = address_a.subscribe(mlist, MemberRole.member) >>> member_b = address_b.subscribe(mlist, MemberRole.member) - >>> flush() >>> # This is the message metadata dictionary as it would be produced by >>> # the CalcRecips handler. - >>> recips = dict(recips=['aperson@example.com', 'bperson@example.com']) + >>> recips = dict(recips=[u'aperson@example.com', u'bperson@example.com']) Short circuiting @@ -39,7 +34,7 @@ The module short-circuits if there are no recipients. ... Subject: A message of great import ... ... Something - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> msgdata @@ -62,16 +57,15 @@ one of the recipient headers (i.e. To, CC, Resent-To, or Resent-CC), then they will get a list copy. >>> member_a.preferences.receive_list_copy = False - >>> flush() >>> msg = message_from_string("""\ ... From: Claire Person <cperson@example.com> ... ... Something of great import. - ... """, Message) + ... """) >>> msgdata = recips.copy() >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) - ['aperson@example.com', 'bperson@example.com'] + [u'aperson@example.com', u'bperson@example.com'] >>> print msg.as_string() From: Claire Person <cperson@example.com> <BLANKLINE> @@ -85,11 +79,11 @@ If they're mentioned on the CC line, they won't get a list copy. ... CC: aperson@example.com ... ... Something of great import. - ... """, Message) + ... """) >>> msgdata = recips.copy() >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) - ['bperson@example.com'] + [u'bperson@example.com'] >>> print msg.as_string() From: Claire Person <cperson@example.com> CC: aperson@example.com @@ -105,11 +99,11 @@ But if they're mentioned on the CC line and have receive_list_copy set to True ... CC: bperson@example.com ... ... Something of great import. - ... """, Message) + ... """) >>> msgdata = recips.copy() >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) - ['aperson@example.com', 'bperson@example.com'] + [u'aperson@example.com', u'bperson@example.com'] >>> print msg.as_string() From: Claire Person <cperson@example.com> CC: bperson@example.com @@ -124,11 +118,11 @@ Other headers checked for recipients include the To... ... To: aperson@example.com ... ... Something of great import. - ... """, Message) + ... """) >>> msgdata = recips.copy() >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) - ['bperson@example.com'] + [u'bperson@example.com'] >>> print msg.as_string() From: Claire Person <cperson@example.com> To: aperson@example.com @@ -143,11 +137,11 @@ Other headers checked for recipients include the To... ... Resent-To: aperson@example.com ... ... Something of great import. - ... """, Message) + ... """) >>> msgdata = recips.copy() >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) - ['bperson@example.com'] + [u'bperson@example.com'] >>> print msg.as_string() From: Claire Person <cperson@example.com> Resent-To: aperson@example.com @@ -162,11 +156,11 @@ Other headers checked for recipients include the To... ... Resent-Cc: aperson@example.com ... ... Something of great import. - ... """, Message) + ... """) >>> msgdata = recips.copy() >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) - ['bperson@example.com'] + [u'bperson@example.com'] >>> print msg.as_string() From: Claire Person <cperson@example.com> Resent-Cc: aperson@example.com diff --git a/Mailman/docs/bounces.txt b/Mailman/docs/bounces.txt index 7195a082f..fa0d44ce9 100644 --- a/Mailman/docs/bounces.txt +++ b/Mailman/docs/bounces.txt @@ -14,22 +14,18 @@ essentially equivalent to rejecting the message with notification. Mailing lists can bounce a message with an optional error message. >>> 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.preferred_language = u'en' - >>> flush() Any message can be bounced. - >>> from email import message_from_string - >>> from Mailman.Message import Message - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... To: _xtest@example.com ... From: aperson@example.com ... Subject: Something important ... ... I sometimes say something important. - ... """, Message) + ... """) Bounce a message by passing in the original message, and an optional error message. The bounced message ends up in the virgin queue, awaiting sending diff --git a/Mailman/docs/calc-recips.txt b/Mailman/docs/calc-recips.txt index e2a01fa8a..c36841d1c 100644 --- a/Mailman/docs/calc-recips.txt +++ b/Mailman/docs/calc-recips.txt @@ -5,25 +5,20 @@ Every message that makes it through to the list membership gets sent to a set of recipient addresses. These addresses are calculated by one of the handler modules and depends on a host of factors. - >>> from email import message_from_string - >>> from Mailman.Message import Message >>> from Mailman.Handlers.CalcRecips import process >>> from Mailman.configuration import config - >>> from Mailman.database import flush - >>> mlist = config.db.list_manager.create('_xtest@example.com') - >>> flush() - + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') Recipients are calculate from the list members, so add a bunch of members to start out with. First, create a bunch of addresses... >>> usermgr = config.db.user_manager - >>> address_a = usermgr.create_address('aperson@example.com') - >>> address_b = usermgr.create_address('bperson@example.com') - >>> address_c = usermgr.create_address('cperson@example.com') - >>> address_d = usermgr.create_address('dperson@example.com') - >>> address_e = usermgr.create_address('eperson@example.com') - >>> address_f = usermgr.create_address('fperson@example.com') + >>> address_a = usermgr.create_address(u'aperson@example.com') + >>> address_b = usermgr.create_address(u'bperson@example.com') + >>> address_c = usermgr.create_address(u'cperson@example.com') + >>> address_d = usermgr.create_address(u'dperson@example.com') + >>> address_e = usermgr.create_address(u'eperson@example.com') + >>> address_f = usermgr.create_address(u'fperson@example.com') ...then subscribe these addresses to the mailing list as members... @@ -41,7 +36,6 @@ start out with. First, create a bunch of addresses... >>> member_d.preferences.delivery_mode = DeliveryMode.plaintext_digests >>> member_e.preferences.delivery_mode = DeliveryMode.mime_digests >>> member_f.preferences.delivery_mode = DeliveryMode.summary_digests - >>> flush() Short-circuiting @@ -55,12 +49,12 @@ but not all of the recipients. ... From: Xavier Person <xperson@example.com> ... ... Something of great import. - ... """, Message) - >>> recips = set(('qperson@example.com', 'zperson@example.com')) + ... """) + >>> recips = set((u'qperson@example.com', u'zperson@example.com')) >>> msgdata = dict(recips=recips) >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) - ['qperson@example.com', 'zperson@example.com'] + [u'qperson@example.com', u'zperson@example.com'] Regular delivery recipients @@ -72,21 +66,20 @@ soon as they are posted. In other words, these folks are not digest members. >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) - ['aperson@example.com', 'bperson@example.com', 'cperson@example.com'] + [u'aperson@example.com', u'bperson@example.com', u'cperson@example.com'] Members can elect not to receive a list copy of their own postings. >>> member_c.preferences.receive_own_postings = False - >>> flush() >>> msg = message_from_string("""\ ... From: Claire Person <cperson@example.com> ... ... Something of great import. - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) - ['aperson@example.com', 'bperson@example.com'] + [u'aperson@example.com', u'bperson@example.com'] Members can also elect not to receive a list copy of any message on which they are explicitly named as a recipient. However, see the AvoidDuplicates handler diff --git a/Mailman/docs/cleanse.txt b/Mailman/docs/cleanse.txt index ce0a69b23..2e40e6df5 100644 --- a/Mailman/docs/cleanse.txt +++ b/Mailman/docs/cleanse.txt @@ -5,13 +5,9 @@ All messages posted to a list get their headers cleansed. Some headers are related to additional permissions that can be granted to the message and other headers can be used to fish for membership. - >>> from email import message_from_string - >>> from Mailman.Message import Message >>> from Mailman.Handlers.Cleanse import process >>> from Mailman.configuration import config - >>> from Mailman.database import flush - >>> mlist = config.db.list_manager.create('_xtest@example.com') - >>> flush() + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') Headers such as Approved, Approve, and Urgent are used to grant special pemissions to individual messages. All may contain a password; the first two @@ -20,7 +16,7 @@ for approval. The latter header is used to send a regular message to all members, regardless of whether they get digests or not. Because all three headers contain passwords, they must be removed from any posted message. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... Approved: foobar ... Approve: barfoo @@ -28,7 +24,7 @@ headers contain passwords, they must be removed from any posted message. ... Subject: A message of great import ... ... Blah blah blah - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.com @@ -43,7 +39,7 @@ headers supported by some mail readers. For example, X-PMRC is supported by Pegasus mail. I don't remember what program uses X-Confirm-Reading-To though (Some Microsoft product perhaps?). - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: bperson@example.com ... Reply-To: bperson@example.org ... Sender: asystem@example.net @@ -54,7 +50,7 @@ Pegasus mail. I don't remember what program uses X-Confirm-Reading-To though ... Subject: a message to you ... ... How are you doing? - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> print msg.as_string() From: bperson@example.com @@ -80,8 +76,7 @@ Hotmail apparently sets X-Originating-Email. >>> mlist.anonymous_list = True >>> mlist.description = u'A Test Mailing List' >>> mlist.preferred_language = u'en' - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: bperson@example.com ... Reply-To: bperson@example.org ... Sender: asystem@example.net @@ -89,7 +84,7 @@ Hotmail apparently sets X-Originating-Email. ... Subject: a message to you ... ... How are you doing? - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> print msg.as_string() Subject: a message to you diff --git a/Mailman/docs/cook-headers.txt b/Mailman/docs/cook-headers.txt index 62c80b186..1b7705d1c 100644 --- a/Mailman/docs/cook-headers.txt +++ b/Mailman/docs/cook-headers.txt @@ -7,19 +7,15 @@ 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'' >>> mlist.include_list_post_header = False >>> mlist.archive = True >>> # XXX This will almost certainly change once we've worked out the web >>> # space layout for mailing lists now. - >>> mlist.web_page_url = 'http://lists.example.com/' - >>> flush() + >>> mlist.web_page_url = u'http://lists.example.com/' Saving the original sender @@ -28,23 +24,23 @@ Saving the original sender Because the original sender headers may get deleted or changed, CookHeaders will place the sender in the message metadata for safe keeping. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... ... A message of great import. - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> msgdata['original_sender'] - 'aperson@example.com' + u'aperson@example.com' But if there was no original sender, then the empty string will be saved. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... Subject: No original sender ... ... A message of great import. - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> msgdata['original_sender'] @@ -58,27 +54,27 @@ The X-BeenThere header is what Mailman uses to recognize messages that have already been processed by this mailing list. It's one small measure against mail loops. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> msg['x-beenthere'] - '_xtest@example.com' + u'_xtest@example.com' Mailman appends X-BeenThere headers, so if there already is one in the original message, the posted message will contain two such headers. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... X-BeenThere: another@example.com ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> sorted(msg.get_all('x-beenthere')) - ['_xtest@example.com', 'another@example.com'] + [u'_xtest@example.com', u'another@example.com'] Mailman version header @@ -86,11 +82,11 @@ Mailman version header Mailman will also insert an X-Mailman-Version header... - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> from Mailman.Version import VERSION >>> msg['x-mailman-version'] == VERSION @@ -98,16 +94,16 @@ Mailman will also insert an X-Mailman-Version header... ...but only if one doesn't already exist. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... X-Mailman-Version: 3000 ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> from Mailman.Version import VERSION >>> msg['x-mailman-version'] - '3000' + u'3000' Precedence header @@ -117,29 +113,29 @@ Mailman will insert a Precedence header, which is a de-facto standard for telling automatic reply software (e.g. vacation(1)) not to respond to this message. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> from Mailman.Version import VERSION >>> msg['precedence'] - 'list' + u'list' But Mailman will only add that header if the original message doesn't already have one of them. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... Precedence: junk ... ... A message of great import. - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> from Mailman.Version import VERSION >>> msg['precedence'] - 'junk' + u'junk' RFC 2919 and 2369 headers @@ -164,10 +160,10 @@ These RFCs define headers for mailing list actions. A mailing list should generally add these headers, but not for messages that aren't crafted for a specific list (e.g. password reminders in Mailman 2.x). - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, dict(_nolist=True)) >>> list_headers(msg) ---start--- @@ -177,11 +173,10 @@ Some people don't like these headers because their mail readers aren't good about hiding them. A list owner can turn these headers off. >>> mlist.include_rfc2369_headers = False - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> list_headers(msg) ---start--- @@ -191,12 +186,11 @@ But normally, a list will include these headers. >>> mlist.include_rfc2369_headers = True >>> mlist.include_list_post_header = True - >>> mlist.preferred_language = 'en' - >>> flush() - >>> msg = message_from_string("""\ + >>> mlist.preferred_language = u'en' + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> list_headers(msg) ---start--- @@ -213,12 +207,11 @@ But normally, a list will include these headers. If the mailing list has a description, then it is included in the List-Id header. - >>> mlist.description = 'My test mailing list' - >>> flush() - >>> msg = message_from_string("""\ + >>> mlist.description = u'My test mailing list' + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> list_headers(msg) ---start--- @@ -234,10 +227,10 @@ header. Administrative messages crafted by Mailman will have a reduced set of headers. - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, dict(reduced_list_headers=True)) >>> list_headers(msg) ---start--- @@ -254,11 +247,10 @@ With the normal set of List-* headers, it's still possible to suppress the List-Post header, which is reasonable for an announce only mailing list. >>> mlist.include_list_post_header = False - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> list_headers(msg) ---start--- @@ -276,11 +268,10 @@ List-Archive header either. >>> mlist.include_list_post_header = True >>> mlist.archive = False - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> list_headers(msg) ---start--- @@ -305,11 +296,10 @@ the recipient headers so that users will be able to reply back to the list. >>> from Mailman.interfaces import Personalization, ReplyToMunging >>> mlist.personalize = Personalization.full >>> mlist.reply_goes_to_list = ReplyToMunging.no_munging - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.com diff --git a/Mailman/docs/decorate.txt b/Mailman/docs/decorate.txt index bf0adddd7..6f05c6982 100644 --- a/Mailman/docs/decorate.txt +++ b/Mailman/docs/decorate.txt @@ -5,12 +5,9 @@ Message decoration is the process of adding headers and footers to the original message. A handler module takes care of this based on the settings of the mailing list and the type of message being processed. - >>> from email import message_from_string >>> from Mailman.Handlers.Decorate import process >>> from Mailman.configuration import config - >>> from Mailman.database import flush - >>> mlist = config.db.list_manager.create('_xtest@example.com') - >>> flush() + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') >>> msg_text = """\ ... From: aperson@example.org ... @@ -49,10 +46,9 @@ placeholder variables, the message's payload will be prepended by the verbatim header, and appended with the verbatim footer. >>> msg = message_from_string(msg_text) - >>> mlist.msg_header = 'header\n' - >>> mlist.msg_footer = 'footer' - >>> mlist.preferred_language = 'en' - >>> flush() + >>> mlist.msg_header = u'header\n' + >>> mlist.msg_footer = u'footer' + >>> mlist.preferred_language = u'en' >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.org @@ -68,10 +64,9 @@ data. An example of such information is the mailing list's "real name" (a short descriptive name for the mailing list). >>> msg = message_from_string(msg_text) - >>> mlist.msg_header = '$real_name header\n' - >>> mlist.msg_footer = '$real_name footer' - >>> mlist.real_name = 'XTest' - >>> flush() + >>> mlist.msg_header = u'$real_name header\n' + >>> mlist.msg_footer = u'$real_name footer' + >>> mlist.real_name = u'XTest' >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.org @@ -84,9 +79,8 @@ You can't just pick any interpolation variable though; if you do, the variable will remain in the header or footer unchanged. >>> msg = message_from_string(msg_text) - >>> mlist.msg_header = '$dummy header\n' - >>> mlist.msg_footer = '$dummy footer' - >>> flush() + >>> mlist.msg_header = u'$dummy header\n' + >>> mlist.msg_footer = u'$dummy footer' >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.org @@ -109,10 +103,9 @@ When Mailman sees text/plain messages with such RFC 3676 parameters, it preserves these parameters when it concatenates headers and footers to the message payload. - >>> mlist.msg_header = 'header' - >>> mlist.msg_footer = 'footer' - >>> mlist.preferred_language = 'en' - >>> mlist.flush() + >>> mlist.msg_header = u'header' + >>> mlist.msg_footer = u'footer' + >>> mlist.preferred_language = u'en' >>> msg = message_from_string("""\ ... From: aperson@example.org ... Content-Type: text/plain; format=flowed; delsp=no @@ -139,11 +132,10 @@ set, Mailman will still try to concatenate the header and footer, but it will convert the text to utf-8 and base-64 encode the message payload. # 'ja' = Japanese; charset = 'euc-jp' - >>> mlist.preferred_language = 'ja' - >>> mlist.msg_header = '$description header' - >>> mlist.msg_footer = '$description footer' + >>> mlist.preferred_language = u'ja' + >>> mlist.msg_header = u'$description header' + >>> mlist.msg_footer = u'$description footer' >>> mlist.description = u'\u65e5\u672c\u8a9e' - >>> flush() >>> from email.message import Message >>> msg = Message() @@ -167,10 +159,9 @@ Sometimes the message even has an unknown character set. In this case, Mailman has no choice but to decorate the original message with MIME attachments. - >>> mlist.preferred_language = 'en' - >>> mlist.msg_header = 'header' - >>> mlist.msg_footer = 'footer' - >>> flush() + >>> mlist.preferred_language = u'en' + >>> mlist.msg_header = u'header' + >>> mlist.msg_footer = u'footer' >>> msg = message_from_string("""\ ... From: aperson@example.org ... Content-Type: text/plain; charset=unknown @@ -219,10 +210,9 @@ When the outerpart is multipart/mixed, the header and footer can have a Content-Disposition of 'inline' so that MUAs can display these headers as if they were simply concatenated. - >>> mlist.preferred_language = 'en' - >>> mlist.msg_header = 'header' - >>> mlist.msg_footer = 'footer' - >>> flush() + >>> mlist.preferred_language = u'en' + >>> mlist.msg_header = u'header' + >>> mlist.msg_footer = u'footer' >>> part_1 = message_from_string("""\ ... From: aperson@example.org ... diff --git a/Mailman/docs/digests.txt b/Mailman/docs/digests.txt index 4d787221d..aaef4c18b 100644 --- a/Mailman/docs/digests.txt +++ b/Mailman/docs/digests.txt @@ -7,18 +7,14 @@ digests, although only two are currently supported: MIME digests and RFC 1153 (a.k.a. plain text) digests. >>> from Mailman.Handlers.ToDigest 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.preferred_language = 'en' - >>> mlist.web_page_url = 'http://www.example.com/' - >>> mlist.real_name = 'XTest' - >>> mlist.subject_prefix = '[_XTest] ' + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') + >>> mlist.preferred_language = u'en' + >>> mlist.web_page_url = u'http://www.example.com/' + >>> mlist.real_name = u'XTest' + >>> mlist.subject_prefix = u'[_XTest] ' >>> mlist.one_last_digest = set() - >>> flush() >>> switchboard = Switchboard(config.VIRGINQUEUE_DIR) This is a helper function used to iterate through all the accumulated digest @@ -45,7 +41,7 @@ update the tests when we switch to a different mailbox format. ... ... Here is message $i ... """).substitute(i=i) - ... yield message_from_string(text, Message) + ... yield message_from_string(text) Short circuiting @@ -59,7 +55,6 @@ storing of posted messages to the mailbox. For example, the mailing list may not allow digests... >>> mlist.digestable = False - >>> flush() >>> msg = makemsg().next() >>> process(mlist, msg, {}) >>> sum(1 for mboxmsg in digest_mbox()) @@ -70,7 +65,6 @@ not allow digests... ...or they may allow digests but the message is already a digest. >>> mlist.digestable = True - >>> flush() >>> process(mlist, msg, dict(isdigest=True)) >>> sum(1 for mboxmsg in digest_mbox()) 0 @@ -87,7 +81,6 @@ triggering the sending of the digest. If none of those criteria are met, then the message will just sit in the mailbox for a while. >>> mlist.digest_size_threshold = 10000 - >>> flush() >>> process(mlist, msg, {}) >>> switchboard.files [] @@ -102,7 +95,6 @@ digest and an RFC 1153 plain text digest. The size threshold is in KB. >>> mlist.digest_size_threshold = 1 >>> mlist.volume = 2 >>> mlist.next_digest_number = 10 - >>> flush() >>> size = 0 >>> for msg in makemsg(): ... process(mlist, msg, {}) @@ -274,7 +266,7 @@ digest and an RFC 1153 plain text digest. The size threshold is in KB. >>> sorted(mimedata.items()) [('_parsemsg', False), ('isdigest', True), - ('listname', '_xtest@example.com'), + ('listname', u'_xtest@example.com'), ('received_time', ...), ('recips', set([])), ('version', 3)] >>> print rfc1153msg.as_string() @@ -409,7 +401,7 @@ digest and an RFC 1153 plain text digest. The size threshold is in KB. >>> sorted(rfc1153data.items()) [('_parsemsg', False), ('isdigest', True), - ('listname', '_xtest@example.com'), + ('listname', u'_xtest@example.com'), ('received_time', ...), ('recips', set([])), ('version', 3)] @@ -425,9 +417,8 @@ 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' - >>> mlist.preferred_language = 'fr' - >>> flush() + >>> config.DEFAULT_SERVER_LANGUAGE = u'fr' + >>> mlist.preferred_language = u'fr' >>> msg = message_from_string("""\ ... From: aperson@example.org ... To: _xtest@example.com @@ -437,12 +428,11 @@ English template will be found and the masthead won't be translated. ... Content-Transfer-Encoding: 7bit ... ... \x1b$B0lHV\x1b(B - ... """, Message) + ... """) Set the digest threshold to zero so that the digests will be sent immediately. >>> mlist.digest_size_threshold = 0 - >>> flush() >>> process(mlist, msg, {}) >>> sum(1 for mboxmsg in digest_mbox()) 0 @@ -522,7 +512,7 @@ Set the digest threshold to zero so that the digests will be sent immediately. >>> sorted(mimedata.items()) [('_parsemsg', False), ('isdigest', True), - ('listname', '_xtest@example.com'), + ('listname', u'_xtest@example.com'), ('received_time', ...), ('recips', set([])), ('version', 3)] >>> print rfc1153msg.as_string() @@ -541,7 +531,7 @@ Set the digest threshold to zero so that the digests will be sent immediately. >>> sorted(rfc1153data.items()) [('_parsemsg', False), ('isdigest', True), - ('listname', '_xtest@example.com'), + ('listname', u'_xtest@example.com'), ('received_time', ...), ('recips', set([])), ('version', 3)] @@ -549,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/file-recips.txt b/Mailman/docs/file-recips.txt index eab202eb3..c7528a1d1 100644 --- a/Mailman/docs/file-recips.txt +++ b/Mailman/docs/file-recips.txt @@ -5,13 +5,9 @@ Mailman can calculate the recipients for a message from a Sendmail-style include file. This file must be called members.txt and it must live in the list's data directory. - >>> from email import message_from_string - >>> from Mailman.Message import Message >>> from Mailman.Handlers.FileRecips import process >>> from Mailman.configuration import config - >>> from Mailman.database import flush - >>> mlist = config.db.list_manager.create('_xtest@example.com') - >>> flush() + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') Short circuiting @@ -24,7 +20,7 @@ returns. ... From: aperson@example.com ... ... A message. - ... """, Message) + ... """) >>> msgdata = {'recips': 7} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -49,7 +45,7 @@ empty. Traceback (most recent call last): ... IOError: [Errno ...] - No such file or directory: '.../_xtest@example.com/members.txt' + No such file or directory: u'.../_xtest@example.com/members.txt' >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) @@ -85,16 +81,15 @@ in the recipients list. >>> from Mailman.interfaces import MemberRole >>> address_1 = config.db.user_manager.create_address( - ... 'cperson@example.com') + ... u'cperson@example.com') >>> address_1.subscribe(mlist, MemberRole.member) <Member: cperson@example.com on _xtest@example.com as MemberRole.member> - >>> flush() >>> msg = message_from_string("""\ ... From: cperson@example.com ... ... A message. - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> sorted(msgdata['recips']) diff --git a/Mailman/docs/filtering.txt b/Mailman/docs/filtering.txt index 5477dd404..67bef2f8e 100644 --- a/Mailman/docs/filtering.txt +++ b/Mailman/docs/filtering.txt @@ -7,13 +7,9 @@ message. It does this with the MimeDel handler module, although other handlers can potentially do other kinds of finer level content filtering. >>> from Mailman.Handlers.MimeDel import process - >>> 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' Several mailing list options control content filtering. First, the feature must be enabled, then there are two options that control which MIME types get @@ -25,7 +21,6 @@ for these variables, then we'll explain them in more detail below. >>> mlist.filter_mime_types = [] >>> mlist.pass_mime_types = [] >>> mlist.convert_html_to_plaintext = False - >>> flush() Filtering the outer content type @@ -38,14 +33,13 @@ content type matches the filter, the entire message will be discarded. >>> mlist.filter_mime_types = ['image/jpeg'] >>> # XXX Change this to an enum >>> mlist.filter_action = 0 # Discard - >>> flush() >>> msg = message_from_string("""\ ... From: aperson@example.com ... Content-Type: image/jpeg ... MIME-Version: 1.0 ... ... xxxxx - ... """, Message) + ... """) >>> process(mlist, msg, {}) Traceback (most recent call last): ... @@ -55,7 +49,6 @@ However, if we turn off content filtering altogether, then the handler short-circuits. >>> mlist.filter_content = False - >>> flush() >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -71,7 +64,6 @@ Similarly, no content filtering is performed on digest messages, which are crafted internally by Mailman. >>> mlist.filter_content = True - >>> flush() >>> msgdata = {'isdigest': True} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -107,7 +99,7 @@ just that subpart will be stripped. ... ... yyy ... --BOUNDARY-- - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.com @@ -141,7 +133,6 @@ multipart/alternative so that the outer multipart/mixed has just a single gif subpart. >>> mlist.collapse_alternatives = True - >>> flush() >>> msg = message_from_string("""\ ... From: aperson@example.com ... Content-Type: multipart/mixed; boundary=BOUNDARY @@ -165,7 +156,7 @@ subpart. ... --BOUND2-- ... ... --BOUNDARY-- - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.com @@ -187,7 +178,6 @@ part's content type. In other words, the left over inner part is promoted to being the outer part. >>> mlist.filter_mime_types.append('text/html') - >>> flush() >>> msg = message_from_string("""\ ... From: aperson@example.com ... Content-Type: multipart/alternative; boundary=AAA @@ -201,7 +191,7 @@ being the outer part. ... ... This is plain text ... --AAA-- - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.com @@ -213,7 +203,6 @@ being the outer part. Clean up. >>> ignore = mlist.filter_mime_types.pop() - >>> flush() Conversion to plain text @@ -234,7 +223,6 @@ conversion by defining a conversion command. A list administrator still needs to enable such conversion for their list though. >>> mlist.convert_html_to_plaintext = True - >>> flush() By default, Mailman sends the message through lynx, but since this program is not guaranteed to exist, we'll craft a simple, but stupid script to simulate @@ -261,7 +249,7 @@ name of the file containing the message payload to filter. ... ... <html><head></head> ... <body></body></html> - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.com @@ -320,7 +308,7 @@ the entire inner multipart/mixed is discarded. ... ... aaa ... --AAA-- - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.com diff --git a/Mailman/docs/hold.txt b/Mailman/docs/hold.txt index f8934cf6f..56a10206f 100644 --- a/Mailman/docs/hold.txt +++ b/Mailman/docs/hold.txt @@ -10,14 +10,12 @@ are held when they meet any of a number of criteria. >>> from Mailman.Handlers.Hold import process >>> from Mailman.queue import Switchboard >>> from Mailman.configuration import config - >>> from Mailman.database import flush - >>> mlist = config.db.list_manager.create('_xtest@example.com') - >>> mlist.preferred_language = 'en' - >>> mlist.real_name = '_XTest' + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') + >>> mlist.preferred_language = u'en' + >>> mlist.real_name = u'_XTest' >>> # XXX This will almost certainly change once we've worked out the web >>> # space layout for mailing lists now. - >>> mlist.web_page_url = 'http://lists.example.com/' - >>> flush() + >>> mlist.web_page_url = u'http://lists.example.com/' Here's a helper function used when we don't care about what's in the virgin queue or in the pending database. @@ -43,13 +41,11 @@ Short circuiting If the message metadata indicates that the message is pre-approved, then the handler returns immediately. - >>> from email import message_from_string - >>> from Mailman.Message import Message >>> msg = message_from_string("""\ ... From: aperson@example.com ... ... An important message. - ... """, Message) + ... """) >>> msgdata = {'approved': True} >>> process(mlist, msg, msgdata) >>> print msg.as_string() @@ -70,12 +66,11 @@ like an email command. This is to prevent people sending 'help' or of administrivia for the list. >>> mlist.administrivia = True - >>> flush() >>> msg = message_from_string("""\ ... From: aperson@example.com ... Subject: unsubscribe ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) Traceback (most recent call last): ... @@ -90,7 +85,6 @@ Mailman will hold messages that have more than a specified number of explicit recipients. >>> mlist.max_num_recipients = 5 - >>> flush() >>> msg = message_from_string("""\ ... From: aperson@example.com ... To: _xtest@example.com, bperson@example.com @@ -99,7 +93,7 @@ recipients. ... To: Elly Q. Person <eperson@example.com> ... ... Hey folks! - ... """, Message) + ... """) >>> process(mlist, msg, {}) Traceback (most recent call last): ... @@ -114,13 +108,12 @@ Mailman will hold messages that have implicit destination, meaning that the mailing list's posting address isn't included in the explicit recipients. >>> mlist.require_explicit_destination = True - >>> mlist.acceptable_aliases = '' - >>> flush() + >>> mlist.acceptable_aliases = u'' >>> msg = message_from_string("""\ ... From: aperson@example.org ... Subject: An implicit message ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) Traceback (most recent call last): ... @@ -152,14 +145,13 @@ Suspicious headers are a way for Mailman to hold messages that match a particular regular expression. This mostly historical feature is fairly confusing to users, and the list attribute that controls this is misnamed. - >>> mlist.bounce_matching_headers = 'From: .*person@(blah.)?example.com' - >>> flush() + >>> mlist.bounce_matching_headers = u'From: .*person@(blah.)?example.com' >>> msg = message_from_string("""\ ... From: aperson@example.com ... To: _xtest@example.com ... Subject: An implicit message ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) Traceback (most recent call last): ... @@ -174,7 +166,7 @@ fine. This one comes from a .org address. ... To: _xtest@example.com ... Subject: An implicit message ... - ... """, Message) + ... """) >>> msgdata = {} >>> process(mlist, msg, msgdata) >>> print msgdata @@ -183,7 +175,6 @@ fine. This one comes from a .org address. Just a bit of clean up. >>> mlist.bounce_matching_headers = None - >>> flush() Message size @@ -194,14 +185,13 @@ is used to prevent huge attachments from getting posted to the list. This value is calculated in terms of KB (1024 bytes). >>> mlist.max_message_size = 1 - >>> flush() >>> one_line = 'x' * 79 >>> big_body = '\n'.join([one_line] * 15) >>> msg = message_from_string("""\ ... From: aperson@example.com ... To: _xtest@example.com ... - ... """ + big_body, Message) + ... """ + big_body) >>> process(mlist, msg, {}) Traceback (most recent call last): ... @@ -218,16 +208,14 @@ can show this by first holding a message. >>> mlist.respond_to_post_requests = True >>> mlist.admin_immed_notify = True - >>> flush() >>> msg = message_from_string("""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) Traceback (most recent call last): ... ImplicitDestination - >>> flush() There should be two messages in the virgin queue, one to the list owner and one to the original author. @@ -300,9 +288,9 @@ one to the original author. of the body of the reply. --... >>> sorted(qdata.items()) - [('_parsemsg', False), ('listname', '_xtest@example.com'), + [('_parsemsg', False), ('listname', u'_xtest@example.com'), ('nodecorate', True), ('received_time', ...), - ('recips', ['_xtest-owner@example.com']), + ('recips', [u'_xtest-owner@example.com']), ('reduced_list_headers', True), ('tomoderators', 1), ('version', 3)] >>> qmsg, qdata = qfiles['aperson@example.com'] @@ -335,9 +323,9 @@ one to the original author. <BLANKLINE> <BLANKLINE> >>> sorted(qdata.items()) - [('_parsemsg', False), ('listname', '_xtest@example.com'), + [('_parsemsg', False), ('listname', u'_xtest@example.com'), ('nodecorate', True), ('received_time', ...), - ('recips', ['aperson@example.com']), + ('recips', [u'aperson@example.com']), ('reduced_list_headers', True), ('version', 3)] In addition, the pending database is holding the original messages, waiting @@ -356,7 +344,7 @@ first item is a type code and the second item is a message id. ... break >>> data = config.db.pendings.confirm(cookie) >>> sorted(data.items()) - [('id', '...'), ('type', 'held message')] + [(u'id', ...), (u'type', u'held message')] The message itself is held in the message store. diff --git a/Mailman/docs/lifecycle.txt b/Mailman/docs/lifecycle.txt index 4a6354381..ba9c83ef7 100644 --- a/Mailman/docs/lifecycle.txt +++ b/Mailman/docs/lifecycle.txt @@ -63,11 +63,9 @@ Start by registering a test style. Using the higher level interface for creating a list, applies all matching list styles. - >>> mlist_1 = create_list('test_1@example.com') - >>> from Mailman.database import flush - >>> flush() + >>> mlist_1 = create_list(u'test_1@example.com') >>> mlist_1.fqdn_listname - 'test_1@example.com' + u'test_1@example.com' >>> mlist_1.msg_footer u'test footer' @@ -79,17 +77,16 @@ You can also specify a list of owner email addresses. If these addresses are not yet known, they will be registered, and new users will be linked to them. However the addresses are not verified. - >>> owners = ['aperson@example.com', 'bperson@example.com', - ... 'cperson@example.com', 'dperson@example.com'] - >>> mlist_2 = create_list('test_2@example.com', owners) - >>> flush() + >>> owners = [u'aperson@example.com', u'bperson@example.com', + ... u'cperson@example.com', u'dperson@example.com'] + >>> mlist_2 = create_list(u'test_2@example.com', owners) >>> mlist_2.fqdn_listname - 'test_2@example.com' + u'test_2@example.com' >>> mlist_2.msg_footer u'test footer' >>> sorted(addr.address for addr in mlist_2.owners.addresses) - ['aperson@example.com', 'bperson@example.com', - 'cperson@example.com', 'dperson@example.com'] + [u'aperson@example.com', u'bperson@example.com', + u'cperson@example.com', u'dperson@example.com'] None of the owner addresses are verified. @@ -107,20 +104,18 @@ the system, they won't be created again. >>> from Mailman.configuration import config >>> usermgr = config.db.user_manager - >>> user_a = usermgr.get_user('aperson@example.com') - >>> user_b = usermgr.get_user('bperson@example.com') - >>> user_c = usermgr.get_user('cperson@example.com') - >>> user_d = usermgr.get_user('dperson@example.com') - >>> user_a.real_name = 'Anne Person' - >>> user_b.real_name = 'Bart Person' - >>> user_c.real_name = 'Caty Person' - >>> user_d.real_name = 'Dirk Person' - >>> flush() + >>> user_a = usermgr.get_user(u'aperson@example.com') + >>> user_b = usermgr.get_user(u'bperson@example.com') + >>> user_c = usermgr.get_user(u'cperson@example.com') + >>> user_d = usermgr.get_user(u'dperson@example.com') + >>> user_a.real_name = u'Anne Person' + >>> user_b.real_name = u'Bart Person' + >>> user_c.real_name = u'Caty Person' + >>> user_d.real_name = u'Dirk Person' - >>> mlist_3 = create_list('test_3@example.com', owners) - >>> flush() + >>> mlist_3 = create_list(u'test_3@example.com', owners) >>> sorted(user.real_name for user in mlist_3.owners.users) - ['Anne Person', 'Bart Person', 'Caty Person', 'Dirk Person'] + [u'Anne Person', u'Bart Person', u'Caty Person', u'Dirk Person'] Removing a list @@ -132,14 +127,12 @@ artifacts. >>> from Mailman import Utils >>> from Mailman.app.lifecycle import remove_list >>> remove_list(mlist_2.fqdn_listname, mlist_2, True) - >>> flush() - >>> Utils.list_exists('test_2@example.com') + >>> Utils.list_exists(u'test_2@example.com') False We should now be able to completely recreate the mailing list. - >>> mlist_2a = create_list('test_2@example.com', owners) - >>> flush() + >>> mlist_2a = create_list(u'test_2@example.com', owners) >>> sorted(addr.address for addr in mlist_2a.owners.addresses) - ['aperson@example.com', 'bperson@example.com', - 'cperson@example.com', 'dperson@example.com'] + [u'aperson@example.com', u'bperson@example.com', + u'cperson@example.com', u'dperson@example.com'] diff --git a/Mailman/docs/listmanager.txt b/Mailman/docs/listmanager.txt index 2c908b169..832100aca 100644 --- a/Mailman/docs/listmanager.txt +++ b/Mailman/docs/listmanager.txt @@ -6,7 +6,6 @@ objects. The Mailman system instantiates an IListManager for you based on the configuration variable MANAGERS_INIT_FUNCTION. The instance is accessible on the global config object. - >>> from Mailman.database import flush >>> from Mailman.configuration import config >>> from Mailman.interfaces import IListManager >>> listmgr = config.db.list_manager @@ -20,8 +19,7 @@ Creating a mailing list Creating the list returns the newly created IMailList object. >>> from Mailman.interfaces import IMailingList - >>> mlist = listmgr.create('_xtest@example.com') - >>> flush() + >>> mlist = listmgr.create(u'_xtest@example.com') >>> IMailingList.providedBy(mlist) True @@ -30,16 +28,16 @@ qualified listname. This latter is what uniquely distinguishes the mailing list to the system. >>> mlist.list_name - '_xtest' + u'_xtest' >>> mlist.host_name - 'example.com' + u'example.com' >>> mlist.fqdn_listname - '_xtest@example.com' + u'_xtest@example.com' If you try to create a mailing list with the same name as an existing list, you will get an exception. - >>> mlist_dup = listmgr.create('_xtest@example.com') + >>> mlist_dup = listmgr.create(u'_xtest@example.com') Traceback (most recent call last): ... MMListAlreadyExistsError: _xtest@example.com @@ -51,16 +49,14 @@ Deleting a mailing list Use the list manager to delete a mailing list. >>> listmgr.delete(mlist) - >>> flush() >>> sorted(listmgr.names) [] After deleting the list, you can create it again. - >>> mlist = listmgr.create('_xtest@example.com') - >>> flush() + >>> mlist = listmgr.create(u'_xtest@example.com') >>> mlist.fqdn_listname - '_xtest@example.com' + u'_xtest@example.com' Retrieving a mailing list @@ -69,13 +65,13 @@ Retrieving a mailing list When a mailing list exists, you can ask the list manager for it and you will always get the same object back. - >>> mlist_2 = listmgr.get('_xtest@example.com') + >>> mlist_2 = listmgr.get(u'_xtest@example.com') >>> mlist_2 is mlist True If you try to get a list that doesn't existing yet, you get None. - >>> print listmgr.get('_xtest_2@example.com') + >>> print listmgr.get(u'_xtest_2@example.com') None @@ -85,18 +81,9 @@ Iterating over all mailing lists Once you've created a bunch of mailing lists, you can use the list manager to iterate over either the list objects, or the list names. - >>> mlist_3 = listmgr.create('_xtest_3@example.com') - >>> mlist_4 = listmgr.create('_xtest_4@example.com') - >>> flush() + >>> mlist_3 = listmgr.create(u'_xtest_3@example.com') + >>> mlist_4 = listmgr.create(u'_xtest_4@example.com') >>> sorted(listmgr.names) - ['_xtest@example.com', '_xtest_3@example.com', '_xtest_4@example.com'] + [u'_xtest@example.com', u'_xtest_3@example.com', u'_xtest_4@example.com'] >>> sorted(m.fqdn_listname for m in listmgr.mailing_lists) - ['_xtest@example.com', '_xtest_3@example.com', '_xtest_4@example.com'] - - -Cleaning up ------------ - - >>> for mlist in listmgr.mailing_lists: - ... listmgr.delete(mlist) - >>> flush() + [u'_xtest@example.com', u'_xtest_3@example.com', u'_xtest_4@example.com'] diff --git a/Mailman/docs/membership.txt b/Mailman/docs/membership.txt index 414012bc3..21084d194 100644 --- a/Mailman/docs/membership.txt +++ b/Mailman/docs/membership.txt @@ -15,9 +15,7 @@ store mailing list data in a different database than user data. When we create a mailing list, it starts out with no members... >>> from Mailman.configuration import config - >>> from Mailman.database import flush - >>> mlist = config.db.list_manager.create('_xtest@example.com') - >>> flush() + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') >>> mlist <mailing list "_xtest@example.com" at ...> >>> sorted(member.address.address for member in mlist.members.members) @@ -66,12 +64,11 @@ assigning roles to users. First we have to create the user, because there are no users in the user database yet. >>> usermgr = config.db.user_manager - >>> user_1 = usermgr.create_user('aperson@example.com', 'Anne Person') - >>> flush() + >>> user_1 = usermgr.create_user(u'aperson@example.com', u'Anne Person') >>> user_1.real_name - 'Anne Person' + u'Anne Person' >>> sorted(address.address for address in user_1.addresses) - ['aperson@example.com'] + [u'aperson@example.com'] We can add Anne as an owner of the mailing list, by creating a member role for her. @@ -79,23 +76,22 @@ her. >>> from Mailman.interfaces import MemberRole >>> address_1 = list(user_1.addresses)[0] >>> address_1.address - 'aperson@example.com' + u'aperson@example.com' >>> address_1.subscribe(mlist, MemberRole.owner) <Member: Anne Person <aperson@example.com> on _xtest@example.com as MemberRole.owner> - >>> flush() >>> sorted(member.address.address for member in mlist.owners.members) - ['aperson@example.com'] + [u'aperson@example.com'] >>> sorted(user.real_name for user in mlist.owners.users) - ['Anne Person'] + [u'Anne Person'] >>> sorted(address.address for address in mlist.owners.addresses) - ['aperson@example.com'] + [u'aperson@example.com'] Adding Anne as a list owner also makes her an administrator, but does not make her a moderator. Nor does it make her a member of the list. >>> sorted(user.real_name for user in mlist.administrators.users) - ['Anne Person'] + [u'Anne Person'] >>> sorted(user.real_name for user in mlist.moderators.users) [] >>> sorted(user.real_name for user in mlist.members.users) @@ -104,33 +100,31 @@ her a moderator. Nor does it make her a member of the list. We can add Ben as a moderator of the list, by creating a different member role for him. - >>> user_2 = usermgr.create_user('bperson@example.com', 'Ben Person') - >>> flush() + >>> user_2 = usermgr.create_user(u'bperson@example.com', u'Ben Person') >>> user_2.real_name - 'Ben Person' + u'Ben Person' >>> address_2 = list(user_2.addresses)[0] >>> address_2.address - 'bperson@example.com' + u'bperson@example.com' >>> address_2.subscribe(mlist, MemberRole.moderator) <Member: Ben Person <bperson@example.com> on _xtest@example.com as MemberRole.moderator> - >>> flush() >>> sorted(member.address.address for member in mlist.moderators.members) - ['bperson@example.com'] + [u'bperson@example.com'] >>> sorted(user.real_name for user in mlist.moderators.users) - ['Ben Person'] + [u'Ben Person'] >>> sorted(address.address for address in mlist.moderators.addresses) - ['bperson@example.com'] + [u'bperson@example.com'] Now, both Anne and Ben are list administrators. >>> sorted(member.address.address ... for member in mlist.administrators.members) - ['aperson@example.com', 'bperson@example.com'] + [u'aperson@example.com', u'bperson@example.com'] >>> sorted(user.real_name for user in mlist.administrators.users) - ['Anne Person', 'Ben Person'] + [u'Anne Person', u'Ben Person'] >>> sorted(address.address for address in mlist.administrators.addresses) - ['aperson@example.com', 'bperson@example.com'] + [u'aperson@example.com', u'bperson@example.com'] Members @@ -143,24 +137,22 @@ delivery. Without a preference, Mailman will fall back first to the address's preference, then the user's preference, then the list's preference. Start without any member preference to see the system defaults. - >>> user_3 = usermgr.create_user('cperson@example.com', 'Claire Person') - >>> flush() + >>> user_3 = usermgr.create_user(u'cperson@example.com', u'Claire Person') >>> user_3.real_name - 'Claire Person' + u'Claire Person' >>> address_3 = list(user_3.addresses)[0] >>> address_3.address - 'cperson@example.com' + u'cperson@example.com' >>> address_3.subscribe(mlist, MemberRole.member) <Member: Claire Person <cperson@example.com> on _xtest@example.com as MemberRole.member> - >>> flush() Claire will be a regular delivery member but not a digest member. >>> sorted(address.address for address in mlist.members.addresses) - ['cperson@example.com'] + [u'cperson@example.com'] >>> sorted(address.address for address in mlist.regular_members.addresses) - ['cperson@example.com'] + [u'cperson@example.com'] >>> sorted(address.address for address in mlist.digest_members.addresses) [] @@ -175,11 +167,10 @@ It's easy to make the list administrators members of the mailing list too. _xtest@example.com as MemberRole.member>, <Member: Ben Person <bperson@example.com> on _xtest@example.com as MemberRole.member>] - >>> flush() >>> sorted(address.address for address in mlist.members.addresses) - ['aperson@example.com', 'bperson@example.com', 'cperson@example.com'] + [u'aperson@example.com', u'bperson@example.com', u'cperson@example.com'] >>> sorted(address.address for address in mlist.regular_members.addresses) - ['aperson@example.com', 'bperson@example.com', 'cperson@example.com'] + [u'aperson@example.com', u'bperson@example.com', u'cperson@example.com'] >>> sorted(address.address for address in mlist.digest_members.addresses) [] @@ -190,24 +181,24 @@ Finding members You can find the IMember object that is a member of a roster for a given text email address by using an IRoster's .get_member() method. - >>> mlist.owners.get_member('aperson@example.com') + >>> mlist.owners.get_member(u'aperson@example.com') <Member: Anne Person <aperson@example.com> on _xtest@example.com as MemberRole.owner> - >>> mlist.administrators.get_member('aperson@example.com') + >>> mlist.administrators.get_member(u'aperson@example.com') <Member: Anne Person <aperson@example.com> on _xtest@example.com as MemberRole.owner> - >>> mlist.members.get_member('aperson@example.com') + >>> mlist.members.get_member(u'aperson@example.com') <Member: Anne Person <aperson@example.com> on _xtest@example.com as MemberRole.member> However, if the address is not subscribed with the appropriate role, then None is returned. - >>> print mlist.administrators.get_member('zperson@example.com') + >>> print mlist.administrators.get_member(u'zperson@example.com') None - >>> print mlist.moderators.get_member('aperson@example.com') + >>> print mlist.moderators.get_member(u'aperson@example.com') None - >>> print mlist.members.get_member('zperson@example.com') + >>> print mlist.members.get_member(u'zperson@example.com') None @@ -221,11 +212,11 @@ regardless of their role. ... return (member.address.address, int(member.role)) >>> [(member.address.address, str(member.role)) ... for member in sorted(mlist.subscribers.members, key=sortkey)] - [('aperson@example.com', 'MemberRole.member'), - ('aperson@example.com', 'MemberRole.owner'), - ('bperson@example.com', 'MemberRole.member'), - ('bperson@example.com', 'MemberRole.moderator'), - ('cperson@example.com', 'MemberRole.member')] + [(u'aperson@example.com', 'MemberRole.member'), + (u'aperson@example.com', 'MemberRole.owner'), + (u'bperson@example.com', 'MemberRole.member'), + (u'bperson@example.com', 'MemberRole.moderator'), + (u'cperson@example.com', 'MemberRole.member')] Double subscriptions diff --git a/Mailman/docs/message.txt b/Mailman/docs/message.txt index 601b871bf..8f1e9c17c 100644 --- a/Mailman/docs/message.txt +++ b/Mailman/docs/message.txt @@ -13,10 +13,8 @@ instance, and then calls the .send() method on this object. This method requires a mailing list instance. >>> 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.preferred_language = u'en' - >>> flush() The UserNotification constructor takes the recipient address, the sender address, an optional subject, optional body text, and optional language. diff --git a/Mailman/docs/messagestore.txt b/Mailman/docs/messagestore.txt index a1ed09cb2..9b44a7e59 100644 --- a/Mailman/docs/messagestore.txt +++ b/Mailman/docs/messagestore.txt @@ -10,9 +10,7 @@ second piece of information is supplied by the message store; it is a sequence number that will uniquely identify the message even when the X-List-ID-Hash collides. - >>> from email import message_from_string >>> from Mailman.configuration import config - >>> from Mailman.database import flush >>> store = config.db.message_store If you try to add a message to the store which is missing the Message-ID @@ -33,7 +31,6 @@ However, if the message has a Message-ID header, it can be stored. >>> msg['Message-ID'] = '<87myycy5eh.fsf@uwakimon.sk.tsukuba.ac.jp>' >>> store.add(msg) 1 - >>> flush() >>> print msg.as_string() Subject: An important message Message-ID: <87myycy5eh.fsf@uwakimon.sk.tsukuba.ac.jp> @@ -52,7 +49,7 @@ created above. Because Message-IDs are not guaranteed unique, looking up messages with that key resturns a collection. The collection may be empty if there are no matches. - >>> list(store.get_messages_by_message_id('nothing')) + >>> list(store.get_messages_by_message_id(u'nothing')) [] Given an existing Message-ID, all matching messages will be found. @@ -138,7 +135,6 @@ delete a global ID that isn't in the store, you get an exception. But if you delete an existing message, it really gets deleted. >>> store.delete_message(global_id) - >>> flush() >>> list(store.messages) [] >>> print store.get_message(global_id) diff --git a/Mailman/docs/mlist-addresses.txt b/Mailman/docs/mlist-addresses.txt index 2eba70f8f..dc2184175 100644 --- a/Mailman/docs/mlist-addresses.txt +++ b/Mailman/docs/mlist-addresses.txt @@ -5,56 +5,54 @@ Every mailing list has a number of addresses which are publicly available. These are defined in the IMailingListAddresses interface. >>> from Mailman.configuration import config - >>> from Mailman.database import flush - >>> mlist = config.db.list_manager.create('_xtest@example.com') - >>> flush() + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') The posting address is where people send messages to be posted to the mailing list. This is exactly the same as the fully qualified list name. >>> mlist.fqdn_listname - '_xtest@example.com' + u'_xtest@example.com' >>> mlist.posting_address - '_xtest@example.com' + u'_xtest@example.com' Messages to the mailing list's 'no reply' address always get discarded without prejudice. >>> mlist.noreply_address - 'noreply@example.com' + u'noreply@example.com' The mailing list's owner address reaches the human moderators. >>> mlist.owner_address - '_xtest-owner@example.com' + u'_xtest-owner@example.com' The request address goes to the list's email command robot. >>> mlist.request_address - '_xtest-request@example.com' + u'_xtest-request@example.com' The bounces address accepts and processes all potential bounces. >>> mlist.bounces_address - '_xtest-bounces@example.com' + u'_xtest-bounces@example.com' The join (a.k.a. subscribe) address is where someone can email to get added to the mailing list. The subscribe alias is a synonym for join, but it's deprecated. >>> mlist.join_address - '_xtest-join@example.com' + u'_xtest-join@example.com' >>> mlist.subscribe_address - '_xtest-subscribe@example.com' + u'_xtest-subscribe@example.com' The leave (a.k.a. unsubscribe) address is where someone can email to get added to the mailing list. The unsubscribe alias is a synonym for leave, but it's deprecated. >>> mlist.leave_address - '_xtest-leave@example.com' + u'_xtest-leave@example.com' >>> mlist.unsubscribe_address - '_xtest-unsubscribe@example.com' + u'_xtest-unsubscribe@example.com' Email confirmations @@ -66,12 +64,12 @@ included in the local part of the email address. The exact format of this is dependent on the VERP_CONFIRM_FORMAT configuration variable. >>> mlist.confirm_address('cookie') - '_xtest-confirm+cookie@example.com' + u'_xtest-confirm+cookie@example.com' >>> mlist.confirm_address('wookie') - '_xtest-confirm+wookie@example.com' + u'_xtest-confirm+wookie@example.com' >>> old_format = config.VERP_CONFIRM_FORMAT >>> config.VERP_CONFIRM_FORMAT = '$address---$cookie' >>> mlist.confirm_address('cookie') - '_xtest-confirm---cookie@example.com' + u'_xtest-confirm---cookie@example.com' >>> config.VERP_CONFIRM_FORMAT = old_format diff --git a/Mailman/docs/news-runner.txt b/Mailman/docs/news-runner.txt index 834423c6e..bc6619f50 100644 --- a/Mailman/docs/news-runner.txt +++ b/Mailman/docs/news-runner.txt @@ -6,14 +6,10 @@ NNTP newsgroup. One of the most important things this runner does is prepare the message for Usenet (yes, I know that NNTP is not Usenet, but this runner was originally written to gate to Usenet, which has its own rules). - >>> from email import message_from_string - >>> from Mailman.Message import Message >>> from Mailman.configuration import config - >>> from Mailman.database import flush >>> from Mailman.queue.news import prepare_message - >>> mlist = config.db.list_manager.create('_xtest@example.com') - >>> mlist.linked_newsgroup = 'comp.lang.python' - >>> flush() + >>> 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 @@ -35,7 +31,7 @@ prohibited headers. ... Received: blah blah ... ... A message - ... """, Message) + ... """) >>> msgdata = {} >>> prepare_message(mlist, msg, msgdata) >>> msgdata['prepped'] @@ -66,7 +62,7 @@ X-Original-* header that the news server doesn't care about. ... Content-Transfer-Encoding: maybe ... ... A message - ... """, Message) + ... """) >>> msgdata = {} >>> prepare_message(mlist, msg, msgdata) >>> msgdata['prepped'] @@ -98,7 +94,7 @@ the message. ... Content-Transfer-Encoding: yes ... ... A message - ... """, Message) + ... """) >>> msgdata = {} >>> prepare_message(mlist, msg, msgdata) >>> msgdata['prepped'] @@ -124,7 +120,6 @@ address is added for the benefit of the Usenet system. >>> from Mailman.interfaces import NewsModeration >>> mlist.news_moderation = NewsModeration.open_moderated - >>> flush() >>> msg = message_from_string("""\ ... From: aperson@example.com ... To: _xtest@example.com @@ -133,10 +128,9 @@ 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 - >>> flush() >>> msg = message_from_string("""\ ... From: aperson@example.com ... To: _xtest@example.com @@ -145,12 +139,11 @@ 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. >>> mlist.news_moderation = NewsModeration.none - >>> flush() >>> msg = message_from_string("""\ ... From: aperson@example.com ... To: _xtest@example.com @@ -159,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/nntp.txt b/Mailman/docs/nntp.txt index 9748a06ca..fefddd8b2 100644 --- a/Mailman/docs/nntp.txt +++ b/Mailman/docs/nntp.txt @@ -6,14 +6,10 @@ be forwarded onto an NNTP newsgroup. Typically this means Usenet, but since NNTP is to Usenet as IP is to the web, it's more general than that. >>> from Mailman.Handlers.ToUsenet 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.preferred_language = 'en' - >>> flush() + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') + >>> mlist.preferred_language = u'en' >>> switchboard = Switchboard(config.NEWSQUEUE_DIR) Gatewaying from the mailing list to the newsgroup happens through a separate @@ -25,12 +21,11 @@ There are several situations which prevent a message from being gatewayed to the newsgroup. The feature could be disabled, as is the default. >>> mlist.gateway_to_news = False - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... Subject: An important message ... ... Something of great import. - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> switchboard.files [] @@ -39,7 +34,6 @@ Even if enabled, messages that came from the newsgroup are never gated back to the newsgroup. >>> mlist.gateway_to_news = True - >>> flush() >>> process(mlist, msg, {'fromusenet': True}) >>> switchboard.files [] @@ -54,9 +48,8 @@ However, other posted messages get gated to the newsgroup via the nntp queue. The list owner can set the linked newsgroup and the nntp host that its messages are gated to. - >>> mlist.linked_newsgroup = 'comp.lang.thing' - >>> mlist.nntp_host = 'news.example.com' - >>> flush() + >>> mlist.linked_newsgroup = u'comp.lang.thing' + >>> mlist.nntp_host = u'news.example.com' >>> process(mlist, msg, {}) >>> len(switchboard.files) 1 @@ -70,6 +63,6 @@ messages are gated to. <BLANKLINE> >>> sorted(msgdata.items()) [('_parsemsg', False), - ('listname', '_xtest@example.com'), + ('listname', u'_xtest@example.com'), ('received_time', ...), ('version', 3)] diff --git a/Mailman/docs/outgoing.txt b/Mailman/docs/outgoing.txt index 05dac1fe4..ba2c6430b 100644 --- a/Mailman/docs/outgoing.txt +++ b/Mailman/docs/outgoing.txt @@ -10,13 +10,9 @@ basically describes how to encode the recipient's address in the originator headers for unambigous bounce processing. >>> from Mailman.Handlers.ToOutgoing 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') - >>> flush() + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') >>> switchboard = Switchboard(config.OUTQUEUE_DIR) >>> def queue_size(): @@ -33,7 +29,7 @@ as if this message had passed through some other handlers. ... Subject: Here is a message ... ... Something of great import. - ... """, Message) + ... """) When certain conditions are met, the message will be VERP'd. For example, if the message metadata already has a VERP key, this message will be VERP'd. @@ -60,7 +56,7 @@ additional key set: the mailing list name. >>> sorted(qmsgdata.items()) [('_parsemsg', False), ('bar', 2), ('foo', 1), - ('listname', '_xtest@example.com'), + ('listname', u'_xtest@example.com'), ('received_time', ...), ('verp', True), ('version', 3)] >>> queue_size() @@ -70,10 +66,11 @@ If the list is set to personalize deliveries, and the global configuration option to VERP personalized deliveries is set, then the message will be VERP'd. + # Save the original value for clean up. + >>> verp_personalized_delivieries = config.VERP_PERSONALIZED_DELIVERIES + >>> config.VERP_PERSONALIZED_DELIVERIES = True >>> from Mailman.interfaces import Personalization >>> mlist.personalize = Personalization.individual - >>> flush() - >>> config.VERP_PERSONALIZED_DELIVERIES = True >>> msgdata = dict(foo=1, bar=2) >>> process(mlist, msg, msgdata) >>> msgdata['verp'] @@ -97,9 +94,10 @@ the global configuration variable VERP_DELIVERY_INTERVAL. This variable tells Mailman how often to VERP even non-personalized mailing lists. It can be set to zero, which means non-personalized messages will never be VERP'd. - >>> mlist.personalize = Personalization.none - >>> flush() + # Save the original value for clean up. + >>> verp_delivery_interval = config.VERP_DELIVERY_INTERVAL >>> config.VERP_DELIVERY_INTERVAL = 0 + >>> mlist.personalize = Personalization.none >>> msgdata = dict(foo=1, bar=2) >>> process(mlist, msg, msgdata) >>> print msgdata.get('verp') @@ -133,7 +131,6 @@ will be VERP'd. >>> config.VERP_DELIVERY_INTERVAL = 3 >>> for i in range(10): ... mlist.post_id = i - ... flush() ... msgdata = dict(foo=1, bar=2) ... process(mlist, msg, msgdata) ... print i, msgdata.get('verp', False) @@ -149,3 +146,10 @@ will be VERP'd. 9 True >>> queue_size() 10 + + +Clean up +======== + + >>> config.VERP_PERSONALIZED_DELIVERIES = verp_personalized_delivieries + >>> config.VERP_DELIVERY_INTERVAL = verp_delivery_interval diff --git a/Mailman/docs/pending.txt b/Mailman/docs/pending.txt index d93da5283..566cc2de6 100644 --- a/Mailman/docs/pending.txt +++ b/Mailman/docs/pending.txt @@ -7,7 +7,6 @@ messages (but only for user confirmation), auto-approvals, and probe bounces. This is not where messages held for administrator approval are kept. >>> from Mailman.configuration import config - >>> from Mailman.database import flush >>> from zope.interface import implements >>> from zope.interface.verify import verifyObject @@ -32,7 +31,6 @@ that can be used in urls and such. ... language='en', ... password='xyz') >>> token = pendingdb.add(subscription) - >>> flush() >>> len(token) 40 @@ -45,13 +43,12 @@ returned. >>> print pendable None >>> pendable = pendingdb.confirm(token) - >>> flush() >>> sorted(pendable.items()) - [('address', 'aperson@example.com'), - ('language', 'en'), - ('password', 'xyz'), - ('realname', 'Anne Person'), - ('type', 'subscription')] + [(u'address', u'aperson@example.com'), + (u'language', u'en'), + (u'password', u'xyz'), + (u'realname', u'Anne Person'), + (u'type', u'subscription')] After confirmation, the token is no longer in the database. @@ -69,17 +66,13 @@ expunge it. >>> token_2 = pendingdb.add(event_2) >>> event_3 = SimplePendable(type='three') >>> token_3 = pendingdb.add(event_3) - >>> flush() >>> pendable = pendingdb.confirm(token_1, expunge=False) - >>> flush() >>> pendable.items() - [('type', 'one')] + [(u'type', u'one')] >>> pendable = pendingdb.confirm(token_1, expunge=True) - >>> flush() >>> pendable.items() - [('type', 'one')] + [(u'type', u'one')] >>> pendable = pendingdb.confirm(token_1) - >>> flush() >>> print pendable None @@ -90,16 +83,13 @@ default lifetime. >>> yesterday = timedelta(days=-1) >>> event_4 = SimplePendable(type='four') >>> token_4 = pendingdb.add(event_4, lifetime=yesterday) - >>> flush() Every once in a while the pending database is cleared of old records. >>> pendingdb.evict() - >>> flush() >>> pendable = pendingdb.confirm(token_4) >>> print pendable None >>> pendable = pendingdb.confirm(token_2) >>> pendable.items() - [('type', 'two')] - >>> flush() + [(u'type', u'two')] diff --git a/Mailman/docs/registration.txt b/Mailman/docs/registration.txt index 219a0cef5..9f699b966 100644 --- a/Mailman/docs/registration.txt +++ b/Mailman/docs/registration.txt @@ -9,7 +9,6 @@ will send them any list traffic. >>> from Mailman.app.registrar import Registrar >>> from Mailman.configuration import config - >>> from Mailman.database import flush >>> from Mailman.interfaces import IRegistrar The IUserManager manages users, but it does so at a fairly low level. @@ -105,26 +104,25 @@ is complete. No IUser or IAddress is created at registration time, but a record is added to the pending database, and the token for that record is returned. - >>> token = registrar.register('aperson@example.com', 'Anne Person') - >>> flush() + >>> token = registrar.register(u'aperson@example.com', u'Anne Person') >>> check_token(token) ok There should be no records in the user manager for this address yet. >>> usermgr = config.db.user_manager - >>> print usermgr.get_user('aperson@example.com') + >>> print usermgr.get_user(u'aperson@example.com') None - >>> print usermgr.get_address('aperson@example.com') + >>> print usermgr.get_address(u'aperson@example.com') None But this address is waiting for confirmation. >>> pendingdb = config.db.pendings >>> sorted(pendingdb.confirm(token, expunge=False).items()) - [('address', 'aperson@example.com'), - ('real_name', 'Anne Person'), - ('type', 'registration')] + [(u'address', u'aperson@example.com'), + (u'real_name', u'Anne Person'), + (u'type', u'registration')] Verification by email @@ -176,7 +174,7 @@ message is sent to the user in order to verify the registered address. [('_parsemsg', False), ('nodecorate', True), ('received_time', ...), - ('recips', ['aperson@example.com']), + ('recips', [u'aperson@example.com']), ('reduced_list_headers', True), ('version', 3)] @@ -204,15 +202,14 @@ extracts the token and uses that to confirm the pending registration. >>> registrar.confirm(token) True - >>> flush() Now, there is an IAddress in the database matching the address, as well as an IUser linked to this address. The IAddress is verified. - >>> found_address = usermgr.get_address('aperson@example.com') + >>> found_address = usermgr.get_address(u'aperson@example.com') >>> found_address <Address: Anne Person <aperson@example.com> [verified] at ...> - >>> found_user = usermgr.get_user('aperson@example.com') + >>> found_user = usermgr.get_user(u'aperson@example.com') >>> found_user <User "Anne Person" at ...> >>> found_user.controls(found_address.address) @@ -228,8 +225,7 @@ Non-standard registrations If you try to confirm a registration token twice, of course only the first one will work. The second one is ignored. - >>> token = registrar.register('bperson@example.com') - >>> flush() + >>> token = registrar.register(u'bperson@example.com') >>> check_token(token) ok >>> filebase = switchboard.files[0] @@ -240,7 +236,6 @@ will work. The second one is ignored. True >>> registrar.confirm(token) True - >>> flush() >>> registrar.confirm(token) False @@ -248,28 +243,25 @@ If an address is in the system, but that address is not linked to a user yet and the address is not yet validated, then no user is created until the confirmation step is completed. - >>> usermgr.create_address('cperson@example.com') + >>> usermgr.create_address(u'cperson@example.com') <Address: cperson@example.com [not verified] at ...> - >>> flush() - >>> token = registrar.register('cperson@example.com', 'Claire Person') - >>> flush() - >>> print usermgr.get_user('cperson@example.com') + >>> token = registrar.register(u'cperson@example.com', u'Claire Person') + >>> print usermgr.get_user(u'cperson@example.com') None >>> filebase = switchboard.files[0] >>> qmsg, qdata = switchboard.dequeue(filebase) >>> switchboard.finish(filebase) >>> registrar.confirm(token) True - >>> flush() - >>> usermgr.get_user('cperson@example.com') + >>> usermgr.get_user(u'cperson@example.com') <User "Claire Person" at ...> - >>> usermgr.get_address('cperson@example.com') + >>> usermgr.get_address(u'cperson@example.com') <Address: cperson@example.com [verified] at ...> If an address being registered has already been verified, linked or not to a user, then registration sends no confirmation. - >>> print registrar.register('cperson@example.com') + >>> print registrar.register(u'cperson@example.com') None >>> len(switchboard.files) 0 @@ -277,17 +269,15 @@ user, then registration sends no confirmation. But if the already verified address is not linked to a user, then a user is created now and they are linked, with no confirmation necessary. - >>> address = usermgr.create_address('dperson@example.com', 'Dave Person') + >>> address = usermgr.create_address(u'dperson@example.com', u'Dave Person') >>> address.verified_on = datetime.now() - >>> flush() - >>> print usermgr.get_user('dperson@example.com') + >>> print usermgr.get_user(u'dperson@example.com') None - >>> print registrar.register('dperson@example.com') + >>> print registrar.register(u'dperson@example.com') None - >>> flush() >>> len(switchboard.files) 0 - >>> usermgr.get_user('dperson@example.com') + >>> usermgr.get_user(u'dperson@example.com') <User "Dave Person" at ...> @@ -297,17 +287,15 @@ Discarding A confirmation token can also be discarded, say if the user changes his or her mind about registering. When discarded, no IAddress or IUser is created. - >>> token = registrar.register('eperson@example.com', 'Elly Person') + >>> token = registrar.register(u'eperson@example.com', u'Elly Person') >>> check_token(token) ok - >>> flush() >>> registrar.discard(token) - >>> flush() >>> print pendingdb.confirm(token) None - >>> print usermgr.get_address('eperson@example.com') + >>> print usermgr.get_address(u'eperson@example.com') None - >>> print usermgr.get_user('eperson@example.com') + >>> print usermgr.get_user(u'eperson@example.com') None @@ -318,23 +306,21 @@ When a new address for an existing user is registered, there isn't too much different except that the new address will still need to be verified before it can be used. - >>> dperson = usermgr.get_user('dperson@example.com') + >>> dperson = usermgr.get_user(u'dperson@example.com') >>> dperson <User "Dave Person" at ...> >>> from operator import attrgetter >>> sorted((addr for addr in dperson.addresses), key=attrgetter('address')) [<Address: Dave Person <dperson@example.com> [verified] at ...>] - >>> dperson.register('david.person@example.com', 'David Person') + >>> dperson.register(u'david.person@example.com', u'David Person') <Address: David Person <david.person@example.com> [not verified] at ...> - >>> flush() - >>> token = registrar.register('david.person@example.com') - >>> flush() + >>> token = registrar.register(u'david.person@example.com') >>> filebase = switchboard.files[0] >>> qmsg, qdata = switchboard.dequeue(filebase) >>> switchboard.finish(filebase) >>> registrar.confirm(token) True - >>> user = usermgr.get_user('david.person@example.com') + >>> user = usermgr.get_user(u'david.person@example.com') >>> user is dperson True >>> user @@ -362,10 +348,8 @@ pending even matched with that token will still be removed. ... implements(IPendable) >>> pendable = SimplePendable(type='foo', bar='baz') >>> token = pendingdb.add(pendable) - >>> flush() >>> registrar.confirm(token) False - >>> flush() >>> print pendingdb.confirm(token) None @@ -374,9 +358,7 @@ record, you will also get None back, and the record will be removed. >>> pendable = SimplePendable(type='registration', foo='bar') >>> token = pendingdb.add(pendable) - >>> flush() >>> registrar.confirm(token) False - >>> flush() >>> print pendingdb.confirm(token) None diff --git a/Mailman/docs/reply-to.txt b/Mailman/docs/reply-to.txt index a937ced8f..537681f93 100644 --- a/Mailman/docs/reply-to.txt +++ b/Mailman/docs/reply-to.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() Reply-to munging refers to the behavior where a mailing list can be configured to change or augment an existing Reply-To header in a message posted to the @@ -43,50 +39,47 @@ message, the list's posting address simply gets inserted. >>> from Mailman.interfaces import ReplyToMunging >>> mlist.reply_goes_to_list = ReplyToMunging.point_to_list - >>> mlist.preferred_language = 'en' - >>> mlist.description = '' - >>> flush() - >>> msg = message_from_string("""\ + >>> mlist.preferred_language = u'en' + >>> mlist.description = u'' + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> len(msg.get_all('reply-to')) 1 >>> msg['reply-to'] - '_xtest@example.com' + u'_xtest@example.com' It's also possible to strip any existing Reply-To header first, before adding the list's posting address. >>> mlist.first_strip_reply_to = True - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... Reply-To: bperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> len(msg.get_all('reply-to')) 1 >>> msg['reply-to'] - '_xtest@example.com' + u'_xtest@example.com' If you don't first strip the header, then the list's posting address will just get appended to whatever the original version was. >>> mlist.first_strip_reply_to = False - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... Reply-To: bperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> len(msg.get_all('reply-to')) 1 >>> msg['reply-to'] - 'bperson@example.com, _xtest@example.com' + u'bperson@example.com, _xtest@example.com' Explicit Reply-To @@ -95,44 +88,41 @@ Explicit Reply-To The list can also be configured to have an explicit Reply-To header. >>> mlist.reply_goes_to_list = ReplyToMunging.explicit_header - >>> mlist.reply_to_address = 'my-list@example.com' - >>> flush() - >>> msg = message_from_string("""\ + >>> mlist.reply_to_address = u'my-list@example.com' + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> len(msg.get_all('reply-to')) 1 >>> msg['reply-to'] - 'my-list@example.com' + u'my-list@example.com' And as before, it's possible to either strip any existing Reply-To header... >>> mlist.first_strip_reply_to = True - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... Reply-To: bperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> len(msg.get_all('reply-to')) 1 >>> msg['reply-to'] - 'my-list@example.com' + u'my-list@example.com' ...or not. >>> mlist.first_strip_reply_to = False - >>> flush() - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... Reply-To: bperson@example.com ... - ... """, Message) + ... """) >>> process(mlist, msg, {}) >>> len(msg.get_all('reply-to')) 1 >>> msg['reply-to'] - 'my-list@example.com, bperson@example.com' + u'my-list@example.com, bperson@example.com' 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..7a395ce94 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. @@ -15,7 +14,7 @@ Here is a helper function for printing out held requests. ... key, data = requests.get_request(request.id) ... if data is not None: ... data = sorted(data.items()) - ... print request.id, str(request.type), key, data + ... print request.id, str(request.request_type), key, data And another helper for displaying messages in the virgin queue. @@ -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 @@ -67,13 +65,12 @@ of associated data. The request database assigns no semantics to the held data, except for the request type. Here we hold some simple bits of data. >>> from Mailman.interfaces import RequestType - >>> id_1 = requests.hold_request(RequestType.held_message, 'hold_1') - >>> id_2 = requests.hold_request(RequestType.subscription, 'hold_2') - >>> id_3 = requests.hold_request(RequestType.unsubscription, 'hold_3') - >>> id_4 = requests.hold_request(RequestType.held_message, 'hold_4') + >>> id_1 = requests.hold_request(RequestType.held_message, u'hold_1') + >>> id_2 = requests.hold_request(RequestType.subscription, u'hold_2') + >>> id_3 = requests.hold_request(RequestType.unsubscription, u'hold_3') + >>> id_4 = requests.hold_request(RequestType.held_message, u'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. @@ -101,8 +98,7 @@ If we try to hold a request with a bogus type, we get an exception. 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 = requests.hold_request(RequestType.held_message, u'hold_5', data) >>> id_5 5 >>> requests.count @@ -112,7 +108,7 @@ We can hold requests with additional data. 2 RequestType.subscription hold_2 None 3 RequestType.unsubscription hold_3 None 4 RequestType.held_message hold_4 None - 5 RequestType.held_message hold_5 [('bar', 'no'), ('foo', 'yes')] + 5 RequestType.held_message hold_5 [(u'bar', u'no'), (u'foo', u'yes')] Getting requests @@ -136,9 +132,9 @@ However, if we ask for a request that had data, we'd get it back now. >>> key, data = requests.get_request(5) >>> key - 'hold_5' + u'hold_5' >>> sorted(data.items()) - [('bar', 'no'), ('foo', 'yes')] + [(u'bar', u'no'), (u'foo', u'yes')] If we ask for a request that is not in the database, we get None back. @@ -155,14 +151,14 @@ over by type. >>> requests.count_of(RequestType.held_message) 3 >>> for request in requests.of_type(RequestType.held_message): - ... assert request.type is RequestType.held_message + ... assert request.request_type is RequestType.held_message ... key, data = requests.get_request(request.id) ... if data is not None: ... data = sorted(data.items()) ... print request.id, key, data 1 hold_1 None 4 hold_4 None - 5 hold_5 [('bar', 'no'), ('foo', 'yes')] + 5 hold_5 [(u'bar', u'no'), (u'foo', u'yes')] Deleting requests @@ -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 @@ -215,19 +209,16 @@ Holding messages 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("""\ + >>> mlist = config.db.list_manager.create(u'alist@example.com') + >>> mlist.preferred_language = u'en' + >>> mlist.real_name = u'A Test List' + >>> 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 +226,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 @@ -244,8 +234,7 @@ We can also hold a message with some additional metadata. >>> msgdata = dict(sender='aperson@example.com', ... approved=True, ... received_time=123.45) - >>> id_2 = moderator.hold_message(mlist, msg, msgdata, 'Feeling ornery') - >>> flush() + >>> id_2 = moderator.hold_message(mlist, msg, msgdata, u'Feeling ornery') >>> requests.get_request(id_2) is not None True @@ -254,7 +243,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 +250,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 +258,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() @@ -302,10 +288,10 @@ The message can be rejected, meaning it is bounced back to the sender. <BLANKLINE> >>> sorted(qdata.items()) [('_parsemsg', False), - ('listname', 'alist@example.com'), + ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), - ('recips', ['aperson@example.org']), + ('recips', [u'aperson@example.org']), ('reduced_list_headers', True), ('version', 3)] @@ -314,9 +300,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() @@ -332,8 +316,8 @@ indicates that the message has been approved. <BLANKLINE> >>> sorted(qdata.items()) [('_parsemsg', False), - ('adminapproved', True), ('approved', True), - ('received_time', ...), ('sender', 'aperson@example.com'), + ('adminapproved', True), (u'approved', True), + (u'received_time', 123.45), (u'sender', u'aperson@example.com'), ('version', 3)] In addition to any of the above dispositions, the message can also be @@ -344,19 +328,17 @@ 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>') + >>> msgs = config.db.message_store.get_messages_by_message_id(u'<12345>') >>> list(msgs) [] @@ -364,10 +346,8 @@ 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 = config.db.message_store.get_messages_by_message_id(u'<12345>') >>> msgs = list(msgs) >>> len(msgs) 1 @@ -387,10 +367,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() + ... forward=[u'zperson@example.com']) >>> qmsg, qdata = dequeue() >>> print qmsg.as_string() Subject: Forward of moderated message @@ -412,9 +390,9 @@ moderators. Here's something important about our mailing list. <BLANKLINE> >>> sorted(qdata.items()) - [('_parsemsg', False), ('listname', 'alist@example.com'), + [('_parsemsg', False), ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), - ('recips', ['zperson@example.com']), + ('recips', [u'zperson@example.com']), ('reduced_list_headers', True), ('version', 3)] @@ -429,11 +407,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() + ... u'bperson@example.org', u'Ben Person', + ... u'{NONE}abcxyz', DeliveryMode.regular, u'en') >>> requests.get_request(id_3) is not None True @@ -451,12 +427,10 @@ queue when the message is held. >>> mlist.admin_immed_notify = True >>> # 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() + >>> mlist.web_page_url = u'http://www.example.com/' >>> id_4 = moderator.hold_subscription(mlist, - ... 'cperson@example.org', 'Claire Person', - ... '{NONE}zyxcba', DeliveryMode.regular, 'en') - >>> flush() + ... u'cperson@example.org', u'Claire Person', + ... u'{NONE}zyxcba', DeliveryMode.regular, u'en') >>> requests.get_request(id_4) is not None True >>> qmsg, qdata = dequeue() @@ -486,24 +460,22 @@ queue when the message is held. <BLANKLINE> >>> sorted(qdata.items()) [('_parsemsg', False), - ('listname', 'alist@example.com'), + ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), - ('recips', ['alist-owner@example.com']), + ('recips', [u'alist-owner@example.com']), ('reduced_list_headers', True), ('tomoderators', True), ('version', 3)] 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 +484,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() @@ -542,10 +513,10 @@ subscriber. alist-owner@example.com <BLANKLINE> >>> sorted(qdata.items()) - [('_parsemsg', False), ('listname', 'alist@example.com'), + [('_parsemsg', False), ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), - ('recips', ['cperson@example.org']), + ('recips', [u'cperson@example.org']), ('reduced_list_headers', True), ('version', 3)] The subscription can also be accepted. This subscribes the address to the @@ -553,9 +524,8 @@ mailing list. >>> mlist.send_welcome_msg = True >>> id_4 = moderator.hold_subscription(mlist, - ... 'fperson@example.org', 'Frank Person', - ... '{NONE}abcxyz', DeliveryMode.regular, 'en') - >>> flush() + ... u'fperson@example.org', u'Frank Person', + ... u'{NONE}abcxyz', DeliveryMode.regular, u'en') A message will be sent to the moderators telling them about the held subscription and the fact that they may need to approve it. @@ -586,16 +556,15 @@ subscription and the fact that they may need to approve it. to process the request. <BLANKLINE> >>> sorted(qdata.items()) - [('_parsemsg', False), ('listname', 'alist@example.com'), + [('_parsemsg', False), ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), - ('recips', ['alist-owner@example.com']), + ('recips', [u'alist-owner@example.com']), ('reduced_list_headers', True), ('tomoderators', True), ('version', 3)] 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 @@ -657,9 +626,9 @@ The welcome message is sent to the person who just subscribed. options page that will send your current password to you. <BLANKLINE> >>> sorted(welcome_qdata.items()) - [('_parsemsg', False), ('listname', 'alist@example.com'), + [('_parsemsg', False), ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), - ('recips', ['fperson@example.org']), + ('recips', [u'fperson@example.org']), ('reduced_list_headers', True), ('verp', False), ('version', 3)] The admin message is sent to the moderators. @@ -680,25 +649,25 @@ The admin message is sent to the moderators. <BLANKLINE> >>> sorted(admin_qdata.items()) [('_parsemsg', False), ('envsender', 'changeme@example.com'), - ('listname', 'alist@example.com'), + ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), ('recips', []), ('reduced_list_headers', True), ('version', 3)] Frank Person is now a member of the mailing list. - >>> member = mlist.members.get_member('fperson@example.org') + >>> member = mlist.members.get_member(u'fperson@example.org') >>> member <Member: Frank Person <fperson@example.org> on alist@example.com as MemberRole.member> >>> member.preferred_language - 'en' + u'en' >>> print member.delivery_mode DeliveryMode.regular >>> user = config.db.user_manager.get_user(member.address.address) >>> user.real_name - 'Frank Person' + u'Frank Person' >>> user.password - '{NONE}abcxyz' + u'{NONE}abcxyz' Holding unsubscription requests @@ -709,28 +678,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() + >>> user_1 = config.db.user_manager.create_user(u'gperson@example.com') >>> 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() + >>> user_2 = config.db.user_manager.create_user(u'hperson@example.com') >>> 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() + >>> id_5 = moderator.hold_unsubscription(mlist, u'gperson@example.com') >>> 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() + >>> id_6 = moderator.hold_unsubscription(mlist, u'hperson@example.com') >>> qmsg, qdata = dequeue() >>> print qmsg.as_string() MIME-Version: 1.0 @@ -757,16 +720,15 @@ unsubscription holds can send the list's moderators an immediate notification. <BLANKLINE> >>> sorted(qdata.items()) [('_parsemsg', False), - ('listname', 'alist@example.com'), ('nodecorate', True), + ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), - ('recips', ['alist-owner@example.com']), + ('recips', [u'alist-owner@example.com']), ('reduced_list_headers', True), ('tomoderators', True), ('version', 3)] 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,10 +736,9 @@ 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') + >>> mlist.members.get_member(u'gperson@example.com') <Member: gperson@example.com on alist@example.com as MemberRole.member> The request can be rejected, in which case a message is sent to the member, @@ -785,7 +746,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() @@ -816,25 +776,22 @@ and the person remains a member of the mailing list. <BLANKLINE> >>> sorted(qdata.items()) [('_parsemsg', False), - ('listname', 'alist@example.com'), + ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), ('recips', [u'hperson@example.com']), ('reduced_list_headers', True), ('version', 3)] - >>> mlist.members.get_member('hperson@example.com') + >>> mlist.members.get_member(u'hperson@example.com') <Member: hperson@example.com on alist@example.com as MemberRole.member> The unsubscription request can also be accepted. This removes the member from the mailing list. >>> mlist.send_goodbye_msg = True - >>> mlist.goodbye_msg = 'So long!' + >>> mlist.goodbye_msg = u'So long!' >>> mlist.admin_immed_notify = False - >>> flush() - >>> id_7 = moderator.hold_unsubscription(mlist, 'gperson@example.com') - >>> flush() + >>> id_7 = moderator.hold_unsubscription(mlist, u'gperson@example.com') >>> moderator.handle_unsubscription(mlist, id_7, Action.accept) - >>> flush() - >>> print mlist.members.get_member('gperson@example.com') + >>> print mlist.members.get_member(u'gperson@example.com') None There are now two messages in the virgin queue, one to the member who was just @@ -872,9 +829,9 @@ The goodbye message... <BLANKLINE> >>> sorted(goodbye_qdata.items()) [('_parsemsg', False), - ('listname', 'alist@example.com'), + ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), - ('recips', ['gperson@example.com']), + ('recips', [u'gperson@example.com']), ('reduced_list_headers', True), ('verp', False), ('version', 3)] ...and the admin message. @@ -894,6 +851,6 @@ The goodbye message... <BLANKLINE> >>> sorted(admin_qdata.items()) [('_parsemsg', False), ('envsender', 'changeme@example.com'), - ('listname', 'alist@example.com'), + ('listname', u'alist@example.com'), ('nodecorate', True), ('received_time', ...), ('recips', []), ('reduced_list_headers', True), ('version', 3)] diff --git a/Mailman/docs/runner.txt b/Mailman/docs/runner.txt index 75ec90758..5e5a88d8c 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() @@ -68,8 +64,7 @@ on instance variables. >>> sorted(runner.msgdata.items()) [('_parsemsg', False), ('bar', 'no'), ('foo', 'yes'), - ('lang', 'en'), ('listname', '_xtest@example.com'), + ('lang', u'en'), ('listname', u'_xtest@example.com'), ('received_time', ...), ('version', 3)] - XXX More of the Runner API should be tested. 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/switchboard.txt b/Mailman/docs/switchboard.txt index ce8f277ed..299aba499 100644 --- a/Mailman/docs/switchboard.txt +++ b/Mailman/docs/switchboard.txt @@ -4,21 +4,19 @@ The switchboard The switchboard is subsystem that moves messages between queues. Each instance of a switchboard is responsible for one queue directory. - >>> from email import message_from_string - >>> from Mailman.Message import Message - >>> from Mailman.queue import Switchboard - >>> msg = message_from_string("""\ + >>> msg = message_from_string(u"""\ ... From: aperson@example.com ... To: _xtest@example.com ... ... A test message. - ... """, Message) + ... """) Create a switchboard by giving its queue directory. >>> import os >>> from Mailman.configuration import config >>> queue_directory = os.path.join(config.QUEUE_DIR, 'test') + >>> from Mailman.queue import Switchboard >>> switchboard = Switchboard(queue_directory) >>> switchboard.queue_directory == queue_directory True 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/docs/usermanager.txt b/Mailman/docs/usermanager.txt index b8a9d2e66..95cded2aa 100644 --- a/Mailman/docs/usermanager.txt +++ b/Mailman/docs/usermanager.txt @@ -7,7 +7,6 @@ variable MANAGERS_INIT_FUNCTION. The instance is accessible on the global config object. >>> from Mailman.configuration import config - >>> from Mailman.database import flush >>> from Mailman.interfaces import IUserManager >>> from zope.interface.verify import verifyObject >>> usermgr = config.db.user_manager @@ -25,13 +24,12 @@ have a password. >>> from Mailman.interfaces import IUser >>> user = usermgr.create_user() - >>> flush() >>> verifyObject(IUser, user) True >>> sorted(address.address for address in user.addresses) [] >>> user.real_name - '' + u'' >>> print user.password None @@ -42,59 +40,53 @@ The user has preferences, but none of them will be specified. A user can be assigned a real name. - >>> user.real_name = 'Anne Person' - >>> flush() + >>> user.real_name = u'Anne Person' >>> sorted(user.real_name for user in usermgr.users) - ['Anne Person'] + [u'Anne Person'] A user can be assigned a password. - >>> user.password = 'secret' - >>> flush() + >>> user.password = u'secret' >>> sorted(user.password for user in usermgr.users) - ['secret'] + [u'secret'] You can also create a user with an address to start out with. - >>> user_2 = usermgr.create_user('bperson@example.com') - >>> flush() + >>> user_2 = usermgr.create_user(u'bperson@example.com') >>> verifyObject(IUser, user_2) True >>> sorted(address.address for address in user_2.addresses) - ['bperson@example.com'] + [u'bperson@example.com'] >>> sorted(user.real_name for user in usermgr.users) - ['', 'Anne Person'] + [u'', u'Anne Person'] As above, you can assign a real name to such users. - >>> user_2.real_name = 'Ben Person' - >>> flush() + >>> user_2.real_name = u'Ben Person' >>> sorted(user.real_name for user in usermgr.users) - ['Anne Person', 'Ben Person'] + [u'Anne Person', u'Ben Person'] You can also create a user with just a real name. - >>> user_3 = usermgr.create_user(real_name='Claire Person') - >>> flush() + >>> user_3 = usermgr.create_user(real_name=u'Claire Person') >>> verifyObject(IUser, user_3) True >>> sorted(address.address for address in user.addresses) [] >>> sorted(user.real_name for user in usermgr.users) - ['Anne Person', 'Ben Person', 'Claire Person'] + [u'Anne Person', u'Ben Person', u'Claire Person'] Finally, you can create a user with both an address and a real name. - >>> user_4 = usermgr.create_user('dperson@example.com', 'Dan Person') - >>> flush() + >>> user_4 = usermgr.create_user(u'dperson@example.com', u'Dan Person') >>> verifyObject(IUser, user_3) True >>> sorted(address.address for address in user_4.addresses) - ['dperson@example.com'] + [u'dperson@example.com'] >>> sorted(address.real_name for address in user_4.addresses) - ['Dan Person'] + [u'Dan Person'] >>> sorted(user.real_name for user in usermgr.users) - ['Anne Person', 'Ben Person', 'Claire Person', 'Dan Person'] + [u'Anne Person', u'Ben Person', u'Claire Person', u'Dan Person'] Deleting users @@ -104,9 +96,8 @@ You delete users by going through the user manager. The deleted user is no longer available through the user manager iterator. >>> usermgr.delete_user(user) - >>> flush() >>> sorted(user.real_name for user in usermgr.users) - ['Ben Person', 'Claire Person', 'Dan Person'] + [u'Ben Person', u'Claire Person', u'Dan Person'] Finding users @@ -127,9 +118,8 @@ object. If the address is not in the user database or does not have a user associated with it, you will get None back. - >>> print usermgr.get_user('zperson@example.com') + >>> print usermgr.get_user(u'zperson@example.com') None >>> user_4.unlink(address) - >>> flush() >>> print usermgr.get_user(address.address) None diff --git a/Mailman/docs/users.txt b/Mailman/docs/users.txt index 130c97210..d346d37fe 100644 --- a/Mailman/docs/users.txt +++ b/Mailman/docs/users.txt @@ -7,7 +7,6 @@ they control. See usermanager.txt for examples of how to create, delete, and find users. - >>> from Mailman.database import flush >>> from Mailman.configuration import config >>> usermgr = config.db.user_manager @@ -18,23 +17,21 @@ User data Users may have a real name and a password. >>> user_1 = usermgr.create_user() - >>> user_1.password = 'my password' - >>> user_1.real_name = 'Zoe Person' - >>> flush() + >>> user_1.password = u'my password' + >>> user_1.real_name = u'Zoe Person' >>> sorted(user.real_name for user in usermgr.users) - ['Zoe Person'] + [u'Zoe Person'] >>> sorted(user.password for user in usermgr.users) - ['my password'] + [u'my password'] The password and real name can be changed at any time. - >>> user_1.real_name = 'Zoe X. Person' - >>> user_1.password = 'another password' - >>> flush() + >>> user_1.real_name = u'Zoe X. Person' + >>> user_1.password = u'another password' >>> sorted(user.real_name for user in usermgr.users) - ['Zoe X. Person'] + [u'Zoe X. Person'] >>> sorted(user.password for user in usermgr.users) - ['another password'] + [u'another password'] Users addresses @@ -47,25 +44,23 @@ many addresses, but addresses may be controlled by only one user. The easiest way to link a user to an address is to just register the new address on a user object. - >>> user_1.register('zperson@example.com', 'Zoe Person') + >>> user_1.register(u'zperson@example.com', u'Zoe Person') <Address: Zoe Person <zperson@example.com> [not verified] at 0x...> - >>> user_1.register('zperson@example.org') + >>> user_1.register(u'zperson@example.org') <Address: zperson@example.org [not verified] at 0x...> - >>> flush() >>> sorted(address.address for address in user_1.addresses) - ['zperson@example.com', 'zperson@example.org'] + [u'zperson@example.com', u'zperson@example.org'] >>> sorted(address.real_name for address in user_1.addresses) - ['', 'Zoe Person'] + [u'', u'Zoe Person'] You can also create the address separately and then link it to the user. - >>> address_1 = usermgr.create_address('zperson@example.net') + >>> address_1 = usermgr.create_address(u'zperson@example.net') >>> user_1.link(address_1) - >>> flush() >>> sorted(address.address for address in user_1.addresses) - ['zperson@example.com', 'zperson@example.net', 'zperson@example.org'] + [u'zperson@example.com', u'zperson@example.net', u'zperson@example.org'] >>> sorted(address.real_name for address in user_1.addresses) - ['', '', 'Zoe Person'] + [u'', u'', u'Zoe Person'] But don't try to link an address to more than one user. @@ -79,27 +74,27 @@ You can also ask whether a given user controls a given address. >>> user_1.controls(address_1.address) True - >>> user_1.controls('bperson@example.com') + >>> user_1.controls(u'bperson@example.com') False Given a text email address, the user manager can find the user that controls that address. - >>> usermgr.get_user('zperson@example.com') is user_1 + >>> usermgr.get_user(u'zperson@example.com') is user_1 True - >>> usermgr.get_user('zperson@example.net') is user_1 + >>> usermgr.get_user(u'zperson@example.net') is user_1 True - >>> usermgr.get_user('zperson@example.org') is user_1 + >>> usermgr.get_user(u'zperson@example.org') is user_1 True - >>> print usermgr.get_user('bperson@example.com') + >>> print usermgr.get_user(u'bperson@example.com') None Addresses can also be unlinked from a user. >>> user_1.unlink(address_1) - >>> user_1.controls('zperson@example.net') + >>> user_1.controls(u'zperson@example.net') False - >>> print usermgr.get_user('aperson@example.net') + >>> print usermgr.get_user(u'aperson@example.net') None But don't try to unlink the address from a user it's not linked to. @@ -141,11 +136,10 @@ Some of these preferences are booleans and they can be set to True or False. >>> from Mailman.constants import DeliveryMode >>> prefs = user_1.preferences >>> prefs.acknowledge_posts = True - >>> prefs.preferred_language = 'it' + >>> prefs.preferred_language = u'it' >>> prefs.receive_list_copy = False >>> prefs.receive_own_postings = False >>> prefs.delivery_mode = DeliveryMode.regular - >>> flush() >>> show_prefs(user_1.preferences) acknowledge_posts : True preferred_language : it |
