[Python-checkins] python/nondist/sandbox/mailbox mailbox.py, 1.9, 1.10 libmailbox.tex, 1.10, 1.11 test_mailbox.py, 1.7, 1.8
gregorykjohnson@users.sourceforge.net
gregorykjohnson at users.sourceforge.net
Wed Aug 17 01:38:22 CEST 2005
Update of /cvsroot/python/python/nondist/sandbox/mailbox
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2326
Modified Files:
mailbox.py libmailbox.tex test_mailbox.py
Log Message:
* Add delivery date support to MaildirMessage and Maildir, and support
for conversion between delivery dates in MaildirMessage, mboxMessage,
and MMDFMessage instances.
* Don't guess delivery dates from headers.
* Add full support for labels to Babyl.
* Small tweaks:
* Remove outdated "start, stop, ..." mentions in comments.
* Change exception raising style: use "Exception(...)" instead of
"Exception, ..." in accordance with Raymond Hettinger's comment in
the Python Tutorial and A.M. Kuchling's recent post on python-dev.
* Use ": %s" consistently in exception messages, not " '%s'".
Index: mailbox.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- mailbox.py 16 Aug 2005 17:12:03 -0000 1.9
+++ mailbox.py 16 Aug 2005 23:38:11 -0000 1.10
@@ -4,6 +4,7 @@
import os
import time
+import calendar
import socket
import errno
import stat
@@ -33,11 +34,11 @@
def add(self, message):
"""Add message and return assigned key."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def remove(self, key):
"""Remove the keyed message; raise KeyError if it doesn't exist."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def __delitem__(self, key):
self.remove(key)
@@ -51,7 +52,7 @@
def __setitem__(self, key, message):
"""Replace the keyed message; raise KeyError if it doesn't exist."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def get(self, key, default=None):
"""Return the keyed message, or default if it doesn't exist."""
@@ -69,19 +70,19 @@
def get_message(self, key):
"""Return a Message representation or raise a KeyError."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def get_string(self, key):
"""Return a string representation or raise a KeyError."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def get_file(self, key):
"""Return a file-like representation or raise a KeyError."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def iterkeys(self):
"""Return an iterator over keys."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def keys(self):
"""Return a list of keys."""
@@ -118,14 +119,14 @@
def has_key(self, key):
"""Return True if the keyed message exists, False otherwise."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def __contains__(self, key):
return self.has_key(key)
def __len__(self):
"""Return a count of messages in the mailbox."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def clear(self):
"""Delete all messages."""
@@ -146,7 +147,7 @@
for key in self.iterkeys():
return (key, self.pop(key)) # This is only run once.
else:
- raise KeyError, "No messages in mailbox"
+ raise KeyError('No messages in mailbox')
def update(self, arg=None):
"""Change the messages that correspond to certain keys."""
@@ -163,23 +164,23 @@
except KeyError:
bad_key = True
if bad_key:
- raise KeyError, "No message with key(s)"
+ raise KeyError('No message with key(s)')
def flush(self):
"""Write any pending changes to the disk."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def lock(self):
"""Lock the mailbox."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def unlock(self, f=None):
"""Unlock the mailbox if it is locked."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def close(self):
"""Flush and close the mailbox."""
- raise NotImplementedError, "Method must be implemented by subclass"
+ raise NotImplementedError('Method must be implemented by subclass')
def _dump_message(self, message, target):
"""Dump message contents to target file."""
@@ -195,7 +196,7 @@
break
target.write(buffer)
else:
- raise TypeError, "Invalid message type"
+ raise TypeError('Invalid message type: %s' % type(message))
class Maildir(Mailbox):
@@ -211,7 +212,7 @@
os.mkdir(os.path.join(self._path, 'new'), 0700)
os.mkdir(os.path.join(self._path, 'cur'), 0700)
else:
- raise NoSuchMailboxError, self._path
+ raise NoSuchMailboxError(self._path)
self._toc = {}
def add(self, message):
@@ -232,6 +233,8 @@
uniq = os.path.basename(tmp_file.name).split(':')[0]
dest = os.path.join(self._path, subdir, uniq + suffix)
os.rename(tmp_file.name, dest)
+ if isinstance(message, MaildirMessage):
+ os.utime(dest, (os.path.getatime(dest), message.get_date()))
return uniq
def remove(self, key):
@@ -268,9 +271,11 @@
else:
suffix = ''
self.discard(key)
- os.rename(os.path.join(self._path, temp_subpath),
- os.path.join(self._path, subdir, key + suffix))
- # XXX: the mtime should be reset to keep delivery date
+ new_path = os.path.join(self._path, subdir, key + suffix)
+ os.rename(os.path.join(self._path, temp_subpath), new_path)
+ if isinstance(message, MaildirMessage):
+ os.utime(new_path, (os.path.getatime(new_path),
+ message.get_date()))
def get_message(self, key):
"""Return a Message representation or raise a KeyError."""
@@ -284,6 +289,7 @@
msg.set_subdir(subdir)
if ':' in name:
msg.set_info(name.split(':')[-1])
+ msg.set_date(os.path.getmtime(os.path.join(self._path, subpath)))
return msg
def get_string(self, key):
@@ -363,12 +369,12 @@
for entry in os.listdir(os.path.join(path, 'new')) + \
os.listdir(os.path.join(path, 'cur')):
if len(entry) < 1 or entry[0] != '.':
- raise NotEmptyError, "Folder '%s' contains message" % folder
+ raise NotEmptyError('Folder contains message(s): %s' % folder)
for entry in os.listdir(path):
if entry != 'new' and entry != 'cur' and entry != 'tmp' and \
os.path.isdir(os.path.join(path, entry)):
- raise NotEmptyError, "Folder '%s' contains subdirectory '%s'" \
- % (folder, entry)
+ raise NotEmptyError("Folder contains subdirectory '%s': %s" %
+ (folder, entry))
for root, dirs, files in os.walk(path, topdown=False):
for entry in files:
os.remove(os.path.join(root, entry))
@@ -406,8 +412,8 @@
else:
raise
else:
- raise ExternalClashError, \
- "Name clash prevented file creation: '%s'" % path
+ raise ExternalClashError('Name clash prevented file creation: %s' %
+ path)
def _refresh(self):
"""Update table of contents mapping."""
@@ -428,7 +434,7 @@
try:
return self._toc[key]
except KeyError:
- raise KeyError, "No message with key '%s'" % key
+ raise KeyError('No message with key: %s' % key)
class _singlefileMailbox(Mailbox):
@@ -444,7 +450,7 @@
if create:
f = file(self._path, 'w+')
else:
- raise NoSuchMailboxError, self._path
+ raise NoSuchMailboxError(self._path)
elif e.errno == errno.EACCES:
f = file(self._path, 'r')
else:
@@ -565,17 +571,17 @@
self._file.close()
def _lookup(self, key=None):
- """Return (start, stop), possibly with more info, or raise KeyError."""
+ """Return (start, stop) or raise KeyError."""
if self._toc is None:
self._generate_toc()
if key is not None:
try:
return self._toc[key]
except KeyError:
- raise KeyError, "No message with key '%s'" % key
+ raise KeyError('No message with key: %s' % key)
def _append_message(self, message):
- """Append message to mailbox and return (start, stop, ...) offsets."""
+ """Append message to mailbox and return (start, stop) offsets."""
self._file.seek(0, 2)
self._pre_message_hook(self._file)
offsets = self._install_message(message)
@@ -629,8 +635,7 @@
elif isinstance(message, email.Message.Message):
from_line = message.get_unixfrom() # May be None.
if from_line is None:
- from_line = 'From MAILER-DAEMON %s' % \
- time.strftime('%a %b %d %H:%M:%S %Y', time.gmtime())
+ from_line = 'From MAILER-DAEMON %s' % time.asctime(time.gmtime())
start = self._file.tell()
self._file.write('%s%s' % (from_line, os.linesep))
self._dump_message(message, self._file)
@@ -724,7 +729,7 @@
os.close(os.open(os.path.join(self._path, '.mh_sequences'),
os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0600))
else:
- raise NoSuchMailboxError, self._path
+ raise NoSuchMailboxError(self._path)
self._locked = False
def add(self, message):
@@ -757,7 +762,7 @@
f = file(path, 'r+')
except IOError, e:
if e.errno == errno.ENOENT:
- raise KeyError, "No message with key '%s'" % key
+ raise KeyError('No message with key: %s' % key)
else:
raise
try:
@@ -779,7 +784,7 @@
f = file(path, 'r+')
except IOError, e:
if e.errno == errno.ENOENT:
- raise KeyError, "No message with key '%s'" % key
+ raise KeyError('No message with key: %s' % key)
else:
raise
try:
@@ -805,7 +810,7 @@
f = file(os.path.join(self._path, str(key)), 'r')
except IOError, e:
if e.errno == errno.ENOENT:
- raise KeyError, "No message with key '%s'" % key
+ raise KeyError('No message with key: %s' % key)
else:
raise
try:
@@ -832,7 +837,7 @@
f = file(os.path.join(self._path, str(key)), 'r')
except IOError, e:
if e.errno == errno.ENOENT:
- raise KeyError, "No message with key '%s'" % key
+ raise KeyError('No message with key: %s' % key)
else:
raise
try:
@@ -852,7 +857,7 @@
f = file(os.path.join(self._path, str(key)), 'r')
except IOError, e:
if e.errno == errno.ENOENT:
- raise KeyError, "No message with key '%s'" % key
+ raise KeyError('No message with key: %s' % key)
else:
raise
return _ProxyFile(f)
@@ -919,8 +924,7 @@
elif entries == []:
pass
else:
- raise NotEmptyError, "Folder '%s' is not empty" % \
- self._path
+ raise NotEmptyError('Folder not empty: %s' % self._path)
os.rmdir(path)
def get_sequences(self):
@@ -942,8 +946,8 @@
results[name] = [key for key in sorted(keys) \
if key in all_keys]
except ValueError:
- raise FormatError, "Invalid sequence specification: " % \
- "'%s'" % line.rstrip()
+ raise FormatError('Invalid sequence specification: %s' %
+ line.rstrip())
finally:
f.close()
return results
@@ -1032,11 +1036,38 @@
class Babyl(_singlefileMailbox):
"""An Rmail-style Babyl mailbox."""
+ _special_labels = frozenset(('unseen', 'deleted', 'filed', 'answered',
+ 'forwarded', 'edited', 'resent'))
+
+ def __init__(self, path, factory=None, create=True):
+ """Initialize a Babyl mailbox."""
+ _singlefileMailbox.__init__(self, path, factory, create)
+ self._labels = {}
+
+ def add(self, message):
+ """Add message and return assigned key."""
+ key = _singlefileMailbox.add(self, message)
+ if isinstance(message, BabylMessage):
+ self._labels[key] = message.get_labels()
+ return key
+
+ def remove(self, key):
+ """Remove the keyed message; raise KeyError if it doesn't exist."""
+ _singlefileMailbox.remove(self, key)
+ if key in self._labels:
+ del self._labels[key]
+
+ def __setitem__(self, key, message):
+ """Replace the keyed message; raise KeyError if it doesn't exist."""
+ _singlefileMailbox.__setitem__(self, key, message)
+ if isinstance(message, BabylMessage):
+ self._labels[key] = message.get_labels()
+
def get_message(self, key):
"""Return a Message representation or raise a KeyError."""
start, stop = self._lookup(key)
self._file.seek(start)
- self._file.readline() # XXX: parse this '1,' line for labels
+ self._file.readline() # Skip '1,' line specifying labels.
original_headers = StringIO.StringIO()
while True:
line = self._file.readline()
@@ -1052,13 +1083,15 @@
body = self._file.read(stop - self._file.tell())
msg = BabylMessage(original_headers.getvalue() + body)
msg.set_visible(visible_headers.getvalue())
+ if key in self._labels:
+ msg.set_labels(self._labels[key])
return msg
def get_string(self, key):
"""Return a string representation or raise a KeyError."""
start, stop = self._lookup(key)
self._file.seek(start)
- self._file.readline() # Skip '1,' line.
+ self._file.readline() # Skip '1,' line specifying labels.
original_headers = StringIO.StringIO()
while True:
line = self._file.readline()
@@ -1078,13 +1111,19 @@
def get_labels(self):
"""Return a list of user-defined labels in the mailbox."""
- raise NotImplementedError, 'Method not yet implemented'
+ self._lookup()
+ labels = set()
+ for label_list in self._labels.values():
+ labels.update(label_list)
+ labels.difference_update(self._special_labels)
+ return list(labels)
def _generate_toc(self):
- """Generate key-to-(start, stop, eooh, body) table of contents."""
+ """Generate key-to-(start, stop) table of contents."""
starts, stops = [], []
self._file.seek(0)
next_pos = 0
+ label_lists = []
while True:
line_pos = next_pos
line = self._file.readline()
@@ -1093,6 +1132,10 @@
if len(stops) < len(starts):
stops.append(line_pos - len(os.linesep))
starts.append(next_pos)
+ labels = [label.strip() for label
+ in self._file.readline()[1:].split(',')
+ if label.strip() != '']
+ label_lists.append(labels)
elif line == '\037' or line == '\037' + os.linesep:
if len(stops) < len(starts):
stops.append(line_pos - len(os.linesep))
@@ -1100,12 +1143,13 @@
stops.append(line_pos - len(os.linesep))
break
self._toc = dict(enumerate(zip(starts, stops)))
+ self._labels = dict(enumerate(label_lists))
self._next_key = len(self._toc)
def _pre_mailbox_hook(self, f):
"""Called before writing the mailbox to file f."""
- f.write('BABYL OPTIONS:%sVersion: 5%s\037' % (os.linesep, os.linesep))
- # XXX: write "Labels:" line too
+ f.write('BABYL OPTIONS:\nVersion: 5\nLabels:%s\n\037' %
+ ','.join(self.get_labels()))
def _pre_message_hook(self, f):
"""Called before writing each message to file f."""
@@ -1116,9 +1160,25 @@
f.write('\n\037')
def _install_message(self, message):
- """Write message contents and return (start, stop, ...)."""
+ """Write message contents and return (start, stop)."""
start = self._file.tell()
- self._file.write('1,,\n') # XXX: check for labels and add them
+ if isinstance(message, BabylMessage):
+ special_labels = []
+ labels = []
+ for label in message.get_labels():
+ if label in self._special_labels:
+ special_labels.append(label)
+ else:
+ labels.append(label)
+ self._file.write('1')
+ for label in special_labels:
+ self._file.write(', ' + label)
+ self._file.write(',,')
+ for label in labels:
+ self._file.write(' ' + label + ',')
+ self._file.write('\n')
+ else:
+ self._file.write('1,,\n')
if isinstance(message, email.Message.Message):
pseudofile = StringIO.StringIO()
ps_generator = email.Generator.Generator(pseudofile, False, 0)
@@ -1175,7 +1235,7 @@
break
self._file.write(buffer)
else:
- raise TypeError, "Invalid message type"
+ raise TypeError('Invalid message type: %s' % type(message))
stop = self._file.tell()
return (start, stop)
@@ -1196,7 +1256,7 @@
elif message is None:
email.Message.Message.__init__(self)
else:
- raise TypeError, "Invalid message type"
+ raise TypeError('Invalid message type: %s' % type(message))
def _become_message(self, message):
"""Assume the non-format-specific state of message."""
@@ -1209,7 +1269,7 @@
if isinstance(message, Message):
return # There's nothing format-specific to explain.
else:
- raise TypeError, "Cannot convert to specified type"
+ raise TypeError('Cannot convert to specified type')
class MaildirMessage(Message):
@@ -1219,6 +1279,7 @@
"""Initialize a MaildirMessage instance."""
self._subdir = 'new'
self._info = ''
+ self._date = time.time()
Message.__init__(self, message)
def get_subdir(self):
@@ -1230,7 +1291,7 @@
if subdir == 'new' or subdir == 'cur':
self._subdir = subdir
else:
- raise ValueError, "subdir must be 'new' or 'cur'"
+ raise ValueError("subdir must be 'new' or 'cur': %s" % subdir)
def get_flags(self):
"""Return as a string the flags that are set."""
@@ -1252,6 +1313,17 @@
if self.get_flags() != '':
self.set_flags(''.join(set(self.get_flags()) - set(flag)))
+ def get_date(self):
+ """Return delivery date of message, in seconds since the epoch."""
+ return self._date
+
+ def set_date(self, date):
+ """Set delivery date of message, in seconds since the epoch."""
+ try:
+ self._date = float(date)
+ except ValueError:
+ raise TypeError("can't convert to float: %s" % date)
+
def get_info(self):
"""Get the message's "info" as a string."""
return self._info
@@ -1261,13 +1333,14 @@
if isinstance(info, str):
self._info = info
else:
- raise TypeError, "info must be a string"
+ raise TypeError('info must be a string: %s' % type(info))
def _explain_to(self, message):
"""Copy Maildir-specific state to message insofar as possible."""
if isinstance(message, MaildirMessage):
message.set_flags(self.get_flags())
message.set_subdir(self.get_subdir())
+ message.set_date(self.get_date())
elif isinstance(message, _mboxMMDFMessage):
flags = set(self.get_flags())
if 'S' in flags:
@@ -1280,6 +1353,7 @@
message.add_flag('F')
if 'R' in flags:
message.add_flag('A')
+ message.set_from('MAILER-DAEMON', time.gmtime(self.get_date()))
elif isinstance(message, MHMessage):
flags = set(self.get_flags())
if 'S' not in flags:
@@ -1301,7 +1375,8 @@
elif isinstance(message, Message):
pass
else:
- raise TypeError, "Cannot convert to specified type"
+ raise TypeError('Cannot convert to specified type: %s' %
+ type(message))
class _mboxMMDFMessage(Message):
@@ -1314,10 +1389,6 @@
unixfrom = message.get_unixfrom()
if unixfrom is not None and unixfrom[:5] == 'From ':
self.set_from(unixfrom[5:])
- elif 'Return-Path' in message:
- # XXX: generate "From " line from Return-Path: and Received:
- pass
-
Message.__init__(self, message)
def get_from(self):
@@ -1329,7 +1400,7 @@
if time_ is not None:
if time_ is True:
time_ = time.gmtime()
- from_ += time.strftime(" %a %b %d %H:%M:%S %Y", time_)
+ from_ += ' ' + time.asctime(time_)
self._from = from_
def get_flags(self):
@@ -1381,6 +1452,14 @@
message.add_flag('S')
if 'D' in flags:
message.add_flag('T')
+ del message['status']
+ del message['x-status']
+ maybe_date = ' '.join(self.get_from().split()[-5:])
+ try:
+ message.set_date(calendar.timegm(time.strptime(maybe_date,
+ '%a %b %d %H:%M:%S %Y')))
+ except ValueError, OverflowError:
+ pass
elif isinstance(message, _mboxMMDFMessage):
message.set_flags(self.get_flags())
message.set_from(self.get_from())
@@ -1392,6 +1471,8 @@
message.add_sequence('replied')
if 'F' in flags:
message.add_sequence('flagged')
+ del message['status']
+ del message['x-status']
elif isinstance(message, BabylMessage):
flags = set(self.get_flags())
if 'R' not in flags:
@@ -1400,10 +1481,13 @@
message.add_label('deleted')
if 'A' in flags:
message.add_label('answered')
+ del message['status']
+ del message['x-status']
elif isinstance(message, Message):
pass
else:
- raise TypeError, "Cannot convert to specified type"
+ raise TypeError('Cannot convert to specified type: %s' %
+ type(message))
class mboxMessage(_mboxMMDFMessage):
@@ -1432,7 +1516,7 @@
if not sequence in self._sequences:
self._sequences.append(sequence)
else:
- raise TypeError, "sequence must be a string"
+ raise TypeError('sequence must be a string: %s' % type(sequence))
def remove_sequence(self, sequence):
"""Remove sequence from the list of sequences including the message."""
@@ -1476,7 +1560,8 @@
elif isinstance(message, Message):
pass
else:
- raise TypeError, "Cannot convert to specified type"
+ raise TypeError('Cannot convert to specified type: %s' %
+ type(message))
class BabylMessage(Message):
@@ -1502,7 +1587,7 @@
if label not in self._labels:
self._labels.append(label)
else:
- raise TypeError, "label must be a string"
+ raise TypeError('label must be a string: %s' % type(label))
def remove_label(self, label):
"""Remove label from the list of labels on the message."""
@@ -1568,7 +1653,8 @@
elif isinstance(message, Message):
pass
else:
- raise TypeError, "Cannot convert to specified type"
+ raise TypeError('Cannot convert to specified type: %s' %
+ type(message))
class MMDFMessage(_mboxMMDFMessage):
@@ -1675,16 +1761,16 @@
fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError, e:
if e.errno == errno.EAGAIN:
- raise ExternalClashError, \
- "lockf: lock unavailable: %s" % f.name
+ raise ExternalClashError('lockf: lock unavailable: %s' %
+ f.name)
else:
raise
try:
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError, e:
if e.errno == errno.EWOULDBLOCK:
- raise ExternalClashError, \
- "flock: lock unavailable: %s" % f.name
+ raise ExternalClashError('flock: lock unavailable: %s' %
+ f.name)
else:
raise
if dotlock:
@@ -1707,8 +1793,8 @@
except OSError, e:
if e.errno == errno.EEXIST:
os.remove(pre_lock)
- raise ExternalClashError, 'dot lock unavailable: %s' % \
- f.name
+ raise ExternalClashError('dot lock unavailable: %s' %
+ f.name)
else:
raise
except:
Index: libmailbox.tex
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- libmailbox.tex 16 Aug 2005 17:12:03 -0000 1.10
+++ libmailbox.tex 16 Aug 2005 23:38:11 -0000 1.11
@@ -720,6 +720,16 @@
current "info" is not modified.
\end{methoddesc}
+\begin{methoddesc}{get_date}{}
+Return the delivery date of the message as a floating-point number representing
+seconds since the epoch.
+\end{methoddesc}
+
+\begin{methoddesc}{set_date}{date}
+Set the delivery date of the message to \var{date}, a floating-point number
+representing seconds since the epoch.
+\end{methoddesc}
+
\begin{methoddesc}{get_info}{}
Return a string containing the "info" for a message. This is useful for
accessing and modifying "info" that is experimental (i.e., not a list of
@@ -807,10 +817,11 @@
\begin{methoddesc}{set_from}{from_\optional{, time_=None}}
Set the "From~" line to \var{from_}, which should be specified without a
-leading "From~" or trailing newline. If \var{time_} is specified, it should be
-a \class{struct_time} or a tuple suitable for passing to
-\method{time.strftime()}; if \var{time_} is \code{True}, the result of
-\method{time.gmtime()} is used.
+leading "From~" or trailing newline. For convenience, \var{time_} may be
+specified and will be formatted appropriately and appended to \var{from_}. If
+\var{time_} is specified, it should be a \class{struct_time}, a tuple suitable
+for passing to \method{time.strftime()}, or \code{True} (to use
+\method{time.gmtime()}).
\end{methoddesc}
\begin{methoddesc}{get_flags}{}
@@ -840,7 +851,9 @@
\end{methoddesc}
When an \class{mboxMessage} instance is created based upon a
-\class{MaildirMessage} instance, the following conversions take place:
+\class{MaildirMessage} instance, a "From~" line is generated based upon the
+\class{MaildirMessage} instance's delivery date, and the following conversions
+take place:
\begin{tableii}{l|l}{textrm}
{Resulting state}{\class{MaildirMessage} state}
@@ -1097,10 +1110,11 @@
\begin{methoddesc}{set_from}{from_\optional{, time_=None}}
Set the "From~" line to \var{from_}, which should be specified without a
-leading "From~" or trailing newline. If \var{time_} is specified, it should be
-a \class{struct_time} or a tuple suitable for passing to
-\method{time.strftime()}; if \var{time_} is \code{True}, the result of
-\method{time.gmtime()} is used.
+leading "From~" or trailing newline. For convenience, \var{time_} may be
+specified to format a time appropriately and append it to \var{from_}. If
+\var{time_} is specified, it should be a \class{struct_time}, a tuple suitable
+for passing to \method{time.strftime()}, or \code{True} (to use
+\method{time.gmtime()}).
\end{methoddesc}
\begin{methoddesc}{get_flags}{}
@@ -1130,7 +1144,9 @@
\end{methoddesc}
When an \class{MMDFMessage} instance is created based upon a
-\class{MaildirMessage} instance, the following conversions take place:
+\class{MaildirMessage} instance, a "From~" line is generated based upon the
+\class{MaildirMessage} instance's delivery date, and the following conversions
+take place:
\begin{tableii}{l|l}{textrm}
{Resulting state}{\class{MaildirMessage} state}
Index: test_mailbox.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/test_mailbox.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- test_mailbox.py 13 Aug 2005 22:41:33 -0000 1.7
+++ test_mailbox.py 16 Aug 2005 23:38:11 -0000 1.8
@@ -792,6 +792,13 @@
self.assert_(msg.get_subdir() == 'new')
self._check_sample(msg)
+ def test_date(self):
+ # Use get_date() and set_date()
+ msg = mailbox.MaildirMessage(_sample_message)
+ self.assert_(abs(msg.get_date() - time.time()) < 60)
+ msg.set_date(0.0)
+ self.assert_(msg.get_date() == 0.0)
+
def test_info(self):
# Use get_info() and set_info()
msg = mailbox.MaildirMessage(_sample_message)
@@ -995,10 +1002,12 @@
msg_maildir = mailbox.MaildirMessage(_sample_message)
msg_maildir.set_flags('DFPRST')
msg_maildir.set_subdir('cur')
+ date = msg_maildir.get_date()
msg = mailbox.MaildirMessage(msg_maildir)
self._check_sample(msg)
self.assert_(msg.get_flags() == 'DFPRST')
self.assert_(msg.get_subdir() == 'cur')
+ self.assert_(msg.get_date() == date)
def test_maildir_to_mboxmmdf(self):
# Convert MaildirMessage to mboxmessage and MMDFMessage
@@ -1006,9 +1015,13 @@
('T', 'D'), ('DFPRST', 'RDFA'))
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
msg_maildir = mailbox.MaildirMessage(_sample_message)
+ msg_maildir.set_date(0.0)
for setting, result in pairs:
msg_maildir.set_flags(setting)
- self.assert_(class_(msg_maildir).get_flags() == result)
+ msg = class_(msg_maildir)
+ self.assert_(msg.get_flags() == result)
+ self.assert_(msg.get_from() == 'MAILER-DAEMON %s' %
+ time.asctime(time.gmtime(0.0)))
msg_maildir.set_subdir('cur')
self.assert_(class_(msg_maildir).get_flags() == 'RODFA')
@@ -1039,12 +1052,14 @@
# Convert mboxMessage and MMDFMessage to MaildirMessage
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
msg_mboxMMDF = class_(_sample_message)
+ msg_mboxMMDF.set_from('foo at bar', time.gmtime(0.0))
pairs = (('R', 'S'), ('O', ''), ('D', 'T'), ('F', 'F'), ('A', 'R'),
('RODFA', 'FRST'))
for setting, result in pairs:
msg_mboxMMDF.set_flags(setting)
- self.assert_(mailbox.MaildirMessage(msg_mboxMMDF).get_flags() \
- == result)
+ msg = mailbox.MaildirMessage(msg_mboxMMDF)
+ self.assert_(msg.get_flags() == result)
+ self.assert_(msg.get_date() == 0.0, msg.get_date())
msg_mboxMMDF.set_flags('O')
self.assert_(mailbox.MaildirMessage(msg_mboxMMDF).get_subdir() == \
'cur')
More information about the Python-checkins
mailing list