[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%s037円' % (os.linesep, os.linesep))
- # XXX: write "Labels:" line too
+ f.write('BABYL OPTIONS:\nVersion: 5\nLabels:%s\n037円' %
+ ','.join(self.get_labels()))
 
 def _pre_message_hook(self, f):
 """Called before writing each message to file f."""
@@ -1116,9 +1160,25 @@
 f.write('\n037円')
 
 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

AltStyle によって変換されたページ (->オリジナル) /