diff options
| author | Petri Lehtinen <petri@digip.org> | 2012-09-25 19:00:32 (GMT) | 
|---|---|---|
| committer | Petri Lehtinen <petri@digip.org> | 2012-09-25 19:02:06 (GMT) | 
| commit | f39884bb5a01c3fa9db74833d2d8a05bf0530315 (patch) | |
| tree | f79b3eeaaac3713727c6e7c6f5d1828d571e47e3 /Lib/mailbox.py | |
| parent | 468091954f9e9d46e9d4c7673a37ccb3b3b03eb5 (diff) | |
| download | cpython-f39884bb5a01c3fa9db74833d2d8a05bf0530315.zip cpython-f39884bb5a01c3fa9db74833d2d8a05bf0530315.tar.gz cpython-f39884bb5a01c3fa9db74833d2d8a05bf0530315.tar.bz2  | |
#15222: Insert blank line after each message in mbox mailboxes
Diffstat (limited to 'Lib/mailbox.py')
| -rw-r--r-- | Lib/mailbox.py | 44 | 
1 files changed, 38 insertions, 6 deletions
diff --git a/Lib/mailbox.py b/Lib/mailbox.py index 282c055..c73fb95 100644 --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -208,6 +208,9 @@ class Mailbox:              raise ValueError("String input must be ASCII-only; "                  "use bytes or a Message instead") +    # Whether each message must end in a newline +    _append_newline = False +      def _dump_message(self, message, target, mangle_from_=False):          # This assumes the target file is open in binary mode.          """Dump message contents to target file.""" @@ -219,6 +222,9 @@ class Mailbox:              data = buffer.read()              data = data.replace(b'\n', linesep)              target.write(data) +            if self._append_newline and not data.endswith(linesep): +                # Make sure the message ends with a newline +                target.write(linesep)          elif isinstance(message, (str, bytes, io.StringIO)):              if isinstance(message, io.StringIO):                  warnings.warn("Use of StringIO input is deprecated, " @@ -230,11 +236,15 @@ class Mailbox:                  message = message.replace(b'\nFrom ', b'\n>From ')              message = message.replace(b'\n', linesep)              target.write(message) +            if self._append_newline and not message.endswith(linesep): +                # Make sure the message ends with a newline +                target.write(linesep)          elif hasattr(message, 'read'):              if hasattr(message, 'buffer'):                  warnings.warn("Use of text mode files is deprecated, "                      "use a binary mode file instead", DeprecationWarning, 3)                  message = message.buffer +            lastline = None              while True:                  line = message.readline()                  # Universal newline support. @@ -248,6 +258,10 @@ class Mailbox:                      line = b'>From ' + line[5:]                  line = line.replace(b'\n', linesep)                  target.write(line) +                lastline = line +            if self._append_newline and lastline and not lastline.endswith(linesep): +                # Make sure the message ends with a newline +                target.write(linesep)          else:              raise TypeError('Invalid message type: %s' % type(message)) @@ -833,30 +847,48 @@ class mbox(_mboxMMDF):      _mangle_from_ = True +    # All messages must end in a newline character, and +    # _post_message_hooks outputs an empty line between messages. +    _append_newline = True +      def __init__(self, path, factory=None, create=True):          """Initialize an mbox mailbox."""          self._message_factory = mboxMessage          _mboxMMDF.__init__(self, path, factory, create) -    def _pre_message_hook(self, f): -        """Called before writing each message to file f.""" -        if f.tell() != 0: -            f.write(linesep) +    def _post_message_hook(self, f): +        """Called after writing each message to file f.""" +        f.write(linesep)      def _generate_toc(self):          """Generate key-to-(start, stop) table of contents."""          starts, stops = [], [] +        last_was_empty = False          self._file.seek(0)          while True:              line_pos = self._file.tell()              line = self._file.readline()              if line.startswith(b'From '):                  if len(stops) < len(starts): -                    stops.append(line_pos - len(linesep)) +                    if last_was_empty: +                        stops.append(line_pos - len(linesep)) +                    else: +                        # The last line before the "From " line wasn't +                        # blank, but we consider it a start of a +                        # message anyway. +                        stops.append(line_pos)                  starts.append(line_pos) +                last_was_empty = False              elif not line: -                stops.append(line_pos) +                if last_was_empty: +                    stops.append(line_pos - len(linesep)) +                else: +                    stops.append(line_pos)                  break +            elif line == linesep: +                last_was_empty = True +            else: +                last_was_empty = False          self._toc = dict(enumerate(zip(starts, stops)))          self._next_key = len(self._toc)          self._file_length = self._file.tell()  | 
