summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrett Cannon <brett@python.org>2022-04-13 17:47:41 (GMT)
committerGitHub <noreply@github.com>2022-04-13 17:47:41 (GMT)
commit3fc57e8f6ff925b561b03c46bcf5bd323782c19c (patch)
treea69bfe3acdb5be3ee7ffc0536d15397a39580800
parentdfbc792a4b1e033d6628eda463c0933aef081bbe (diff)
downloadcpython-3fc57e8f6ff925b561b03c46bcf5bd323782c19c.zip
cpython-3fc57e8f6ff925b561b03c46bcf5bd323782c19c.tar.gz
cpython-3fc57e8f6ff925b561b03c46bcf5bd323782c19c.tar.bz2
gh-91217: deprecate imghdr (#91461)
* Deprecate imghdr Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> * Update Doc/whatsnew/3.11.rst Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> * Inline `imghdr` into `email.mime.image` Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> Co-authored-by: Barry Warsaw <barry@python.org>
-rw-r--r--Doc/includes/email-mime.py5
-rw-r--r--Doc/library/email.mime.rst11
-rw-r--r--Doc/whatsnew/3.11.rst1
-rw-r--r--Lib/email/mime/image.py121
-rw-r--r--Lib/imghdr.py5
-rw-r--r--Lib/test/test_email/test_email.py2
-rw-r--r--Lib/test/test_imghdr.py5
-rw-r--r--Misc/NEWS.d/next/Library/2022-04-11-17-04-38.gh-issue-91217.QVDLOq.rst1
8 files changed, 128 insertions, 23 deletions
diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py
index 6af2be0..c87db6a 100644
--- a/Doc/includes/email-mime.py
+++ b/Doc/includes/email-mime.py
@@ -1,9 +1,6 @@
# Import smtplib for the actual sending function
import smtplib
-# And imghdr to find the types of our images
-import imghdr
-
# Here are the email package modules we'll need
from email.message import EmailMessage
@@ -22,7 +19,7 @@ for file in pngfiles:
with open(file, 'rb') as fp:
img_data = fp.read()
msg.add_attachment(img_data, maintype='image',
- subtype=imghdr.what(None, img_data))
+ subtype='jpeg')
# Send the email via our own SMTP server.
with smtplib.SMTP('localhost') as s:
diff --git a/Doc/library/email.mime.rst b/Doc/library/email.mime.rst
index f37f6aa..ab4f7bc 100644
--- a/Doc/library/email.mime.rst
+++ b/Doc/library/email.mime.rst
@@ -180,11 +180,12 @@ Here are the classes:
A subclass of :class:`~email.mime.nonmultipart.MIMENonMultipart`, the
:class:`MIMEImage` class is used to create MIME message objects of major type
:mimetype:`image`. *_imagedata* is a string containing the raw image data. If
- this data can be decoded by the standard Python module :mod:`imghdr`, then the
- subtype will be automatically included in the :mailheader:`Content-Type` header.
- Otherwise you can explicitly specify the image subtype via the *_subtype*
- argument. If the minor type could not be guessed and *_subtype* was not given,
- then :exc:`TypeError` is raised.
+ this data type can be detected (jpeg, png, gif, tiff, rgb, pbm, pgm, ppm,
+ rast, xbm, bmp, webp, and exr attempted), then the subtype will be
+ automatically included in the :mailheader:`Content-Type` header. Otherwise
+ you can explicitly specify the image subtype via the *_subtype* argument.
+ If the minor type could not be guessed and *_subtype* was not given, then
+ :exc:`TypeError` is raised.
Optional *_encoder* is a callable (i.e. function) which will perform the actual
encoding of the image data for transport. This callable takes one argument,
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index d803801..894ec8a 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -856,6 +856,7 @@ Deprecated
* :mod:`cgitb`
* :mod:`chunk`
* :mod:`crypt`
+ * :mod:`imghdr`
(Contributed by Brett Cannon in :issue:`47061`.)
diff --git a/Lib/email/mime/image.py b/Lib/email/mime/image.py
index 9272464..fac238c 100644
--- a/Lib/email/mime/image.py
+++ b/Lib/email/mime/image.py
@@ -6,13 +6,113 @@
__all__ = ['MIMEImage']
-import imghdr
-
from email import encoders
from email.mime.nonmultipart import MIMENonMultipart
-
+# Originally from the imghdr module.
+def _what(h):
+ for tf in tests:
+ if res := tf(h):
+ return res
+ else:
+ return None
+
+tests = []
+
+def _test_jpeg(h):
+ """JPEG data with JFIF or Exif markers; and raw JPEG"""
+ if h[6:10] in (b'JFIF', b'Exif'):
+ return 'jpeg'
+ elif h[:4] == b'\xff\xd8\xff\xdb':
+ return 'jpeg'
+
+tests.append(_test_jpeg)
+
+def _test_png(h):
+ if h.startswith(b'\211PNG\r\n\032\n'):
+ return 'png'
+
+tests.append(_test_png)
+
+def _test_gif(h):
+ """GIF ('87 and '89 variants)"""
+ if h[:6] in (b'GIF87a', b'GIF89a'):
+ return 'gif'
+
+tests.append(_test_gif)
+
+def _test_tiff(h):
+ """TIFF (can be in Motorola or Intel byte order)"""
+ if h[:2] in (b'MM', b'II'):
+ return 'tiff'
+
+tests.append(_test_tiff)
+
+def _test_rgb(h):
+ """SGI image library"""
+ if h.startswith(b'\001\332'):
+ return 'rgb'
+
+tests.append(_test_rgb)
+
+def _test_pbm(h):
+ """PBM (portable bitmap)"""
+ if len(h) >= 3 and \
+ h[0] == ord(b'P') and h[1] in b'14' and h[2] in b' \t\n\r':
+ return 'pbm'
+
+tests.append(_test_pbm)
+
+def _test_pgm(h):
+ """PGM (portable graymap)"""
+ if len(h) >= 3 and \
+ h[0] == ord(b'P') and h[1] in b'25' and h[2] in b' \t\n\r':
+ return 'pgm'
+
+tests.append(_test_pgm)
+
+def _test_ppm(h):
+ """PPM (portable pixmap)"""
+ if len(h) >= 3 and \
+ h[0] == ord(b'P') and h[1] in b'36' and h[2] in b' \t\n\r':
+ return 'ppm'
+
+tests.append(_test_ppm)
+
+def _test_rast(h):
+ """Sun raster file"""
+ if h.startswith(b'\x59\xA6\x6A\x95'):
+ return 'rast'
+
+tests.append(_test_rast)
+
+def _test_xbm(h):
+ """X bitmap (X10 or X11)"""
+ if h.startswith(b'#define '):
+ return 'xbm'
+
+tests.append(_test_xbm)
+
+def _test_bmp(h):
+ if h.startswith(b'BM'):
+ return 'bmp'
+
+tests.append(_test_bmp)
+
+def _test_webp(h):
+ if h.startswith(b'RIFF') and h[8:12] == b'WEBP':
+ return 'webp'
+
+tests.append(_test_webp)
+
+def _test_exr(h):
+ if h.startswith(b'\x76\x2f\x31\x01'):
+ return 'exr'
+
+tests.append(_test_exr)
+
+
class MIMEImage(MIMENonMultipart):
"""Class for generating image/* type MIME documents."""
@@ -20,11 +120,11 @@ class MIMEImage(MIMENonMultipart):
_encoder=encoders.encode_base64, *, policy=None, **_params):
"""Create an image/* type MIME document.
- _imagedata is a string containing the raw image data. If this data
- can be decoded by the standard Python `imghdr' module, then the
- subtype will be automatically included in the Content-Type header.
- Otherwise, you can specify the specific image subtype via the _subtype
- parameter.
+ _imagedata is a string containing the raw image data. If the data
+ type can be detected (jpeg, png, gif, tiff, rgb, pbm, pgm, ppm,
+ rast, xbm, bmp, webp, and exr attempted), then the subtype will be
+ automatically included in the Content-Type header. Otherwise, you can
+ specify the specific image subtype via the _subtype parameter.
_encoder is a function which will perform the actual encoding for
transport of the image data. It takes one argument, which is this
@@ -38,9 +138,8 @@ class MIMEImage(MIMENonMultipart):
header.
"""
if _subtype is None:
- _subtype = imghdr.what(None, _imagedata)
- if _subtype is None:
- raise TypeError('Could not guess image MIME subtype')
+ if (_subtype := _what(_imagedata)) is None:
+ raise TypeError('Could not guess image MIME subtype')
MIMENonMultipart.__init__(self, 'image', _subtype, policy=policy,
**_params)
self.set_payload(_imagedata)
diff --git a/Lib/imghdr.py b/Lib/imghdr.py
index afcb677..6a372e6 100644
--- a/Lib/imghdr.py
+++ b/Lib/imghdr.py
@@ -1,9 +1,14 @@
"""Recognize image file formats based on their first few bytes."""
from os import PathLike
+import warnings
__all__ = ["what"]
+
+warnings._deprecated(__name__, remove=(3, 13))
+
+
#-------------------------#
# Recognize image headers #
#-------------------------#
diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py
index ca9c773..b87dae2 100644
--- a/Lib/test/test_email/test_email.py
+++ b/Lib/test/test_email/test_email.py
@@ -7,6 +7,7 @@ import time
import base64
import unittest
import textwrap
+import warnings
from io import StringIO, BytesIO
from itertools import chain
@@ -1591,7 +1592,6 @@ class TestMIMEImage(unittest.TestCase):
header='foobar'), missing)
-
# Test the basic MIMEApplication class
class TestMIMEApplication(unittest.TestCase):
def test_headers(self):
diff --git a/Lib/test/test_imghdr.py b/Lib/test/test_imghdr.py
index ca0a0b2..208c8ee 100644
--- a/Lib/test/test_imghdr.py
+++ b/Lib/test/test_imghdr.py
@@ -1,12 +1,13 @@
-import imghdr
import io
import os
import pathlib
import unittest
import warnings
-from test.support import findfile
+from test.support import findfile, warnings_helper
from test.support.os_helper import TESTFN, unlink
+imghdr = warnings_helper.import_deprecated("imghdr")
+
TEST_FILES = (
('python.png', 'png'),
diff --git a/Misc/NEWS.d/next/Library/2022-04-11-17-04-38.gh-issue-91217.QVDLOq.rst b/Misc/NEWS.d/next/Library/2022-04-11-17-04-38.gh-issue-91217.QVDLOq.rst
new file mode 100644
index 0000000..3e59c20
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-04-11-17-04-38.gh-issue-91217.QVDLOq.rst
@@ -0,0 +1 @@
+Deprecate the imghdr module.