Commit 23c51a26 authored by Benjamin Peterson's avatar Benjamin Peterson

actually remove the mimetools module

parent af488af5
:mod:`mimetools` --- Tools for parsing MIME messages
====================================================
.. module:: mimetools
:synopsis: Tools for parsing MIME-style message bodies.
:deprecated:
.. deprecated:: 2.3
The :mod:`email` package should be used in preference to the :mod:`mimetools`
module. This module is present only to maintain backward compatibility.
.. index:: module: rfc822
This module defines a subclass of the :mod:`rfc822` module's :class:`Message`
class and a number of utility functions that are useful for the manipulation for
MIME multipart or encoded message.
It defines the following items:
.. class:: Message(fp[, seekable])
Return a new instance of the :class:`Message` class. This is a subclass of the
:class:`rfc822.Message` class, with some additional methods (see below). The
*seekable* argument has the same meaning as for :class:`rfc822.Message`.
.. function:: choose_boundary()
Return a unique string that has a high likelihood of being usable as a part
boundary. The string has the form ``'hostipaddr.uid.pid.timestamp.random'``.
.. function:: decode(input, output, encoding)
Read data encoded using the allowed MIME *encoding* from open file object
*input* and write the decoded data to open file object *output*. Valid values
for *encoding* include ``'base64'``, ``'quoted-printable'``, ``'uuencode'``,
``'x-uuencode'``, ``'uue'``, ``'x-uue'``, ``'7bit'``, and ``'8bit'``. Decoding
messages encoded in ``'7bit'`` or ``'8bit'`` has no effect. The input is simply
copied to the output.
.. function:: encode(input, output, encoding)
Read data from open file object *input* and write it encoded using the allowed
MIME *encoding* to open file object *output*. Valid values for *encoding* are
the same as for :meth:`decode`.
.. function:: copyliteral(input, output)
Read lines from open file *input* until EOF and write them to open file
*output*.
.. function:: copybinary(input, output)
Read blocks until EOF from open file *input* and write them to open file
*output*. The block size is currently fixed at 8192.
.. seealso::
Module :mod:`email`
Comprehensive email handling package; supersedes the :mod:`mimetools` module.
Module :mod:`rfc822`
Provides the base class for :class:`mimetools.Message`.
Module :mod:`multifile`
Support for reading files which contain distinct parts, such as MIME data.
http://faqs.cs.uu.nl/na-dir/mail/mime-faq/.html
The MIME Frequently Asked Questions document. For an overview of MIME, see the
answer to question 1.1 in Part 1 of this document.
.. _mimetools-message-objects:
Additional Methods of Message Objects
-------------------------------------
The :class:`Message` class defines the following methods in addition to the
:class:`rfc822.Message` methods:
.. method:: Message.getplist()
Return the parameter list of the :mailheader:`Content-Type` header. This is a
list of strings. For parameters of the form ``key=value``, *key* is converted
to lower case but *value* is not. For example, if the message contains the
header ``Content-type: text/html; spam=1; Spam=2; Spam`` then :meth:`getplist`
will return the Python list ``['spam=1', 'spam=2', 'Spam']``.
.. method:: Message.getparam(name)
Return the *value* of the first parameter (as returned by :meth:`getplist`) of
the form ``name=value`` for the given *name*. If *value* is surrounded by
quotes of the form '``<``...\ ``>``' or '``"``...\ ``"``', these are removed.
.. method:: Message.getencoding()
Return the encoding specified in the :mailheader:`Content-Transfer-Encoding`
message header. If no such header exists, return ``'7bit'``. The encoding is
converted to lower case.
.. method:: Message.gettype()
Return the message type (of the form ``type/subtype``) as specified in the
:mailheader:`Content-Type` header. If no such header exists, return
``'text/plain'``. The type is converted to lower case.
.. method:: Message.getmaintype()
Return the main type as specified in the :mailheader:`Content-Type` header. If
no such header exists, return ``'text'``. The main type is converted to lower
case.
.. method:: Message.getsubtype()
Return the subtype as specified in the :mailheader:`Content-Type` header. If no
such header exists, return ``'plain'``. The subtype is converted to lower case.
......@@ -15,7 +15,6 @@ on the Internet.
json.rst
mailcap.rst
mailbox.rst
mimetools.rst
mimetypes.rst
rfc822.rst
base64.rst
......
"""Various tools used by MIME-reading or MIME-writing programs."""
import os
import rfc822
import tempfile
__all__ = ["Message","choose_boundary","encode","decode","copyliteral",
"copybinary"]
class Message(rfc822.Message):
"""A derived class of rfc822.Message that knows about MIME headers and
contains some hooks for decoding encoded and multipart messages."""
def __init__(self, fp, seekable = 1):
rfc822.Message.__init__(self, fp, seekable)
self.encodingheader = \
self.getheader('content-transfer-encoding')
self.typeheader = \
self.getheader('content-type')
self.parsetype()
self.parseplist()
def parsetype(self):
str = self.typeheader
if str is None:
str = 'text/plain'
if ';' in str:
i = str.index(';')
self.plisttext = str[i:]
str = str[:i]
else:
self.plisttext = ''
fields = str.split('/')
for i in range(len(fields)):
fields[i] = fields[i].strip().lower()
self.type = '/'.join(fields)
self.maintype = fields[0]
self.subtype = '/'.join(fields[1:])
def parseplist(self):
str = self.plisttext
self.plist = []
while str[:1] == ';':
str = str[1:]
if ';' in str:
# XXX Should parse quotes!
end = str.index(';')
else:
end = len(str)
f = str[:end]
if '=' in f:
i = f.index('=')
f = f[:i].strip().lower() + \
'=' + f[i+1:].strip()
self.plist.append(f.strip())
str = str[end:]
def getplist(self):
return self.plist
def getparam(self, name):
name = name.lower() + '='
n = len(name)
for p in self.plist:
if p[:n] == name:
return rfc822.unquote(p[n:])
return None
def getparamnames(self):
result = []
for p in self.plist:
i = p.find('=')
if i >= 0:
result.append(p[:i].lower())
return result
def getencoding(self):
if self.encodingheader is None:
return '7bit'
return self.encodingheader.lower()
def gettype(self):
return self.type
def getmaintype(self):
return self.maintype
def getsubtype(self):
return self.subtype
# Utility functions
# -----------------
try:
import _thread
except ImportError:
import _dummy_thread as _thread
_counter_lock = _thread.allocate_lock()
del _thread
_counter = 0
def _get_next_counter():
global _counter
_counter_lock.acquire()
_counter += 1
result = _counter
_counter_lock.release()
return result
_prefix = None
def choose_boundary():
"""Return a string usable as a multipart boundary.
The string chosen is unique within a single program run, and
incorporates the user id (if available), process id (if available),
and current time. So it's very unlikely the returned string appears
in message text, but there's no guarantee.
The boundary contains dots so you have to quote it in the header."""
global _prefix
import time
if _prefix is None:
import socket
try:
hostid = socket.gethostbyname(socket.gethostname())
except socket.gaierror:
hostid = '127.0.0.1'
try:
uid = repr(os.getuid())
except AttributeError:
uid = '1'
try:
pid = repr(os.getpid())
except AttributeError:
pid = '1'
_prefix = hostid + '.' + uid + '.' + pid
return "%s.%.3f.%d" % (_prefix, time.time(), _get_next_counter())
# Subroutines for decoding some common content-transfer-types
# Input and output must be files opened in binary mode
def decode(input, output, encoding):
"""Decode common content-transfer-encodings (base64, quopri, uuencode)."""
if encoding == 'base64':
import base64
return base64.decode(input, output)
if encoding == 'quoted-printable':
import quopri
return quopri.decode(input, output)
if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
import uu
return uu.decode(input, output)
if encoding in ('7bit', '8bit'):
return output.write(input.read())
if encoding in decodetab:
pipethrough(input, decodetab[encoding], output)
else:
raise ValueError('unknown Content-Transfer-Encoding: %s' % encoding)
def encode(input, output, encoding):
"""Encode common content-transfer-encodings (base64, quopri, uuencode)."""
if encoding == 'base64':
import base64
return base64.encode(input, output)
if encoding == 'quoted-printable':
import quopri
return quopri.encode(input, output, 0)
if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
import uu
return uu.encode(input, output)
if encoding in ('7bit', '8bit'):
return output.write(input.read())
if encoding in encodetab:
pipethrough(input, encodetab[encoding], output)
else:
raise ValueError('unknown Content-Transfer-Encoding: %s' % encoding)
# The following is no longer used for standard encodings
# XXX This requires that uudecode and mmencode are in $PATH
uudecode_pipe = '''(
TEMP=/tmp/@uu.$$
sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
cat $TEMP
rm $TEMP
)'''
decodetab = {
'uuencode': uudecode_pipe,
'x-uuencode': uudecode_pipe,
'uue': uudecode_pipe,
'x-uue': uudecode_pipe,
'quoted-printable': 'mmencode -u -q',
'base64': 'mmencode -u -b',
}
encodetab = {
'x-uuencode': 'uuencode tempfile',
'uuencode': 'uuencode tempfile',
'x-uue': 'uuencode tempfile',
'uue': 'uuencode tempfile',
'quoted-printable': 'mmencode -q',
'base64': 'mmencode -b',
}
def pipeto(input, command):
pipe = os.popen(command, 'w')
copyliteral(input, pipe)
pipe.close()
def pipethrough(input, command, output):
(fd, tempname) = tempfile.mkstemp()
temp = os.fdopen(fd, 'w')
copyliteral(input, temp)
temp.close()
pipe = os.popen(command + ' <' + tempname, 'r')
copybinary(pipe, output)
pipe.close()
os.unlink(tempname)
def copyliteral(input, output):
while 1:
line = input.readline()
if not line: break
output.write(line)
def copybinary(input, output):
BUFSIZE = 8192
while 1:
line = input.read(BUFSIZE)
if not line: break
output.write(line)
import unittest
from test import support
import string, mimetools
import io
msgtext1 = mimetools.Message(io.StringIO(
"""Content-Type: text/plain; charset=iso-8859-1; format=flowed
Content-Transfer-Encoding: 8bit
Foo!
"""))
sample = bytes(string.ascii_letters + "=" + string.digits + "\n", "ASCII")
class MimeToolsTest(unittest.TestCase):
def decode_encode_test(self, enc):
i = io.BytesIO(sample)
o = io.BytesIO()
mimetools.encode(i, o, enc)
i = io.BytesIO(o.getvalue())
o = io.BytesIO()
mimetools.decode(i, o, enc)
self.assertEqual(o.getvalue(), sample)
# Separate tests for better diagnostics
def test_7bit(self):
self.decode_encode_test('7bit')
def test_8bit(self):
self.decode_encode_test('8bit')
def test_base64(self):
self.decode_encode_test('base64')
def test_quoted_printable(self):
self.decode_encode_test('quoted-printable')
def test_uuencode(self):
self.decode_encode_test('uuencode')
def test_x_uuencode(self):
self.decode_encode_test('x-uuencode')
def test_uue(self):
self.decode_encode_test('uue')
def test_x_uue(self):
self.decode_encode_test('x-uue')
def test_boundary(self):
s = set([""])
for i in range(100):
nb = mimetools.choose_boundary()
self.assert_(nb not in s)
s.add(nb)
def test_message(self):
msg = mimetools.Message(io.StringIO(str(msgtext1)))
self.assertEqual(msg.gettype(), "text/plain")
self.assertEqual(msg.getmaintype(), "text")
self.assertEqual(msg.getsubtype(), "plain")
self.assertEqual(msg.getplist(), ["charset=iso-8859-1", "format=flowed"])
self.assertEqual(msg.getparamnames(), ["charset", "format"])
self.assertEqual(msg.getparam("charset"), "iso-8859-1")
self.assertEqual(msg.getparam("format"), "flowed")
self.assertEqual(msg.getparam("spam"), None)
self.assertEqual(msg.getencoding(), "8bit")
def test_main():
support.run_unittest(MimeToolsTest)
if __name__=="__main__":
test_main()
......@@ -78,6 +78,8 @@ Extension Modules
Library
-------
- mimetools has been removed in favor of the email package
- Patch #2849: Remove use of rfc822 module from standard library.
- Added C optimized implementation of io.StringIO.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment