[Python-checkins] python/dist/src/Lib/email Charset.py, 1.15, 1.16 Encoders.py, 1.8, 1.9 Errors.py, 1.6, 1.7 FeedParser.py, 1.9, 1.10 Generator.py, 1.23, 1.24 Header.py, 1.29, 1.30 Iterators.py, 1.14, 1.15 MIMEAudio.py, 1.4, 1.5 MIMEBase.py, 1.6, 1.7 MIMEImage.py, 1.6, 1.7 MIMEMessage.py, 1.6, 1.7 MIMEMultipart.py, 1.4, 1.5 MIMENonMultipart.py, 1.2, 1.3 MIMEText.py, 1.8, 1.9 Message.py, 1.37, 1.38 Parser.py, 1.22, 1.23 Utils.py, 1.26, 1.27 __init__.py, 1.32, 1.33 _parseaddr.py, 1.9, 1.10 base64MIME.py, 1.7, 1.8 quopriMIME.py, 1.6, 1.7

bwarsaw at users.sourceforge.net bwarsaw at users.sourceforge.net
Sun Oct 3 05:16:25 CEST 2004


Update of /cvsroot/python/python/dist/src/Lib/email
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32603/Lib/email

Modified Files:
	Charset.py Encoders.py Errors.py FeedParser.py Generator.py 
	Header.py Iterators.py MIMEAudio.py MIMEBase.py MIMEImage.py 
	MIMEMessage.py MIMEMultipart.py MIMENonMultipart.py 
	MIMEText.py Message.py Parser.py Utils.py __init__.py 
	_parseaddr.py base64MIME.py quopriMIME.py 
Log Message:
Big email 3.0 API changes, with updated unit tests and documentation.
Briefly (from the NEWS file):

- Updates for the email package:
  + All deprecated APIs that in email 2.x issued warnings have been removed:
    _encoder argument to the MIMEText constructor, Message.add_payload(),
    Utils.dump_address_pair(), Utils.decode(), Utils.encode()
  + New deprecations: Generator.__call__(), Message.get_type(),
    Message.get_main_type(), Message.get_subtype(), the 'strict' argument to
    the Parser constructor.  These will be removed in email 3.1.
  + Support for Python earlier than 2.3 has been removed (see PEP 291).
  + All defect classes have been renamed to end in 'Defect'.
  + Some FeedParser fixes; also a MultipartInvariantViolationDefect will be
    added to messages that claim to be multipart but really aren't.
  + Updates to documentation.


Index: Charset.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/Charset.py,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- Charset.py	9 May 2004 03:24:43 -0000	1.15
+++ Charset.py	3 Oct 2004 03:16:18 -0000	1.16
@@ -1,18 +1,6 @@
 # Copyright (C) 2001-2004 Python Software Foundation
-# Author: che at debian.org (Ben Gertzfield), barry at python.org (Barry Warsaw)
-
-# XXX The following information needs updating.
-
-# Python 2.3 doesn't come with any Asian codecs by default.  Two packages are
-# currently available and supported as of this writing (30-Dec-2003):
-#
-# CJKCodecs
-# http://cjkpython.i18n.org
-# This package contains Chinese, Japanese, and Korean codecs
-
-# JapaneseCodecs
-# http://www.asahi-net.or.jp/~rd6t-kjym/python
-# Some Japanese users prefer this codec package
+# Author: Ben Gertzfield, Barry Warsaw
+# Contact: email-sig at python.org
 
 import email.base64MIME
 import email.quopriMIME
@@ -21,9 +9,9 @@
 
 
 # Flags for types of header encodings
-QP     = 1   # Quoted-Printable
-BASE64 = 2   # Base64
-SHORTEST = 3 # the shorter of QP and base64, but only for headers
+QP          = 1 # Quoted-Printable
+BASE64      = 2 # Base64
+SHORTEST    = 3 # the shorter of QP and base64, but only for headers
 
 # In "=?charset?q?hello_world?=", the =?, ?q?, and ?= add up to 7
 MISC_LEN = 7
