Skip to content

Commit 49da972

Browse files
committed
Replace deprecated imghdr package with filetype
The `imghdr` package from the Python standard library is [deprecated and will be removed in Python 3.13][1]. The deprecated PEP suggests packages filetype, puremagic, python-magic as replacements. I chose filetype because it has a [larger user-base][2] than puremagic and does not have a C dependency, like python-magic. [1]: https://peps.python.org/pep-0594/#deprecated-modules [2]: https://libraries.io/pypi/filetype
1 parent 6accdc4 commit 49da972

File tree

4 files changed

+4
-53
lines changed

4 files changed

+4
-53
lines changed

mediafile.py

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@
4646
import codecs
4747
import datetime
4848
import enum
49+
import filetype
4950
import functools
50-
import imghdr
5151
import logging
5252
import math
5353
import os
@@ -78,8 +78,6 @@
7878
'wav': 'WAVE',
7979
}
8080

81-
PREFERRED_IMAGE_EXTENSIONS = {'jpeg': 'jpg'}
82-
8381

8482
# Exceptions.
8583

@@ -346,52 +344,15 @@ def _sc_encode(gain, peak):
346344

347345

348346
# Cover art and other images.
349-
def _imghdr_what_wrapper(data):
350-
"""A wrapper around imghdr.what to account for jpeg files that can only be
351-
identified as such using their magic bytes
352-
See #1545
353-
See https://github.com/file/file/blob/master/magic/Magdir/jpeg#L12
354-
"""
355-
# imghdr.what returns none for jpegs with only the magic bytes, so
356-
# _wider_test_jpeg is run in that case. It still returns None if it didn't
357-
# match such a jpeg file.
358-
return imghdr.what(None, h=data) or _wider_test_jpeg(data)
359-
360-
361-
def _wider_test_jpeg(data):
362-
"""Test for a jpeg file following the UNIX file implementation which
363-
uses the magic bytes rather than just looking for the bytes that
364-
represent 'JFIF' or 'EXIF' at a fixed position.
365-
"""
366-
if data[:2] == b'\xff\xd8':
367-
return 'jpeg'
368-
369347

370348
def image_mime_type(data):
371349
"""Return the MIME type of the image data (a bytestring).
372350
"""
373-
# This checks for a jpeg file with only the magic bytes (unrecognized by
374-
# imghdr.what). imghdr.what returns none for that type of file, so
375-
# _wider_test_jpeg is run in that case. It still returns None if it didn't
376-
# match such a jpeg file.
377-
kind = _imghdr_what_wrapper(data)
378-
if kind in ['gif', 'jpeg', 'png', 'tiff', 'bmp']:
379-
return 'image/{0}'.format(kind)
380-
elif kind == 'pgm':
381-
return 'image/x-portable-graymap'
382-
elif kind == 'pbm':
383-
return 'image/x-portable-bitmap'
384-
elif kind == 'ppm':
385-
return 'image/x-portable-pixmap'
386-
elif kind == 'xbm':
387-
return 'image/x-xbitmap'
388-
else:
389-
return 'image/x-{0}'.format(kind)
351+
return filetype.guess_mime(data)
390352

391353

392354
def image_extension(data):
393-
ext = _imghdr_what_wrapper(data)
394-
return PREFERRED_IMAGE_EXTENSIONS.get(ext, ext)
355+
return filetype.guess_extension(data)
395356

396357

397358
class ImageType(enum.Enum):

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ home-page = "https://github.com/beetbox/mediafile"
1010
description-file = "README.rst"
1111
requires = [
1212
"mutagen>=1.46",
13+
"filetype>=1.2.0",
1314
]
1415
requires-python = ">=3.7"
1516
classifiers = [

test/rsrc/only-magic-bytes.jpg

-622 Bytes
Binary file not shown.

test/test_mediafile_edge.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,6 @@ def test_old_ape_version_bitrate(self):
7878
f = mediafile.MediaFile(media_file)
7979
self.assertEqual(f.bitrate, 0)
8080

81-
def test_only_magic_bytes_jpeg(self):
82-
# Some jpeg files can only be recognized by their magic bytes and as
83-
# such aren't recognized by imghdr. Ensure that this still works thanks
84-
# to our own follow up mimetype detection based on
85-
# https://github.com/file/file/blob/master/magic/Magdir/jpeg#L12
86-
magic_bytes_file = os.path.join(_common.RSRC, b'only-magic-bytes.jpg')
87-
with open(magic_bytes_file, 'rb') as f:
88-
jpg_data = f.read()
89-
self.assertEqual(
90-
mediafile._imghdr_what_wrapper(jpg_data), 'jpeg')
91-
9281
def test_soundcheck_non_ascii(self):
9382
# Make sure we don't crash when the iTunes SoundCheck field contains
9483
# non-ASCII binary data.

0 commit comments

Comments
 (0)