More informative MediaFile exceptions

* Remove generic messages for `UnreadableFileError`. The class
  carries that information—so we see it if the exceptions crashes the
  program. If the exception is caught (in `library`, `importer`,
  and `autotag`) the type of the exceptions is logged.

* Attach file path to the exceptions. This allows us to determine
  the file that crashed the application.

See #788
This commit is contained in:
Thomas Scholtes 2014-05-23 11:20:41 +02:00
parent 7339559359
commit fe6c7819d3

View file

@ -52,6 +52,9 @@ import logging
import traceback
import enum
from beets.util import displayable_path
__all__ = ['UnreadableFileError', 'FileTypeError', 'MediaFile']
log = logging.getLogger('beets')
@ -75,21 +78,33 @@ TYPES = {
# Exceptions.
class UnreadableFileError(Exception):
"""Indicates a file that MediaFile can't read.
"""Mutagen is not able to extract information from the file.
"""
pass
def __init__(self, path):
Exception.__init__(self, displayable_path(path))
class FileTypeError(UnreadableFileError):
"""Raised for files that don't seem to have a type MediaFile
supports.
"""Reading this type of file is not supported.
If passed the `mutagen_type` argument this indicates that the
mutagen type is not supported by `Mediafile`.
"""
pass
def __init__(self, path, mutagen_type=None):
path = displayable_path(path)
if mutagen_type is None:
msg = path
else:
msg = u'{0}: of mutagen type {1}'.format(path, mutagen_type)
Exception.__init__(self, msg)
class MutagenError(UnreadableFileError):
"""Raised when Mutagen fails unexpectedly---probably due to a bug.
"""
def __init__(self, path, mutagen_exc):
msg = u'{0}: {1}'.format(displayable_path(path), mutagen_exc)
Exception.__init__(self, msg)
# Utility.
@ -1230,7 +1245,7 @@ class MediaFile(object):
self.mgfile = mutagen.File(path)
except unreadable_exc as exc:
log.debug(u'header parsing failed: {0}'.format(unicode(exc)))
raise UnreadableFileError('Mutagen could not read file')
raise UnreadableFileError(path)
except IOError as exc:
if type(exc) == IOError:
# This is a base IOError, not a subclass from Mutagen or
@ -1238,16 +1253,16 @@ class MediaFile(object):
raise
else:
log.debug(traceback.format_exc())
raise MutagenError('Mutagen raised an exception')
raise MutagenError(path, exc)
except Exception as exc:
# Isolate bugs in Mutagen.
log.debug(traceback.format_exc())
log.error('uncaught Mutagen exception in open: {0}'.format(exc))
raise MutagenError('Mutagen raised an exception')
raise MutagenError(path, exc)
if self.mgfile is None:
# Mutagen couldn't guess the type
raise FileTypeError('file type unsupported by Mutagen')
raise FileTypeError(path)
elif (type(self.mgfile).__name__ == 'M4A' or
type(self.mgfile).__name__ == 'MP4'):
# This hack differentiates AAC and ALAC until we find a more
@ -1279,8 +1294,7 @@ class MediaFile(object):
elif type(self.mgfile).__name__ == 'AIFF':
self.type = 'aiff'
else:
raise FileTypeError('file type %s unsupported by MediaFile' %
type(self.mgfile).__name__)
raise FileTypeError(path, type(self.mgfile).__name__)
# add a set of tags if it's missing
if self.mgfile.tags is None:
@ -1310,7 +1324,7 @@ class MediaFile(object):
except Exception as exc:
log.debug(traceback.format_exc())
log.error('uncaught Mutagen exception in save: {0}'.format(exc))
raise MutagenError('Mutagen raised an exception')
raise MutagenError(self.path, exc)
def delete(self):
"""Remove the current metadata tag from the file.