@@ -128,7 +116,7 @@
     documentation for more information.
     """
     if body_enc == SHORTEST:
-        raise ValueError, 'SHORTEST not allowed for body_enc'
+        raise ValueError('SHORTEST not allowed for body_enc')
     CHARSETS[charset] = (header_enc, body_enc, output_charset)
 
 

Index: Encoders.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/Encoders.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- Encoders.py	13 May 2004 22:50:12 -0000	1.8
+++ Encoders.py	3 Oct 2004 03:16:18 -0000	1.9
@@ -1,37 +1,16 @@
 # Copyright (C) 2001-2004 Python Software Foundation
-# Author: barry at python.org (Barry Warsaw)
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
 """Encodings and related functions."""
 
 import base64
+from quopri import encodestring as _encodestring
 
-
-
-# Helpers
-try:
-    from quopri import encodestring as _encodestring
-
-    def _qencode(s):
-        enc = _encodestring(s, quotetabs=1)
-        # Must encode spaces, which quopri.encodestring() doesn't do
-        return enc.replace(' ', '=20')
-except ImportError:
-    # Python 2.1 doesn't have quopri.encodestring()
-    from cStringIO import StringIO
-    import quopri as _quopri
-
-    def _qencode(s):
-        if not s:
-            return s
-        hasnewline = (s[-1] == '\n')
-        infp = StringIO(s)
-        outfp = StringIO()
-        _quopri.encode(infp, outfp, quotetabs=1)
-        # Python 2.x's encode() doesn't encode spaces even when quotetabs==1
-        value = outfp.getvalue().replace(' ', '=20')
-        if not hasnewline and value[-1] == '\n':
-            return value[:-1]
-        return value
+def _qencode(s):
+    enc = _encodestring(s, quotetabs=True)
+    # Must encode spaces, which quopri.encodestring() doesn't do
+    return enc.replace(' ', '=20')
 
 
 def _bencode(s):

Index: Errors.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/Errors.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- Errors.py	9 May 2004 03:26:07 -0000	1.6
+++ Errors.py	3 Oct 2004 03:16:18 -0000	1.7
@@ -1,5 +1,6 @@
 # Copyright (C) 2001-2004 Python Software Foundation
-# Author: barry at python.org (Barry Warsaw)
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
 """email package exception classes."""
 
@@ -33,17 +34,20 @@
     def __init__(self, line=None):
         self.line = line
 
-class NoBoundaryInMultipart(MessageDefect):
+class NoBoundaryInMultipartDefect(MessageDefect):
     """A message claimed to be a multipart but had no boundary parameter."""
 
-class StartBoundaryNotFound(MessageDefect):
+class StartBoundaryNotFoundDefect(MessageDefect):
     """The claimed start boundary was never found."""
 
-class FirstHeaderLineIsContinuation(MessageDefect):
+class FirstHeaderLineIsContinuationDefect(MessageDefect):
     """A message had a continuation line as its first header line."""
 
-class MisplacedEnvelopeHeader(MessageDefect):
+class MisplacedEnvelopeHeaderDefect(MessageDefect):
     """A 'Unix-from' header was found in the middle of a header block."""
 
-class MalformedHeader(MessageDefect):
-    """Found a header that was missing a colon, or was otherwise malformed"""
+class MalformedHeaderDefect(MessageDefect):
+    """Found a header that was missing a colon, or was otherwise malformed."""
+
+class MultipartInvariantViolationDefect(MessageDefect):
+    """A message claimed to be a multipart but no subparts were found."""

Index: FeedParser.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/FeedParser.py,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- FeedParser.py	7 Aug 2004 15:57:51 -0000	1.9
+++ FeedParser.py	3 Oct 2004 03:16:18 -0000	1.10
@@ -1,5 +1,6 @@
 # Copyright (C) 2004 Python Software Foundation
 # Authors: Baxter, Wouters and Warsaw
+# Contact: email-sig at python.org
 
 """FeedParser - An email feed parser.
 
@@ -15,7 +16,7 @@
 The other advantage of this parser is that it will never throw a parsing
 exception.  Instead, when it finds something unexpected, it adds a 'defect' to
 the current message.  Defects are just instances that live on the message
-object's .defect attribute.
+object's .defects attribute.
 """
 
 import re
@@ -100,7 +101,7 @@
         # and the eol character(s).  Gather up a list of lines after
         # re-attaching the newlines.
         lines = []
-        for i in range(len(parts) / 2):
+        for i in range(len(parts) // 2):
             lines.append(parts[i*2] + parts[i*2+1])
         self.pushlines(lines)
 
@@ -156,6 +157,10 @@
         self._call_parse()
         root = self._pop_message()
         assert not self._msgstack
+        # Look for final set of defects
+        if root.get_content_maintype() == 'multipart' \
+               and not root.is_multipart():
+            root.defects.append(Errors.MultipartInvariantViolationDefect())
         return root
 
     def _new_message(self):
@@ -166,7 +171,6 @@
             self._msgstack[-1].attach(msg)
         self._msgstack.append(msg)
         self._cur = msg
-        self._cur.defects = []
         self._last = msg
 
     def _pop_message(self):
@@ -259,7 +263,7 @@
                 # defined a boundary.  That's a problem which we'll handle by
                 # reading everything until the EOF and marking the message as
                 # defective.
-                self._cur.defects.append(Errors.NoBoundaryInMultipart())
+                self._cur.defects.append(Errors.NoBoundaryInMultipartDefect())
                 lines = []
                 for line in self._input:
                     if line is NeedMoreData:
@@ -305,6 +309,8 @@
                             if eolmo:
                                 preamble[-1] = lastline[:-len(eolmo.group(0))]
                             self._cur.preamble = EMPTYSTRING.join(preamble)
+                        #import pdb ; pdb.set_trace()
+                        # See SF bug #1030941
                         capturing_preamble = False
                         self._input.unreadline(line)
                         continue
@@ -363,7 +369,7 @@
             # that as a defect and store the captured text as the payload.
             # Otherwise everything from here to the EOF is epilogue.
             if capturing_preamble:
-                self._cur.defects.append(Errors.StartBoundaryNotFound())
+                self._cur.defects.append(Errors.StartBoundaryNotFoundDefect())
                 self._cur.set_payload(EMPTYSTRING.join(preamble))
                 return
             # If the end boundary ended in a newline, we'll need to make sure
@@ -408,7 +414,7 @@
                     # The first line of the headers was a continuation.  This
                     # is illegal, so let's note the defect, store the illegal
                     # line, and ignore it for purposes of headers.
-                    defect = Errors.FirstHeaderLineIsContinuation(line)
+                    defect = Errors.FirstHeaderLineIsContinuationDefect(line)
                     self._cur.defects.append(defect)
                     continue
                 lastvalue.append(line)
@@ -436,13 +442,13 @@
                 else:
                     # Weirdly placed unix-from line.  Note this as a defect
                     # and ignore it.
-                    defect = Errors.MisplacedEnvelopeHeader(line)
+                    defect = Errors.MisplacedEnvelopeHeaderDefect(line)
                     self._cur.defects.append(defect)
                     continue
             # Split the line on the colon separating field name from value.
             i = line.find(':')
             if i < 0:
-                defect = Errors.MalformedHeader(line)
+                defect = Errors.MalformedHeaderDefect(line)
                 self._cur.defects.append(defect)
                 continue
             lastheader = line[:i]

Index: Generator.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/Generator.py,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- Generator.py	9 May 2004 03:35:17 -0000	1.23
+++ Generator.py	3 Oct 2004 03:16:18 -0000	1.24
@@ -1,13 +1,14 @@
 # Copyright (C) 2001-2004 Python Software Foundation
-# Author: barry at python.org (Barry Warsaw)
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
-"""Classes to generate plain text from a message object tree.
-"""
+"""Classes to generate plain text from a message object tree."""
 
 import re
 import sys
 import time
 import random
+import warnings
 from cStringIO import StringIO
 
 from email.Header import Header
@@ -81,7 +82,10 @@
         self._write(msg)
 
     # For backwards compatibility, but this is slower
-    __call__ = flatten
+    def __call__(self, msg, unixfrom=False):
+        warnings.warn('__call__() deprecated; use flatten()',
+                      DeprecationWarning, 2)
+        self.flatten(msg, unixfrom)
 
     def clone(self, fp):
         """Clone this generator with the exact same options."""
@@ -175,7 +179,7 @@
         if cset is not None:
             payload = cset.body_encode(payload)
         if not isinstance(payload, basestring):
-            raise TypeError, 'string payload expected: %s' % type(payload)
+            raise TypeError('string payload expected: %s' % type(payload))
         if self._mangle_from_:
             payload = fcre.sub('>From ', payload)
         self._fp.write(payload)
@@ -271,6 +275,8 @@
 
 
 
+_FMT = '[Non-text (%(type)s) part of message omitted, filename %(filename)s]'
+
 class DecodedGenerator(Generator):
     """Generator a text representation of a message.
 
@@ -301,13 +307,13 @@
         """
         Generator.__init__(self, outfp, mangle_from_, maxheaderlen)
         if fmt is None:
-            fmt = ('[Non-text (%(type)s) part of message omitted, '
-                   'filename %(filename)s]')
-        self._fmt = fmt
+            self._fmt = _FMT
+        else:
+            self._fmt = fmt
 
     def _dispatch(self, msg):
         for part in msg.walk():
-            maintype = part.get_main_type('text')
+            maintype = part.get_content_maintype()
             if maintype == 'text':
                 print >> self, part.get_payload(decode=True)
             elif maintype == 'multipart':
@@ -315,9 +321,9 @@
                 pass
             else:
                 print >> self, self._fmt % {
-                    'type'       : part.get_type('[no MIME type]'),
-                    'maintype'   : part.get_main_type('[no main MIME type]'),
-                    'subtype'    : part.get_subtype('[no sub-MIME type]'),
+                    'type'       : part.get_content_type(),
+                    'maintype'   : part.get_content_maintype(),
+                    'subtype'    : part.get_content_subtype(),
                     'filename'   : part.get_filename('[no filename]'),
                     'description': part.get('Content-Description',
                                             '[no description]'),

Index: Header.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/Header.py,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- Header.py	10 May 2004 14:44:04 -0000	1.29
+++ Header.py	3 Oct 2004 03:16:18 -0000	1.30
@@ -1,5 +1,6 @@
 # Copyright (C) 2002-2004 Python Software Foundation
-# Author: che at debian.org (Ben Gertzfield), barry at python.org (Barry Warsaw)
+# Author: Ben Gertzfield, Barry Warsaw
+# Contact: email-sig at python.org
 
 """Header encoding and decoding functionality."""
 

Index: Iterators.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/Iterators.py,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- Iterators.py	13 May 2004 20:14:20 -0000	1.14
+++ Iterators.py	3 Oct 2004 03:16:18 -0000	1.15
@@ -1,8 +1,8 @@
 # Copyright (C) 2001-2004 Python Software Foundation
-# Author: Barry Warsaw <barry at python.org>
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
-"""Various types of useful iterators and generators.
-"""
+"""Various types of useful iterators and generators."""
 
 import sys
 from cStringIO import StringIO

Index: MIMEAudio.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEAudio.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- MIMEAudio.py	30 Sep 2002 21:29:10 -0000	1.4
+++ MIMEAudio.py	3 Oct 2004 03:16:18 -0000	1.5
@@ -1,7 +1,8 @@
+# Copyright (C) 2001-2004 Python Software Foundation
 # Author: Anthony Baxter
+# Contact: email-sig at python.org
 
-"""Class representing audio/* type MIME documents.
-"""
+"""Class representing audio/* type MIME documents."""
 
 import sndhdr
 from cStringIO import StringIO
@@ -65,7 +66,7 @@
         if _subtype is None:
             _subtype = _whatsnd(_audiodata)
         if _subtype is None:
-            raise TypeError, 'Could not find audio MIME subtype'
+            raise TypeError('Could not find audio MIME subtype')
         MIMENonMultipart.__init__(self, 'audio', _subtype, **_params)
         self.set_payload(_audiodata)
         _encoder(self)

Index: MIMEBase.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEBase.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- MIMEBase.py	2 Jun 2002 19:04:39 -0000	1.6
+++ MIMEBase.py	3 Oct 2004 03:16:18 -0000	1.7
@@ -1,8 +1,8 @@
-# Copyright (C) 2001,2002 Python Software Foundation
-# Author: barry at zope.com (Barry Warsaw)
+# Copyright (C) 2001-2004 Python Software Foundation
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
-"""Base class for MIME specializations.
-"""
+"""Base class for MIME specializations."""
 
 from email import Message
 

Index: MIMEImage.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEImage.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- MIMEImage.py	30 Sep 2002 22:15:00 -0000	1.6
+++ MIMEImage.py	3 Oct 2004 03:16:18 -0000	1.7
@@ -1,8 +1,8 @@
-# Copyright (C) 2001,2002 Python Software Foundation
-# Author: barry at zope.com (Barry Warsaw)
+# Copyright (C) 2001-2004 Python Software Foundation
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
-"""Class representing image/* type MIME documents.
-"""
+"""Class representing image/* type MIME documents."""
 
 import imghdr
 
@@ -39,7 +39,7 @@
         if _subtype is None:
             _subtype = imghdr.what(None, _imagedata)
         if _subtype is None:
-            raise TypeError, 'Could not guess image MIME subtype'
+            raise TypeError('Could not guess image MIME subtype')
         MIMENonMultipart.__init__(self, 'image', _subtype, **_params)
         self.set_payload(_imagedata)
         _encoder(self)

Index: MIMEMessage.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEMessage.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- MIMEMessage.py	9 Jul 2002 02:40:35 -0000	1.6
+++ MIMEMessage.py	3 Oct 2004 03:16:18 -0000	1.7
@@ -1,8 +1,8 @@
-# Copyright (C) 2001,2002 Python Software Foundation
-# Author: barry at zope.com (Barry Warsaw)
+# Copyright (C) 2001-2004 Python Software Foundation
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
-"""Class representing message/* MIME documents.
-"""
+"""Class representing message/* MIME documents."""
 
 from email import Message
 from email.MIMENonMultipart import MIMENonMultipart
@@ -24,7 +24,7 @@
         """
         MIMENonMultipart.__init__(self, 'message', _subtype)
         if not isinstance(_msg, Message.Message):
-            raise TypeError, 'Argument is not an instance of Message'
+            raise TypeError('Argument is not an instance of Message')
         # It's convenient to use this base class method.  We need to do it
         # this way or we'll get an exception
         Message.Message.attach(self, _msg)

Index: MIMEMultipart.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEMultipart.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- MIMEMultipart.py	9 May 2004 18:04:24 -0000	1.4
+++ MIMEMultipart.py	3 Oct 2004 03:16:18 -0000	1.5
@@ -1,8 +1,8 @@
 # Copyright (C) 2002-2004 Python Software Foundation
-# Author: barry at python.org (Barry Warsaw)
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
-"""Base class for MIME multipart/* type messages.
-"""
+"""Base class for MIME multipart/* type messages."""
 
 from email import MIMEBase
 

Index: MIMENonMultipart.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMENonMultipart.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- MIMENonMultipart.py	28 Sep 2002 20:25:15 -0000	1.2
+++ MIMENonMultipart.py	3 Oct 2004 03:16:18 -0000	1.3
@@ -1,8 +1,8 @@
-# Copyright (C) 2002 Python Software Foundation
-# Author: barry at zope.com (Barry Warsaw)
+# Copyright (C) 2002-2004 Python Software Foundation
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
-"""Base class for MIME type messages that are not multipart.
-"""
+"""Base class for MIME type messages that are not multipart."""
 
 from email import Errors
 from email import MIMEBase

Index: MIMEText.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEText.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- MIMEText.py	11 Mar 2003 05:04:09 -0000	1.8
+++ MIMEText.py	3 Oct 2004 03:16:18 -0000	1.9
@@ -1,10 +1,9 @@
-# Copyright (C) 2001,2002 Python Software Foundation
-# Author: barry at zope.com (Barry Warsaw)
+# Copyright (C) 2001-2004 Python Software Foundation
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
-"""Class representing text/* type MIME documents.
-"""
+"""Class representing text/* type MIME documents."""
 
-import warnings
 from email.MIMENonMultipart import MIMENonMultipart
 from email.Encoders import encode_7or8bit
 
@@ -13,8 +12,7 @@
 class MIMEText(MIMENonMultipart):
     """Class for generating text/* type MIME documents."""
 
-    def __init__(self, _text, _subtype='plain', _charset='us-ascii',
-                 _encoder=None):
+    def __init__(self, _text, _subtype='plain', _charset='us-ascii'):
         """Create a text/* type MIME document.
 
         _text is the string for this message object.
@@ -24,22 +22,7 @@
         _charset is the character set parameter added to the Content-Type
         header.  This defaults to "us-ascii".  Note that as a side-effect, the
         Content-Transfer-Encoding header will also be set.
-
-        The use of the _encoder is deprecated.  The encoding of the payload,
-        and the setting of the character set parameter now happens implicitly
-        based on the _charset argument.  If _encoder is supplied, then a
-        DeprecationWarning is used, and the _encoder functionality may
-        override any header settings indicated by _charset.  This is probably
-        not what you want.
         """
         MIMENonMultipart.__init__(self, 'text', _subtype,
                                   **{'charset': _charset})
         self.set_payload(_text, _charset)
-        if _encoder is not None:
-            warnings.warn('_encoder argument is obsolete.',
-                          DeprecationWarning, 2)
-            # Because set_payload() with a _charset will set its own
-            # Content-Transfer-Encoding header, we need to delete the
-            # existing one or will end up with two of them. :(
-            del self['content-transfer-encoding']
-            _encoder(self)

Index: Message.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/Message.py,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- Message.py	16 Aug 2004 15:47:34 -0000	1.37
+++ Message.py	3 Oct 2004 03:16:18 -0000	1.38
@@ -1,5 +1,6 @@
 # Copyright (C) 2001-2004 Python Software Foundation
-# Author: barry at python.org (Barry Warsaw)
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
 """Basic message object for the email package object model."""
 
@@ -69,6 +70,10 @@
 
 
 def _unquotevalue(value):
+    # This is different than Utils.collapse_rfc2231_value() because it doesn't
+    # try to convert the value to a unicode.  Message.get_param() and
+    # Message.get_params() are both currently defined to return the tuple in
+    # the face of RFC 2231 parameters.
     if isinstance(value, tuple):
         return value[0], value[1], Utils.unquote(value[2])
     else:
@@ -98,6 +103,7 @@
         self._charset = None
         # Defaults for multipart messages
         self.preamble = self.epilogue = None
+        self.defects = []
         # Default content type
         self._default_type = 'text/plain'
 
@@ -124,9 +130,7 @@
 
     def is_multipart(self):
         """Return True if the message consists of multiple parts."""
-        if isinstance(self._payload, list):
-            return True
-        return False
+        return isinstance(self._payload, list)
 
     #
     # Unix From_ line
@@ -140,26 +144,6 @@
     #
     # Payload manipulation.
     #
-    def add_payload(self, payload):
-        """Add the given payload to the current payload.
-
-        If the current payload is empty, then the current payload will be made
-        a scalar, set to the given value.
-
-        Note: This method is deprecated.  Use .attach() instead.
-        """
-        warnings.warn('add_payload() is deprecated, use attach() instead.',
-                      DeprecationWarning, 2)
-        if self._payload is None:
-            self._payload = payload
-        elif isinstance(self._payload, list):
-            self._payload.append(payload)
-        elif self.get_main_type() not in (None, 'multipart'):
-            raise Errors.MultipartConversionError(
-                'Message main content type must be "multipart" or missing')
-        else:
-            self._payload = [self._payload, payload]
-
     def attach(self, payload):
         """Add the given payload to the current payload.
 
@@ -195,7 +179,7 @@
         if i is None:
             payload = self._payload
         elif not isinstance(self._payload, list):
-            raise TypeError, 'Expected list, got %s' % type(self._payload)
+            raise TypeError('Expected list, got %s' % type(self._payload))
         else:
             payload = self._payload[i]
         if decode:
@@ -254,7 +238,7 @@
         if isinstance(charset, str):
             charset = Charset.Charset(charset)
         if not isinstance(charset, Charset.Charset):
-            raise TypeError, charset
+            raise TypeError(charset)
         # BAW: should we accept strings that can serve as arguments to the
         # Charset constructor?
         self._charset = charset
@@ -267,9 +251,9 @@
             self.set_param('charset', charset.get_output_charset())
         if not self.has_key('Content-Transfer-Encoding'):
             cte = charset.get_body_encoding()
-            if callable(cte):
+            try:
                 cte(self)
-            else:
+            except TypeError:
                 self.add_header('Content-Transfer-Encoding', cte)
 
     def get_charset(self):
@@ -290,7 +274,7 @@
         Return None if the header is missing instead of raising an exception.
 
         Note that if the header appeared multiple times, exactly which
-        occurrance gets returned is undefined.  Use getall() to get all
+        occurrance gets returned is undefined.  Use get_all() to get all
         the values matching a header field name.
         """
         return self.get(name)
@@ -320,7 +304,7 @@
 
     def has_key(self, name):
         """Return true if the message contains the header."""
-        missing = []
+        missing = object()
         return self.get(name, missing) is not missing
 
     def keys(self):
@@ -422,11 +406,10 @@
                 self._headers[i] = (k, _value)
                 break
         else:
-            raise KeyError, _name
+            raise KeyError(_name)
 
     #
-    # These methods are silently deprecated in favor of get_content_type() and
-    # friends (see below).  They will be noisily deprecated in email 3.0.
+    # Deprecated methods.  These will be removed in email 3.1.
     #
 
     def get_type(self, failobj=None):
@@ -436,7 +419,9 @@
         string of the form `maintype/subtype'.  If there was no Content-Type
         header in the message, failobj is returned (defaults to None).
         """
-        missing = []
+        warnings.warn('get_type() deprecated; use get_content_type()',
+                      DeprecationWarning, 2)
+        missing = object()
         value = self.get('content-type', missing)
         if value is missing:
             return failobj
@@ -444,7 +429,9 @@
 
     def get_main_type(self, failobj=None):
         """Return the message's main content type if present."""
-        missing = []
+        warnings.warn('get_main_type() deprecated; use get_content_maintype()',
+                      DeprecationWarning, 2)
+        missing = object()
         ctype = self.get_type(missing)
         if ctype is missing:
             return failobj
@@ -454,7 +441,9 @@
 
     def get_subtype(self, failobj=None):
         """Return the message's content subtype if present."""
-        missing = []
+        warnings.warn('get_subtype() deprecated; use get_content_subtype()',
+                      DeprecationWarning, 2)
+        missing = object()
         ctype = self.get_type(missing)
         if ctype is missing:
             return failobj
@@ -479,7 +468,7 @@
         appears inside a multipart/digest container, in which case it would be
         message/rfc822.
         """
-        missing = []
+        missing = object()
         value = self.get('content-type', missing)
         if value is missing:
             # This should have no parameters
@@ -529,7 +518,7 @@
     def _get_params_preserve(self, failobj, header):
         # Like get_params() but preserves the quoting of values.  BAW:
         # should this be part of the public interface?
-        missing = []
+        missing = object()
         value = self.get(header, missing)
         if value is missing:
             return failobj
@@ -560,7 +549,7 @@
         header.  Optional header is the header to search instead of
         Content-Type.  If unquote is True, the value is unquoted.
         """
-        missing = []
+        missing = object()
         params = self._get_params_preserve(missing, header)
         if params is missing:
             return failobj
@@ -713,17 +702,11 @@
         The filename is extracted from the Content-Disposition header's
         `filename' parameter, and it is unquoted.
         """
-        missing = []
+        missing = object()
         filename = self.get_param('filename', missing, 'content-disposition')
         if filename is missing:
             return failobj
-        if isinstance(filename, tuple):
-            # It's an RFC 2231 encoded parameter
-            newvalue = _unquotevalue(filename)
-            return unicode(newvalue[2], newvalue[0] or 'us-ascii')
-        else:
-            newvalue = _unquotevalue(filename.strip())
-            return newvalue
+        return Utils.collapse_rfc2231_value(filename).strip()
 
     def get_boundary(self, failobj=None):
         """Return the boundary associated with the payload if present.
@@ -731,15 +714,11 @@
         The boundary is extracted from the Content-Type header's `boundary'
         parameter, and it is unquoted.
         """
-        missing = []
+        missing = object()
         boundary = self.get_param('boundary', missing)
         if boundary is missing:
             return failobj
-        if isinstance(boundary, tuple):
-            # RFC 2231 encoded, so decode.  It better end up as ascii
-            charset = boundary[0] or 'us-ascii'
-            return unicode(boundary[2], charset).encode('us-ascii')
-        return _unquotevalue(boundary.strip())
+        return Utils.collapse_rfc2231_value(boundary).strip()
 
     def set_boundary(self, boundary):
         """Set the boundary parameter in Content-Type to 'boundary'.
@@ -751,7 +730,7 @@
 
         HeaderParseError is raised if the message has no Content-Type header.
         """
-        missing = []
+        missing = object()
         params = self._get_params_preserve(missing, 'content-type')
         if params is missing:
             # There was no Content-Type header, and we don't know what type
@@ -793,7 +772,7 @@
         Content-Type header, or if that header has no charset parameter,
         failobj is returned.
         """
-        missing = []
+        missing = object()
         charset = self.get_param('charset', missing)
         if charset is missing:
             return failobj

Index: Parser.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/Parser.py,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- Parser.py	9 May 2004 03:46:42 -0000	1.22
+++ Parser.py	3 Oct 2004 03:16:18 -0000	1.23
@@ -4,17 +4,15 @@
 
 """A parser of RFC 2822 and MIME email messages."""
 
-import re
+import warnings
 from cStringIO import StringIO
 from email.FeedParser import FeedParser
 from email.Message import Message
 
-NLCRE = re.compile('\r\n|\r|\n')
-
 
 
 class Parser:
-    def __init__(self, _class=Message, strict=False):
+    def __init__(self, *args, **kws):
         """Parser of RFC 2822 and MIME email messages.
 
         Creates an in-memory object tree representing the email message, which
@@ -29,14 +27,28 @@
         _class is the class to instantiate for new message objects when they
         must be created.  This class must have a constructor that can take
         zero arguments.  Default is Message.Message.
-
-        Optional strict tells the parser to be strictly RFC compliant or to be
-        more forgiving in parsing of ill-formatted MIME documents.  When
-        non-strict mode is used, the parser will try to make up for missing or
-        erroneous boundaries and other peculiarities seen in the wild.
-        Default is non-strict parsing.
         """
-        self._class = _class
+        if len(args) >= 1:
+            if '_class' in kws:
+                raise TypeError("Multiple values for keyword arg '_class'")
+            kws['_class'] = args[0]
+        if len(args) == 2:
+            if 'strict' in kws:
+                raise TypeError("Multiple values for keyword arg 'strict'")
+            kws['strict'] = args[1]
+        if len(args) > 2:
+            raise TypeError('Too many arguments')
+        if '_class' in kws:
+            self._class = kws['_class']
+            del kws['_class']
+        else:
+            self._class = Message
+        if 'strict' in kws:
+            warnings.warn("'strict' argument is deprecated (and ignored)",
+                          DeprecationWarning, 2)
+            del kws['strict']
+        if kws:
+            raise TypeError('Unexpected keyword arguments')
 
     def parse(self, fp, headersonly=False):
         """Create a message structure from the data in a file.

Index: Utils.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/Utils.py,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- Utils.py	9 May 2004 03:50:04 -0000	1.26
+++ Utils.py	3 Oct 2004 03:16:18 -0000	1.27
@@ -1,5 +1,6 @@
 # Copyright (C) 2001-2004 Python Software Foundation
-# Author: barry at python.org (Barry Warsaw)
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
 """Miscellaneous utilities."""
 
@@ -80,12 +81,6 @@
         return '%s%s%s <%s>' % (quotes, name, quotes, address)
     return address
 
-# For backwards compatibility
-def dump_address_pair(pair):
-    warnings.warn('Use email.Utils.formataddr() instead',
-                  DeprecationWarning, 2)
-    return formataddr(pair)
-
 
 
 def getaddresses(fieldvalues):
@@ -107,46 +102,6 @@
   ''', re.VERBOSE | re.IGNORECASE)
 
 
-def decode(s):
-    """Return a decoded string according to RFC 2047, as a unicode string.
-
-    NOTE: This function is deprecated.  Use Header.decode_header() instead.
-    """
-    warnings.warn('Use Header.decode_header() instead.', DeprecationWarning, 2)
-    # Intra-package import here to avoid circular import problems.
-    from email.Header import decode_header
-    L = decode_header(s)
-    if not isinstance(L, list):
-        # s wasn't decoded
-        return s
-
-    rtn = []
-    for atom, charset in L:
-        if charset is None:
-            rtn.append(atom)
-        else:
-            # Convert the string to Unicode using the given encoding.  Leave
-            # Unicode conversion errors to strict.
-            rtn.append(unicode(atom, charset))
-    # Now that we've decoded everything, we just need to join all the parts
-    # together into the final string.
-    return UEMPTYSTRING.join(rtn)
-
-
-
-def encode(s, charset='iso-8859-1', encoding='q'):
-    """Encode a string according to RFC 2047."""
-    warnings.warn('Use Header.Header.encode() instead.', DeprecationWarning, 2)
-    encoding = encoding.lower()
-    if encoding == 'q':
-        estr = _qencode(s)
-    elif encoding == 'b':
-        estr = _bencode(s)
-    else:
-        raise ValueError, 'Illegal encoding code: ' + encoding
-    return '=?%s?%s?%s?=' % (charset.lower(), encoding, estr)
-
-
 
 def formatdate(timeval=None, localtime=False):
     """Returns a date string as specified by RFC 2822, e.g.:
@@ -179,7 +134,7 @@
             sign = '-'
         else:
             sign = '+'
-        zone = '%s%02d%02d' % (sign, hours, minutes / 60)
+        zone = '%s%02d%02d' % (sign, hours, minutes // 60)
     else:
         now = time.gmtime(timeval)
         # Timezone offset is always -0000
@@ -314,3 +269,16 @@
             new_params.append(
                 (name, (charset, language, '"%s"' % quote(value))))
     return new_params
+
+def collapse_rfc2231_value(value, errors='replace',
+                           fallback_charset='us-ascii'):
+    if isinstance(value, tuple):
+        rawval = unquote(value[2])
+        charset = value[0] or 'us-ascii'
+        try:
+            return unicode(rawval, charset, errors)
+        except LookupError:
+            # XXX charset is unknown to Python.
+            return unicode(rawval, fallback_charset, errors)
+    else:
+        return unquote(value)

Index: __init__.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/__init__.py,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- __init__.py	9 May 2004 03:51:39 -0000	1.32
+++ __init__.py	3 Oct 2004 03:16:18 -0000	1.33
@@ -1,5 +1,6 @@
 # Copyright (C) 2001-2004 Python Software Foundation
-# Author: barry at python.org (Barry Warsaw)
+# Author: Barry Warsaw
+# Contact: email-sig at python.org
 
 """A package for parsing, handling, and generating email messages."""
 
@@ -33,25 +34,19 @@
 # Some convenience routines.  Don't import Parser and Message as side-effects
 # of importing email since those cascadingly import most of the rest of the
 # email package.
-def message_from_string(s, _class=None, strict=False):
+def message_from_string(s, *args, **kws):
     """Parse a string into a Message object model.
 
     Optional _class and strict are passed to the Parser constructor.
     """
     from email.Parser import Parser
-    if _class is None:
-        from email.Message import Message
-        _class = Message
-    return Parser(_class, strict=strict).parsestr(s)
+    return Parser(*args, **kws).parsestr(s)
 
 
-def message_from_file(fp, _class=None, strict=False):
+def message_from_file(fp, *args, **kws):
     """Read a file and parse its contents into a Message object model.
 
     Optional _class and strict are passed to the Parser constructor.
     """
     from email.Parser import Parser
-    if _class is None:
-        from email.Message import Message
-        _class = Message
-    return Parser(_class, strict=strict).parse(fp)
+    return Parser(*args, **kws).parse(fp)

Index: _parseaddr.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/_parseaddr.py,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- _parseaddr.py	7 Aug 2004 16:38:39 -0000	1.9
+++ _parseaddr.py	3 Oct 2004 03:16:18 -0000	1.10
@@ -1,4 +1,5 @@
 # Copyright (C) 2002-2004 Python Software Foundation
+# Contact: email-sig at python.org
 
 """Email address parsing code.
 
@@ -115,7 +116,7 @@
             tzoffset = -tzoffset
         else:
             tzsign = 1
-        tzoffset = tzsign * ( (tzoffset/100)*3600 + (tzoffset % 100)*60)
+        tzoffset = tzsign * ( (tzoffset//100)*3600 + (tzoffset % 100)*60)
     tuple = (yy, mm, dd, thh, tmm, tss, 0, 1, 0, tzoffset)
     return tuple
 

Index: base64MIME.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/base64MIME.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- base64MIME.py	9 May 2004 03:53:50 -0000	1.7
+++ base64MIME.py	3 Oct 2004 03:16:18 -0000	1.8
@@ -1,5 +1,6 @@
-# Copyright (C) 2002 Python Software Foundation
-# Author: che at debian.org (Ben Gertzfield)
+# Copyright (C) 2002-2004 Python Software Foundation
+# Author: Ben Gertzfield
+# Contact: email-sig at python.org
 
 """Base64 content transfer encoding per RFCs 2045-2047.
 

Index: quopriMIME.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/email/quopriMIME.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- quopriMIME.py	9 May 2004 03:55:11 -0000	1.6
+++ quopriMIME.py	3 Oct 2004 03:16:18 -0000	1.7
@@ -1,5 +1,6 @@
 # Copyright (C) 2001-2004 Python Software Foundation
-# Author: che at debian.org (Ben Gertzfield)
+# Author: Ben Gertzfield
+# Contact: email-sig at python.org
 
 """Quoted-printable content transfer encoding per RFCs 2045-2047.
 
@@ -43,12 +44,12 @@
 # Helpers
 def header_quopri_check(c):
     """Return True if the character should be escaped with header quopri."""
-    return hqre.match(c) and True
+    return bool(hqre.match(c))
 
 
 def body_quopri_check(c):
     """Return True if the character should be escaped with body quopri."""
-    return bqre.match(c) and True
+    return bool(bqre.match(c))
 
 
 def header_quopri_len(s):



More information about the Python-checkins mailing list