[Python-checkins] Rewrite audio.py to jive with image.py (#91886)

warsaw webhook-mailer at python.org
Sun Apr 24 18:50:17 EDT 2022


https://github.com/python/cpython/commit/440332072706c5e422e6c54a2ec0ebb88e09c85c
commit: 440332072706c5e422e6c54a2ec0ebb88e09c85c
branch: main
author: Barry Warsaw <barry at python.org>
committer: warsaw <barry at python.org>
date: 2022-04-24T15:50:07-07:00
summary:

Rewrite audio.py to jive with image.py (#91886)

Similar to the rewrite of email/mime/image.py and associated test after the
deprecation of imghdr.py, thisrewrites email/mime/audio.py and associated
tests after the deprecation of sndhdr.py.

Closes #91885

files:
A Lib/test/test_email/data/sndhdr.aifc
A Lib/test/test_email/data/sndhdr.aiff
A Lib/test/test_email/data/sndhdr.au
A Lib/test/test_email/data/sndhdr.wav
D Lib/test/test_email/data/audiotest.au
M Lib/email/mime/audio.py
M Lib/test/test_email/test_email.py

diff --git a/Lib/email/mime/audio.py b/Lib/email/mime/audio.py
index e859c2e8a2b6c..8815f5c5ec06d 100644
--- a/Lib/email/mime/audio.py
+++ b/Lib/email/mime/audio.py
@@ -11,58 +11,6 @@
 from email.mime.nonmultipart import MIMENonMultipart
 
 
-_tests = []
-
-def _test_aifc_aiff(h, f):
-    if not h.startswith(b'FORM'):
-        return None
-    if h[8:12] in {b'AIFC', b'AIFF'}:
-        return 'x-aiff'
-    else:
-        return None
-
-_tests.append(_test_aifc_aiff)
-
-
-def _test_au(h, f):
-    if h.startswith(b'.snd'):
-        return 'basic'
-    else:
-        return None
-
-_tests.append(_test_au)
-
-
-def _test_wav(h, f):
-    import wave
-    # 'RIFF' <len> 'WAVE' 'fmt ' <len>
-    if not h.startswith(b'RIFF') or h[8:12] != b'WAVE' or h[12:16] != b'fmt ':
-        return None
-    else:
-        return "x-wav"
-
-_tests.append(_test_wav)
-
-
-# There are others in sndhdr that don't have MIME types. :(
-# Additional ones to be added to sndhdr? midi, mp3, realaudio, wma??
-def _whatsnd(data):
-    """Try to identify a sound file type.
-
-    sndhdr.what() has a pretty cruddy interface, unfortunately.  This is why
-    we re-do it here.  It would be easier to reverse engineer the Unix 'file'
-    command and use the standard 'magic' file, as shipped with a modern Unix.
-    """
-    hdr = data[:512]
-    fakefile = BytesIO(hdr)
-    for testfn in _tests:
-        res = testfn(hdr, fakefile)
-        if res is not None:
-            return res
-    else:
-        return None
-
-
 class MIMEAudio(MIMENonMultipart):
     """Class for generating audio/* MIME documents."""
 
@@ -89,10 +37,64 @@ def __init__(self, _audiodata, _subtype=None,
         header.
         """
         if _subtype is None:
-            _subtype = _whatsnd(_audiodata)
+            _subtype = _what(_audiodata)
         if _subtype is None:
             raise TypeError('Could not find audio MIME subtype')
         MIMENonMultipart.__init__(self, 'audio', _subtype, policy=policy,
                                   **_params)
         self.set_payload(_audiodata)
         _encoder(self)
+
+
+_rules = []
+
+
+# Originally from the sndhdr module.
+#
+# There are others in sndhdr that don't have MIME types. :(
+# Additional ones to be added to sndhdr? midi, mp3, realaudio, wma??
+def _what(data):
+    # Try to identify a sound file type.
+    #
+    # sndhdr.what() had a pretty cruddy interface, unfortunately.  This is why
+    # we re-do it here.  It would be easier to reverse engineer the Unix 'file'
+    # command and use the standard 'magic' file, as shipped with a modern Unix.
+    hdr = data[:512]
+    fakefile = BytesIO(hdr)
+    for testfn in _rules:
+        if res := testfn(hdr, fakefile):
+            return res
+    else:
+        return None
+
+
+def rule(rulefunc):
+    _rules.append(rulefunc)
+    return rulefunc
+
+
+ at rule
+def _aiff(h, f):
+    if not h.startswith(b'FORM'):
+        return None
+    if h[8:12] in {b'AIFC', b'AIFF'}:
+        return 'x-aiff'
+    else:
+        return None
+
+
+ at rule
+def _au(h, f):
+    if h.startswith(b'.snd'):
+        return 'basic'
+    else:
+        return None
+
+
+ at rule
+def _wav(h, f):
+    # 'RIFF' <len> 'WAVE' 'fmt ' <len>
+    if not h.startswith(b'RIFF') or h[8:12] != b'WAVE' or h[12:16] != b'fmt ':
+        return None
+    else:
+        return "x-wav"
diff --git a/Lib/test/test_email/data/sndhdr.aifc b/Lib/test/test_email/data/sndhdr.aifc
new file mode 100644
index 0000000000000..8aae4e730bdaf
Binary files /dev/null and b/Lib/test/test_email/data/sndhdr.aifc differ
diff --git a/Lib/test/test_email/data/sndhdr.aiff b/Lib/test/test_email/data/sndhdr.aiff
new file mode 100644
index 0000000000000..8c279a762f1c7
Binary files /dev/null and b/Lib/test/test_email/data/sndhdr.aiff differ
diff --git a/Lib/test/test_email/data/audiotest.au b/Lib/test/test_email/data/sndhdr.au
similarity index 100%
rename from Lib/test/test_email/data/audiotest.au
rename to Lib/test/test_email/data/sndhdr.au
diff --git a/Lib/test/test_email/data/sndhdr.wav b/Lib/test/test_email/data/sndhdr.wav
new file mode 100644
index 0000000000000..0dca36739cde3
Binary files /dev/null and b/Lib/test/test_email/data/sndhdr.wav differ
diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py
index 6ead5947acb6f..933aa4cbc1959 100644
--- a/Lib/test/test_email/test_email.py
+++ b/Lib/test/test_email/test_email.py
@@ -1515,37 +1515,49 @@ def test_multipart_with_bad_bytes_in_cte(self):
 
 # Test the basic MIMEAudio class
 class TestMIMEAudio(unittest.TestCase):
-    def setUp(self):
-        with openfile('audiotest.au', 'rb') as fp:
+    def _make_audio(self, ext):
+        with openfile(f'sndhdr.{ext}', 'rb') as fp:
             self._audiodata = fp.read()
         self._au = MIMEAudio(self._audiodata)
 
     def test_guess_minor_type(self):
-        self.assertEqual(self._au.get_content_type(), 'audio/basic')
+        for ext, subtype in {
+            'aifc': 'x-aiff',
+            'aiff': 'x-aiff',
+            'wav': 'x-wav',
+            'au': 'basic',
+        }.items():
+            self._make_audio(ext)
+            subtype = ext if subtype is None else subtype
+            self.assertEqual(self._au.get_content_type(), f'audio/{subtype}')
 
     def test_encoding(self):
+        self._make_audio('au')
         payload = self._au.get_payload()
         self.assertEqual(base64.decodebytes(bytes(payload, 'ascii')),
-                self._audiodata)
+                         self._audiodata)
 
     def test_checkSetMinor(self):
+        self._make_audio('au')
         au = MIMEAudio(self._audiodata, 'fish')
         self.assertEqual(au.get_content_type(), 'audio/fish')
 
     def test_add_header(self):
+        self._make_audio('au')
         eq = self.assertEqual
         self._au.add_header('Content-Disposition', 'attachment',
-                            filename='audiotest.au')
+                            filename='sndhdr.au')
         eq(self._au['content-disposition'],
-           'attachment; filename="audiotest.au"')
+           'attachment; filename="sndhdr.au"')
         eq(self._au.get_params(header='content-disposition'),
-           [('attachment', ''), ('filename', 'audiotest.au')])
+           [('attachment', ''), ('filename', 'sndhdr.au')])
         eq(self._au.get_param('filename', header='content-disposition'),
-           'audiotest.au')
+           'sndhdr.au')
         missing = []
         eq(self._au.get_param('attachment', header='content-disposition'), '')
-        self.assertIs(self._au.get_param('foo', failobj=missing,
-                                         header='content-disposition'), missing)
+        self.assertIs(self._au.get_param(
+            'foo', failobj=missing,
+            header='content-disposition'), missing)
         # Try some missing stuff
         self.assertIs(self._au.get_param('foobar', missing), missing)
         self.assertIs(self._au.get_param('attachment', missing,
@@ -3462,7 +3474,7 @@ def test_BytesGenerator_linend_with_non_ascii(self):
         self.assertEqual(s.getvalue(), msgtxt)
 
     def test_mime_classes_policy_argument(self):
-        with openfile('audiotest.au', 'rb') as fp:
+        with openfile('sndhdr.au', 'rb') as fp:
             audiodata = fp.read()
         with openfile('python.gif', 'rb') as fp:
             bindata = fp.read()



More information about the Python-checkins mailing list