mirror of
https://github.com/python/cpython.git
synced 2025-10-28 09:10:36 +00:00
actually remove the mimetools module
This commit is contained in:
parent
af488af55d
commit
23c51a26a5
5 changed files with 2 additions and 448 deletions
|
|
@ -1,131 +0,0 @@
|
||||||
|
|
||||||
: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
|
json.rst
|
||||||
mailcap.rst
|
mailcap.rst
|
||||||
mailbox.rst
|
mailbox.rst
|
||||||
mimetools.rst
|
|
||||||
mimetypes.rst
|
mimetypes.rst
|
||||||
rfc822.rst
|
rfc822.rst
|
||||||
base64.rst
|
base64.rst
|
||||||
|
|
|
||||||
240
Lib/mimetools.py
240
Lib/mimetools.py
|
|
@ -1,240 +0,0 @@
|
||||||
"""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)
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
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
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- mimetools has been removed in favor of the email package
|
||||||
|
|
||||||
- Patch #2849: Remove use of rfc822 module from standard library.
|
- Patch #2849: Remove use of rfc822 module from standard library.
|
||||||
|
|
||||||
- Added C optimized implementation of io.StringIO.
|
- Added C optimized implementation of io.StringIO.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue