mirror of
https://github.com/python/cpython.git
synced 2024-12-01 05:45:40 +08:00
#2814: remove deprecated classes from mailbox module. Patch by Humberto Diogenes.
This commit is contained in:
parent
f7fa63dd55
commit
edb978ff63
@ -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
|
||||
|
178
Lib/mailbox.py
178
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."""
|
||||
|
@ -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 = """\
|
||||
|
Loading…
Reference in New Issue
Block a user