--- mailbox.py.copyback 2007-01-06 13:46:24.000000000 +0000 +++ mailbox.py 2007-01-06 13:50:34.000000000 +0000 @@ -512,51 +512,61 @@ self._file = f self._toc = None self._next_key = 0 + self._user_toc = {} + self._next_user_key = 0 self._pending = False # No changes require rewriting the file. self._locked = False self._file_length = None # Used to record mailbox size + def _add_to_user_toc(self, value): + self._user_toc[self._next_user_key] = value + self._next_user_key += 1 + def add(self, message): """Add message and return assigned key.""" self._lookup() self._toc[self._next_key] = self._append_message(message) + self._add_to_user_toc(self._next_key) self._next_key += 1 self._pending = True - return self._next_key - 1 + return self._next_user_key - 1 def remove(self, key): """Remove the keyed message; raise KeyError if it doesn't exist.""" self._lookup(key) - del self._toc[key] + del self._user_toc[key] self._pending = True def __setitem__(self, key, message): """Replace the keyed message; raise KeyError if it doesn't exist.""" self._lookup(key) - self._toc[key] = self._append_message(message) + self._toc[self._next_key] = self._append_message(message) + self._user_toc[key] = self._next_key + self._next_key += 1 self._pending = True def iterkeys(self): """Return an iterator over keys.""" self._lookup() - for key in self._toc.keys(): + for key in self._user_toc.keys(): yield key def has_key(self, key): """Return True if the keyed message exists, False otherwise.""" self._lookup() - return key in self._toc + return key in self._user_toc def __len__(self): """Return a count of messages in the mailbox.""" self._lookup() - return len(self._toc) + return len(self._user_toc) def lock(self): """Lock the mailbox.""" if not self._locked: _lock_file(self._file) self._locked = True + self._update_toc() def unlock(self): """Unlock the mailbox if it is locked.""" @@ -590,9 +600,11 @@ new_file = _create_temporary(self._path) try: new_toc = {} + new_user_toc = {} self._pre_mailbox_hook(new_file) - for key in sorted(self._toc.keys()): - start, stop = self._toc[key] + seqno = 0 + for key in sorted(self._user_toc.keys()): + start, stop = self._toc[self._user_toc[key]] self._file.seek(start) self._pre_message_hook(new_file) new_start = new_file.tell() @@ -602,7 +614,9 @@ if buffer == '': break new_file.write(buffer) - new_toc[key] = (new_start, new_file.tell()) + new_toc[seqno] = (new_start, new_file.tell()) + new_user_toc[key] = seqno + seqno += 1 self._post_message_hook(new_file) new_size = new_file.tell() _sync_flush(new_file) @@ -629,6 +643,7 @@ if hasattr(self._file, 'truncate'): self._file.truncate(new_size) self._toc = new_toc + self._user_toc = new_user_toc _sync_flush(self._file) remove_temp_file = True self._pending = False @@ -642,6 +657,7 @@ orig_file.close() if self._locked: _lock_file(self._file, dotlock=False) + self._update_toc() def _pre_mailbox_hook(self, f): """Called before writing the mailbox to file f.""" @@ -665,13 +681,26 @@ def _lookup(self, key=None): """Return (start, stop) or raise KeyError.""" if self._toc is None: - self._generate_toc() + self._update_toc() if key is not None: try: - return self._toc[key] + return self._toc[self._user_toc[key]] except KeyError: raise KeyError('No message with key: %s' % key) + def _update_toc(self): + """Update self._toc and self._user_toc from contents of file.""" + old_toc = self._toc or {} + self._toc = None + self._next_key = 0 # Subclasses might expect this? + self._generate_toc() + for key, value in self._user_toc.items(): + if value not in self._toc: + del self._user_toc[key] + for key in sorted(self._toc.keys()): + if key not in old_toc: + self._add_to_user_toc(key) + def _append_message(self, message): """Append message to mailbox and return (start, stop) offsets.""" self._file.seek(0, 2)