mirror of
https://github.com/beetbox/beets.git
synced 2026-01-05 07:23:33 +01:00
Handle exceptions in item.write and use plugin abort
This commit is contained in:
parent
a744e8ea59
commit
a399f294e8
5 changed files with 27 additions and 39 deletions
|
|
@ -894,7 +894,7 @@ def manipulate_files(session):
|
|||
item.move(True)
|
||||
|
||||
if config['import']['write'] and task.should_write_tags():
|
||||
ui.commands._item_write(item)
|
||||
item.write()
|
||||
|
||||
# Save new paths.
|
||||
with session.lib.transaction():
|
||||
|
|
|
|||
|
|
@ -371,15 +371,26 @@ class Item(LibModel):
|
|||
self.path = read_path
|
||||
|
||||
def write(self):
|
||||
"""Writes the item's metadata to the associated file.
|
||||
"""Try to write the item's metadata to the associated file.
|
||||
|
||||
Returns ``True`` if the write was successful. The method catches
|
||||
file system read and write exceptions and logs an error message.
|
||||
If any of 'write' event handlers returns a truthy value the
|
||||
write will not be performed and an error message is logged.
|
||||
"""
|
||||
plugins.send('write', item=self)
|
||||
if any(plugins.send('write', item=self)):
|
||||
log.error(u'plugin aborted writing {0}'.format(
|
||||
util.displayable_path(item.path)))
|
||||
return
|
||||
|
||||
|
||||
try:
|
||||
f = MediaFile(syspath(self.path))
|
||||
except (OSError, IOError) as exc:
|
||||
raise util.FilesystemError(exc, 'read', (self.path,),
|
||||
traceback.format_exc())
|
||||
log.error(u'could not read {0}: {1}'.format(
|
||||
util.displayable_path(item.path), exc
|
||||
))
|
||||
return
|
||||
|
||||
for key in ITEM_KEYS_WRITABLE:
|
||||
setattr(f, key, self[key])
|
||||
|
|
@ -387,12 +398,15 @@ class Item(LibModel):
|
|||
try:
|
||||
f.save(id3v23=beets.config['id3v23'].get(bool))
|
||||
except (OSError, IOError) as exc:
|
||||
raise util.FilesystemError(exc, 'write', (self.path,),
|
||||
traceback.format_exc())
|
||||
log.error(u'could not write {0}: {1}'.format(
|
||||
util.displayable_path(item.path), exc
|
||||
))
|
||||
return
|
||||
|
||||
# The file has a new mtime.
|
||||
self.mtime = self.current_mtime()
|
||||
plugins.send('after_write', item=self)
|
||||
return True
|
||||
|
||||
|
||||
# Files themselves.
|
||||
|
|
|
|||
|
|
@ -30,15 +30,6 @@ LASTFM_KEY = '2dc3914abf35f0d9c92d97d8f8e42b43'
|
|||
log = logging.getLogger('beets')
|
||||
|
||||
|
||||
class BeforeWriteError(Exception):
|
||||
"""May be raised by plugins in a ``write`` event handler to abort
|
||||
prevent writing the item's file.
|
||||
|
||||
Beets will catch this exception during a call to ``item.write()``
|
||||
and display it to the user as an error.
|
||||
"""
|
||||
|
||||
|
||||
# Managing the plugins themselves.
|
||||
|
||||
class BeetsPlugin(object):
|
||||
|
|
@ -362,10 +353,7 @@ def send(event, **arguments):
|
|||
name of the event to send, all other named arguments go to the
|
||||
event handler(s).
|
||||
|
||||
Returns the number of handlers called.
|
||||
Returns a list of return values from the handlers.
|
||||
"""
|
||||
log.debug('Sending event: %s' % event)
|
||||
handlers = event_handlers()[event]
|
||||
for handler in handlers:
|
||||
handler(**arguments)
|
||||
return len(handlers)
|
||||
return [handler(**arguments) for handler in event_handlers()[event]]
|
||||
|
|
|
|||
|
|
@ -76,20 +76,6 @@ def _do_query(lib, query, album, also_items=True):
|
|||
|
||||
return items, albums
|
||||
|
||||
def _item_write(item):
|
||||
"""Wrapper for ``item.write()`` that handles exceptions and logs
|
||||
errors during user interaction.
|
||||
"""
|
||||
try:
|
||||
item.write()
|
||||
except (mediafile.UnreadableFileError,
|
||||
util.FilesystemError,
|
||||
plugins.BeforeWriteError) as exc:
|
||||
log.error(u'could not write {0}: {1}'.format(
|
||||
util.displayable_path(item.path), exc
|
||||
))
|
||||
|
||||
|
||||
|
||||
# fields: Shows a list of available fields for queries and format strings.
|
||||
|
||||
|
|
@ -1148,7 +1134,7 @@ def modify_items(lib, mods, query, write, move, album, confirm):
|
|||
else:
|
||||
changed_items = changed
|
||||
for item in changed_items:
|
||||
_item_write(item)
|
||||
item.write()
|
||||
|
||||
modify_cmd = ui.Subcommand('modify',
|
||||
help='change metadata fields', aliases=('mod',))
|
||||
|
|
@ -1245,7 +1231,7 @@ def write_items(lib, query, pretend):
|
|||
changed = ui.show_model_changes(item, clean_item,
|
||||
library.ITEM_KEYS_WRITABLE, always=True)
|
||||
if changed and not pretend:
|
||||
_item_write(item)
|
||||
item.write()
|
||||
|
||||
write_cmd = ui.Subcommand('write', help='write tag information to files')
|
||||
write_cmd.parser.add_option('-p', '--pretend', action='store_true',
|
||||
|
|
|
|||
|
|
@ -142,8 +142,8 @@ currently available are:
|
|||
|
||||
* *write*: called with an ``Item`` object just before a file's metadata is
|
||||
written to disk (i.e., just before the file on disk is opened). Event
|
||||
handlers may raise ``plugins.BeforeWriteError`` to prevent beets from
|
||||
writing the file and display an error to the user.
|
||||
handlers may return a truthy value to prevent beets from writing the
|
||||
file. In that case make sure that you log an appropriate message.
|
||||
|
||||
* *after_write*: called with an ``Item`` object after a file's metadata is
|
||||
written to disk (i.e., just after the file on disk is closed).
|
||||
|
|
|
|||
Loading…
Reference in a new issue