diff options
-rw-r--r-- | Doc/library/mailbox.rst | 127 | ||||
-rwxr-xr-x | Lib/mailbox.py | 178 | ||||
-rw-r--r-- | Lib/test/test_mailbox.py | 15 |
3 files changed, 1 insertions, 319 deletions
diff --git a/Doc/library/mailbox.rst b/Doc/library/mailbox.rst index f76c97a..6db68ee 100644 --- a/Doc/library/mailbox.rst +++ b/Doc/library/mailbox.rst @@ -1501,133 +1501,6 @@ The following exception classes are defined in the :mod:`mailbox` module: instance attempts to read a corrupted :file:`.mh_sequences` file. -.. _mailbox-deprecated: - -Deprecated classes and methods ------------------------------- - -Older versions of the :mod:`mailbox` module do not support modification of -mailboxes, such as adding or removing message, and do not provide classes to -represent format-specific message properties. For backward compatibility, the -older mailbox classes are still available, but the newer classes should be used -in preference to them. - -Older mailbox objects support only iteration and provide a single public method: - - -.. method:: oldmailbox.next() - - Return the next message in the mailbox, created with the optional *factory* - argument passed into the mailbox object's constructor. By default this is an - :class:`rfc822.Message` object (see the :mod:`rfc822` module). Depending on the - mailbox implementation the *fp* attribute of this object may be a true file - object or a class instance simulating a file object, taking care of things like - message boundaries if multiple mail messages are contained in a single file, - etc. If no more messages are available, this method returns ``None``. - -Most of the older mailbox classes have names that differ from the current -mailbox class names, except for :class:`Maildir`. For this reason, the new -:class:`Maildir` class defines a :meth:`next` method and its constructor differs -slightly from those of the other new mailbox classes. - -The older mailbox classes whose names are not the same as their newer -counterparts are as follows: - - -.. class:: UnixMailbox(fp[, factory]) - - Access to a classic Unix-style mailbox, where all messages are contained in a - single file and separated by ``From`` (a.k.a. ``From_``) lines. The file object - *fp* points to the mailbox file. The optional *factory* parameter is a callable - that should create new message objects. *factory* is called with one argument, - *fp* by the :meth:`next` method of the mailbox object. The default is the - :class:`rfc822.Message` class (see the :mod:`rfc822` module -- and the note - below). - - .. note:: - - For reasons of this module's internal implementation, you will probably want to - open the *fp* object in binary mode. This is especially important on Windows. - - For maximum portability, messages in a Unix-style mailbox are separated by any - line that begins exactly with the string ``'From '`` (note the trailing space) - if preceded by exactly two newlines. Because of the wide-range of variations in - practice, nothing else on the ``From_`` line should be considered. However, the - current implementation doesn't check for the leading two newlines. This is - usually fine for most applications. - - The :class:`UnixMailbox` class implements a more strict version of ``From_`` - line checking, using a regular expression that usually correctly matched - ``From_`` delimiters. It considers delimiter line to be separated by ``From - name time`` lines. For maximum portability, use the - :class:`PortableUnixMailbox` class instead. This class is identical to - :class:`UnixMailbox` except that individual messages are separated by only - ``From`` lines. - - -.. class:: PortableUnixMailbox(fp[, factory]) - - A less-strict version of :class:`UnixMailbox`, which considers only the ``From`` - at the beginning of the line separating messages. The "*name* *time*" portion - of the From line is ignored, to protect against some variations that are - observed in practice. This works since lines in the message which begin with - ``'From '`` are quoted by mail handling software at delivery-time. - - -.. class:: MmdfMailbox(fp[, factory]) - - Access an MMDF-style mailbox, where all messages are contained in a single file - and separated by lines consisting of 4 control-A characters. The file object - *fp* points to the mailbox file. Optional *factory* is as with the - :class:`UnixMailbox` class. - - -.. class:: MHMailbox(dirname[, factory]) - - Access an MH mailbox, a directory with each message in a separate file with a - numeric name. The name of the mailbox directory is passed in *dirname*. - *factory* is as with the :class:`UnixMailbox` class. - - -.. class:: BabylMailbox(fp[, factory]) - - Access a Babyl mailbox, which is similar to an MMDF mailbox. In Babyl format, - each message has two sets of headers, the *original* headers and the *visible* - headers. The original headers appear before a line containing only ``'*** EOOH - ***'`` (End-Of-Original-Headers) and the visible headers appear after the - ``EOOH`` line. Babyl-compliant mail readers will show you only the visible - headers, and :class:`BabylMailbox` objects will return messages containing only - the visible headers. You'll have to do your own parsing of the mailbox file to - get at the original headers. Mail messages start with the EOOH line and end - with a line containing only ``'\037\014'``. *factory* is as with the - :class:`UnixMailbox` class. - -If you wish to use the older mailbox classes with the :mod:`email` module rather -than the deprecated :mod:`rfc822` module, you can do so as follows:: - - import email - import email.Errors - import mailbox - - def msgfactory(fp): - try: - return email.message_from_file(fp) - except email.Errors.MessageParseError: - # Don't return None since that will - # stop the mailbox iterator - return '' - - mbox = mailbox.UnixMailbox(fp, msgfactory) - -Alternatively, if you know your mailbox contains only well-formed MIME messages, -you can simplify this to:: - - import email - import mailbox - - mbox = mailbox.UnixMailbox(fp, email.message_from_file) - - .. _mailbox-examples: Examples diff --git a/Lib/mailbox.py b/Lib/mailbox.py index 3ee9cbe..a12f478 100755 --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -1925,184 +1925,6 @@ def _sync_close(f): _sync_flush(f) f.close() -## Start: classes from the original module (for backward compatibility). - -# Note that the Maildir class, whose name is unchanged, itself offers a next() -# method for backward compatibility. - -class _Mailbox: - - def __init__(self, fp, factory=rfc822.Message): - self.fp = fp - self.seekp = 0 - self.factory = factory - - def __iter__(self): - return iter(self.next, None) - - def next(self): - while 1: - self.fp.seek(self.seekp) - try: - self._search_start() - except EOFError: - self.seekp = self.fp.tell() - return None - start = self.fp.tell() - self._search_end() - self.seekp = stop = self.fp.tell() - if start != stop: - break - return self.factory(_PartialFile(self.fp, start, stop)) - -# Recommended to use PortableUnixMailbox instead! -class UnixMailbox(_Mailbox): - - def _search_start(self): - while 1: - pos = self.fp.tell() - line = self.fp.readline() - if not line: - raise EOFError - if line[:5] == 'From ' and self._isrealfromline(line): - self.fp.seek(pos) - return - - def _search_end(self): - self.fp.readline() # Throw away header line - while 1: - pos = self.fp.tell() - line = self.fp.readline() - if not line: - return - if line[:5] == 'From ' and self._isrealfromline(line): - self.fp.seek(pos) - return - - # An overridable mechanism to test for From-line-ness. You can either - # specify a different regular expression or define a whole new - # _isrealfromline() method. Note that this only gets called for lines - # starting with the 5 characters "From ". - # - # BAW: According to - #http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.html - # the only portable, reliable way to find message delimiters in a BSD (i.e - # Unix mailbox) style folder is to search for "\n\nFrom .*\n", or at the - # beginning of the file, "^From .*\n". While _fromlinepattern below seems - # like a good idea, in practice, there are too many variations for more - # strict parsing of the line to be completely accurate. - # - # _strict_isrealfromline() is the old version which tries to do stricter - # parsing of the From_ line. _portable_isrealfromline() simply returns - # true, since it's never called if the line doesn't already start with - # "From ". - # - # This algorithm, and the way it interacts with _search_start() and - # _search_end() may not be completely correct, because it doesn't check - # that the two characters preceding "From " are \n\n or the beginning of - # the file. Fixing this would require a more extensive rewrite than is - # necessary. For convenience, we've added a PortableUnixMailbox class - # which does no checking of the format of the 'From' line. - - _fromlinepattern = (r"From \s*[^\s]+\s+\w\w\w\s+\w\w\w\s+\d?\d\s+" - r"\d?\d:\d\d(:\d\d)?(\s+[^\s]+)?\s+\d\d\d\d\s*" - r"[^\s]*\s*" - "$") - _regexp = None - - def _strict_isrealfromline(self, line): - if not self._regexp: - import re - self._regexp = re.compile(self._fromlinepattern) - return self._regexp.match(line) - - def _portable_isrealfromline(self, line): - return True - - _isrealfromline = _strict_isrealfromline - - -class PortableUnixMailbox(UnixMailbox): - _isrealfromline = UnixMailbox._portable_isrealfromline - - -class MmdfMailbox(_Mailbox): - - def _search_start(self): - while 1: - line = self.fp.readline() - if not line: - raise EOFError - if line[:5] == '\001\001\001\001\n': - return - - def _search_end(self): - while 1: - pos = self.fp.tell() - line = self.fp.readline() - if not line: - return - if line == '\001\001\001\001\n': - self.fp.seek(pos) - return - - -class MHMailbox: - - def __init__(self, dirname, factory=rfc822.Message): - import re - pat = re.compile('^[1-9][0-9]*$') - self.dirname = dirname - # the three following lines could be combined into: - # list = map(long, filter(pat.match, os.listdir(self.dirname))) - list = os.listdir(self.dirname) - list = filter(pat.match, list) - list = map(int, list) - list.sort() - # This only works in Python 1.6 or later; - # before that str() added 'L': - self.boxes = map(str, list) - self.boxes.reverse() - self.factory = factory - - def __iter__(self): - return iter(self.next, None) - - def next(self): - if not self.boxes: - return None - fn = self.boxes.pop() - fp = open(os.path.join(self.dirname, fn), newline='') - msg = self.factory(fp) - try: - msg._mh_msgno = fn - except (AttributeError, TypeError): - pass - return msg - - -class BabylMailbox(_Mailbox): - - def _search_start(self): - while 1: - line = self.fp.readline() - if not line: - raise EOFError - if line == '*** EOOH ***\n': - return - - def _search_end(self): - while 1: - pos = self.fp.tell() - line = self.fp.readline() - if not line: - return - if line == '\037\014\n' or line == '\037': - self.fp.seek(pos) - return - -## End: classes from the original module (for backward compatibility). - class Error(Exception): """Raised for module-specific errors.""" diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py index bc77621..e14516d 100644 --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -1768,20 +1768,7 @@ class MaildirTestCase(unittest.TestCase): self.assert_(self.mbox.next() is None) self.assert_(self.mbox.next() is None) - def test_unix_mbox(self): - ### should be better! - import email.parser - fname = self.createMessage("cur", True) - n = 0 - for msg in mailbox.PortableUnixMailbox(open(fname), - email.parser.Parser().parse): - n += 1 - self.assertEqual(msg["subject"], "Simple Test") - # XXX Disabled until we figure out how to fix this - ##self.assertEqual(len(str(msg)), len(FROM_)+len(DUMMY_MESSAGE)) - self.assertEqual(n, 1) - -## End: classes from the original module (for backward compatibility). +## End: tests from the original module (for backward compatibility). _sample_message = """\ |