mirror of
https://github.com/python/cpython.git
synced 2025-12-03 16:19:41 +00:00
[Part of bug #1599254] Add suggestion to Mailbox docs to use Maildir, and warn user to lock/unlock mailboxes when modifying them
This commit is contained in:
parent
2e07810ef0
commit
3ffcfe2f68
1 changed files with 57 additions and 25 deletions
|
|
@ -25,22 +25,29 @@ Maildir, mbox, MH, Babyl, and MMDF.
|
||||||
A mailbox, which may be inspected and modified.
|
A mailbox, which may be inspected and modified.
|
||||||
\end{classdesc*}
|
\end{classdesc*}
|
||||||
|
|
||||||
|
The \class{Mailbox} class defines an interface and
|
||||||
|
is not intended to be instantiated. Instead, format-specific
|
||||||
|
subclasses should inherit from \class{Mailbox} and your code
|
||||||
|
should instantiate a particular subclass.
|
||||||
|
|
||||||
The \class{Mailbox} interface is dictionary-like, with small keys
|
The \class{Mailbox} interface is dictionary-like, with small keys
|
||||||
corresponding to messages. Keys are issued by the \class{Mailbox} instance
|
corresponding to messages. Keys are issued by the \class{Mailbox}
|
||||||
with which they will be used and are only meaningful to that \class{Mailbox}
|
instance with which they will be used and are only meaningful to that
|
||||||
instance. A key continues to identify a message even if the corresponding
|
\class{Mailbox} instance. A key continues to identify a message even
|
||||||
message is modified, such as by replacing it with another message. Messages may
|
if the corresponding message is modified, such as by replacing it with
|
||||||
be added to a \class{Mailbox} instance using the set-like method
|
another message.
|
||||||
\method{add()} and removed using a \code{del} statement or the set-like methods
|
|
||||||
\method{remove()} and \method{discard()}.
|
Messages may be added to a \class{Mailbox} instance using the set-like
|
||||||
|
method \method{add()} and removed using a \code{del} statement or the
|
||||||
|
set-like methods \method{remove()} and \method{discard()}.
|
||||||
|
|
||||||
\class{Mailbox} interface semantics differ from dictionary semantics in some
|
\class{Mailbox} interface semantics differ from dictionary semantics in some
|
||||||
noteworthy ways. Each time a message is requested, a new representation
|
noteworthy ways. Each time a message is requested, a new
|
||||||
(typically a \class{Message} instance) is generated, based upon the current
|
representation (typically a \class{Message} instance) is generated
|
||||||
state of the mailbox. Similarly, when a message is added to a \class{Mailbox}
|
based upon the current state of the mailbox. Similarly, when a message
|
||||||
instance, the provided message representation's contents are copied. In neither
|
is added to a \class{Mailbox} instance, the provided message
|
||||||
case is a reference to the message representation kept by the \class{Mailbox}
|
representation's contents are copied. In neither case is a reference
|
||||||
instance.
|
to the message representation kept by the \class{Mailbox} instance.
|
||||||
|
|
||||||
The default \class{Mailbox} iterator iterates over message representations, not
|
The default \class{Mailbox} iterator iterates over message representations, not
|
||||||
keys as the default dictionary iterator does. Moreover, modification of a
|
keys as the default dictionary iterator does. Moreover, modification of a
|
||||||
|
|
@ -51,9 +58,14 @@ skipped, though using a key from an iterator may result in a
|
||||||
\exception{KeyError} exception if the corresponding message is subsequently
|
\exception{KeyError} exception if the corresponding message is subsequently
|
||||||
removed.
|
removed.
|
||||||
|
|
||||||
\class{Mailbox} itself is intended to define an interface and to be inherited
|
Be very cautious when modifying mailboxes that might also be changed
|
||||||
from by format-specific subclasses but is not intended to be instantiated.
|
by some other process. The safest mailbox format to use for such
|
||||||
Instead, you should instantiate a subclass.
|
tasks is Maildir; try to avoid using single-file formats such as mbox
|
||||||
|
for concurrent writing. If you're modifying a mailbox, no matter what
|
||||||
|
the format, you must lock it by calling the \method{lock()} and
|
||||||
|
\method{unlock()} methods before making any changes. Failing to lock
|
||||||
|
the mailbox runs the risk of losing data if some other process makes
|
||||||
|
changes to the mailbox while your Python code is running.
|
||||||
|
|
||||||
\class{Mailbox} instances have the following methods:
|
\class{Mailbox} instances have the following methods:
|
||||||
|
|
||||||
|
|
@ -202,15 +214,16 @@ general it is incorrect for \var{arg} to be a \class{Mailbox} instance.
|
||||||
|
|
||||||
\begin{methoddesc}{flush}{}
|
\begin{methoddesc}{flush}{}
|
||||||
Write any pending changes to the filesystem. For some \class{Mailbox}
|
Write any pending changes to the filesystem. For some \class{Mailbox}
|
||||||
subclasses, changes are always written immediately and this method does
|
subclasses, changes are always written immediately and \method{flush()} does
|
||||||
nothing.
|
nothing, but you should still make a habit of calling this method.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{lock}{}
|
\begin{methoddesc}{lock}{}
|
||||||
Acquire an exclusive advisory lock on the mailbox so that other processes know
|
Acquire an exclusive advisory lock on the mailbox so that other processes know
|
||||||
not to modify it. An \exception{ExternalClashError} is raised if the lock is
|
not to modify it. An \exception{ExternalClashError} is raised if the lock is
|
||||||
not available. The particular locking mechanisms used depend upon the mailbox
|
not available. The particular locking mechanisms used depend upon the mailbox
|
||||||
format.
|
format. You should \emph{always} lock the mailbox before making any
|
||||||
|
modifications to its contents.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{unlock}{}
|
\begin{methoddesc}{unlock}{}
|
||||||
|
|
@ -1373,36 +1386,55 @@ of the format-specific information that can be converted:
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
import mailbox
|
import mailbox
|
||||||
destination = mailbox.MH('~/Mail')
|
destination = mailbox.MH('~/Mail')
|
||||||
|
destination.lock()
|
||||||
for message in mailbox.Babyl('~/RMAIL'):
|
for message in mailbox.Babyl('~/RMAIL'):
|
||||||
destination.add(MHMessage(message))
|
destination.add(MHMessage(message))
|
||||||
|
destination.flush()
|
||||||
|
destination.unlock()
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
An example of sorting mail from numerous mailing lists, being careful to avoid
|
This example sorts mail from several mailing lists into different
|
||||||
mail corruption due to concurrent modification by other programs, mail loss due
|
mailboxes, being careful to avoid mail corruption due to concurrent
|
||||||
to interruption of the program, or premature termination due to malformed
|
modification by other programs, mail loss due to interruption of the
|
||||||
messages in the mailbox:
|
program, or premature termination due to malformed messages in the
|
||||||
|
mailbox:
|
||||||
|
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
import mailbox
|
import mailbox
|
||||||
import email.Errors
|
import email.Errors
|
||||||
|
|
||||||
list_names = ('python-list', 'python-dev', 'python-bugs')
|
list_names = ('python-list', 'python-dev', 'python-bugs')
|
||||||
|
|
||||||
boxes = dict((name, mailbox.mbox('~/email/%s' % name)) for name in list_names)
|
boxes = dict((name, mailbox.mbox('~/email/%s' % name)) for name in list_names)
|
||||||
inbox = mailbox.Maildir('~/Maildir', None)
|
inbox = mailbox.Maildir('~/Maildir', factory=None)
|
||||||
|
|
||||||
for key in inbox.iterkeys():
|
for key in inbox.iterkeys():
|
||||||
try:
|
try:
|
||||||
message = inbox[key]
|
message = inbox[key]
|
||||||
except email.Errors.MessageParseError:
|
except email.Errors.MessageParseError:
|
||||||
continue # The message is malformed. Just leave it.
|
continue # The message is malformed. Just leave it.
|
||||||
|
|
||||||
for name in list_names:
|
for name in list_names:
|
||||||
list_id = message['list-id']
|
list_id = message['list-id']
|
||||||
if list_id and name in list_id:
|
if list_id and name in list_id:
|
||||||
|
# Get mailbox to use
|
||||||
box = boxes[name]
|
box = boxes[name]
|
||||||
|
|
||||||
|
# Write copy to disk before removing original.
|
||||||
|
# If there's a crash, you might duplicate a message, but
|
||||||
|
# that's better than losing a message completely.
|
||||||
box.lock()
|
box.lock()
|
||||||
box.add(message)
|
box.add(message)
|
||||||
box.flush() # Write copy to disk before removing original.
|
box.flush()
|
||||||
box.unlock()
|
box.unlock()
|
||||||
|
|
||||||
|
# Remove original message
|
||||||
|
inbox.lock()
|
||||||
inbox.discard(key)
|
inbox.discard(key)
|
||||||
|
inbox.flush()
|
||||||
|
inbox.unlock()
|
||||||
break # Found destination, so stop looking.
|
break # Found destination, so stop looking.
|
||||||
|
|
||||||
for box in boxes.itervalues():
|
for box in boxes.itervalues():
|
||||||
box.close()
|
box.close()
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue