remove Library.{move,store} methods

These methods are now provided by LibModel, which makes dealing with items and
albums symmetric.
This commit is contained in:
Adrian Sampson 2013-08-21 15:34:45 -07:00
parent 15cf046285
commit c7fe017752
16 changed files with 53 additions and 94 deletions

View file

@ -811,7 +811,7 @@ def plugin_stage(session, func):
# Stage may modify DB, so re-load cached item data.
for item in task.imported_items():
session.lib.load(item)
item.load()
def manipulate_files(session):
"""A coroutine (pipeline stage) that performs necessary file
@ -858,7 +858,7 @@ def manipulate_files(session):
# Save new paths.
with session.lib.transaction():
for item in items:
session.lib.store(item)
item.store()
# Plugin event.
plugins.send('import_task_files', session=session, task=task)

View file

@ -1405,6 +1405,8 @@ class Library(object):
item.added = time.time()
if copy:
self.move(item, copy=True)
if not item._lib:
item._lib = self
# Build essential parts of query.
columns = ','.join([key for key in ITEM_KEYS if key != 'id'])
@ -1438,49 +1440,6 @@ class Library(object):
self._memotable = {}
return new_id
def load(self, item):
"""Refresh the item's metadata from the library database.
"""
if item.id is None:
raise ValueError('cannot load item with no id')
stored_item = self.get_item(item.id)
item.update(dict(stored_item))
item.clear_dirty()
def store(self, item):
"""Save the item's metadata into the library database.
"""
# Build assignments for query.
assignments = ''
subvars = []
for key in ITEM_KEYS:
if key != 'id' and key in item._dirty:
assignments += key + '=?,'
value = getattr(item, key)
# Wrap path strings in buffers so they get stored
# "in the raw".
if key == 'path' and isinstance(value, str):
value = buffer(value)
subvars.append(value)
assignments = assignments[:-1] # Knock off last ,
with self.transaction() as tx:
# Main table update.
if assignments:
query = 'UPDATE items SET ' + assignments + ' WHERE id=?'
subvars.append(item.id)
tx.mutate(query, subvars)
# Flexible attributes.
flexins = 'INSERT INTO item_attributes ' \
' (entity_id, key, value)' \
' VALUES (?, ?, ?)'
for key, value in item._values_flex.items():
tx.mutate(flexins, (item.id, key, value))
item.clear_dirty()
self._memotable = {}
def remove(self, item, delete=False, with_album=True):
"""Removes this item. If delete, then the associated file is
removed from disk. If with_album, then the item's album (if any)
@ -1531,7 +1490,7 @@ class Library(object):
old_path = item.path
item.move(dest, copy)
if item.id is not None:
self.store(item)
item.store()
# If this item is in an album, move its art.
if with_album:
@ -1648,7 +1607,7 @@ class Library(object):
if item.id is None:
self.add(item)
else:
self.store(item)
item.store()
# Construct the new Album object.
album_values['id'] = album_id

View file

@ -941,14 +941,14 @@ def update_items(lib, query, album, move, pretend):
if move and lib.directory in ancestry(item.path):
lib.move(item)
lib.store(item)
item.store()
affected_albums.add(item.album_id)
elif not pretend:
# The file's mtime was different, but there were no changes
# to the metadata. Store the new mtime, which is set in the
# call to read(), so we don't check this again in the
# future.
lib.store(item)
item.store()
# Skip album changes while pretending.
if pretend:
@ -1163,10 +1163,7 @@ def modify_items(lib, mods, query, write, move, album, confirm):
else:
lib.move(obj)
if album:
obj.store()
else:
lib.store(obj)
obj.store()
# Apply tags if requested.
if write:
@ -1223,7 +1220,7 @@ def move_items(lib, dest, query, copy, album):
obj.move(copy, basedir=dest)
else:
lib.move(obj, copy, basedir=dest)
lib.store(obj)
obj.store()
move_cmd = ui.Subcommand('move',
help='move or copy items', aliases=('mv',))

View file

@ -160,7 +160,7 @@ class AcoustidPlugin(plugins.BeetsPlugin):
help='generate fingerprints for items without them')
def fingerprint_cmd_func(lib, opts, args):
for item in lib.items(ui.decargs(args)):
fingerprint_item(item, lib=lib,
fingerprint_item(item,
write=config['import']['write'].get(bool))
fingerprint_cmd.func = fingerprint_cmd_func
@ -237,12 +237,12 @@ def submit_items(userkey, items, chunksize=64):
submit_chunk()
def fingerprint_item(item, lib=None, write=False):
def fingerprint_item(item, write=False):
"""Get the fingerprint for an Item. If the item already has a
fingerprint, it is not regenerated. If fingerprint generation fails,
return None. If `lib` is provided, then new fingerprints are saved
to the database. If `write` is set, then the new fingerprints are
also written to files' metadata.
return None. If the items are associated with a library, they are
saved to the database. If `write` is set, then the new fingerprints
are also written to files' metadata.
"""
# Get a fingerprint and length for this track.
if not item.length:
@ -271,8 +271,8 @@ def fingerprint_item(item, lib=None, write=False):
util.displayable_path(item.path)
))
item.write()
if lib:
lib.store(item)
if item._lib:
item.store()
return item.acoustid_fingerprint
except acoustid.FingerprintGenerationError as exc:
log.info(

View file

@ -120,7 +120,7 @@ def convert_item(lib, dest_dir, keep_new, path_formats):
# writing) to get new bitrate, duration, etc.
if keep_new:
item.read()
lib.store(item) # Store new path and audio data.
item.store() # Store new path and audio data.
if config['convert']['embed']:
album = lib.get_album(item)
@ -142,7 +142,7 @@ def convert_on_import(lib, item):
item.path = dest
item.write()
item.read() # Load new audio information data.
lib.store(item)
item.store()
def convert_func(lib, opts, args):

View file

@ -54,7 +54,7 @@ def fetch_item_tempo(lib, loglevel, item, write):
item.bpm = tempo
if write:
item.write()
lib.store(item)
item.store()
def get_tempo(artist, title):
"""Get the tempo for a song."""

View file

@ -335,7 +335,7 @@ class LastGenrePlugin(plugins.BeetsPlugin):
# track on the album.
if 'track' in self.sources:
item.genre, src = self._get_genre(item)
lib.store(item)
item.store()
log.info(u'genre for track {0} - {1} ({2}): {3}'.format(
item.artist, item.title, src, item.genre
))
@ -353,17 +353,18 @@ class LastGenrePlugin(plugins.BeetsPlugin):
album.genre, src = self._get_genre(album)
log.debug(u'added last.fm album genre ({0}): {1}'.format(
src, album.genre))
album.store()
if 'track' in self.sources:
for item in album.items():
item.genre, src = self._get_genre(item)
log.debug(u'added last.fm item genre ({0}): {1}'.format(
src, item.genre))
session.lib.store(item)
item.store()
else:
item = task.item
item.genre, src = self._get_genre(item)
log.debug(u'added last.fm item genre ({0}): {1}'.format(
src, item.genre))
session.lib.store(item)
item.store()

View file

@ -444,7 +444,7 @@ class LyricsPlugin(BeetsPlugin):
if write:
item.write()
lib.store(item)
item.store()
def get_lyrics(self, artist, title):
"""Fetch lyrics, trying each source in turn. Return a string or

View file

@ -53,7 +53,7 @@ def _print_and_apply_changes(lib, item, move, pretend, write):
log.error(u'could not sync {0}: {1}'.format(
util.displayable_path(item.path), exc))
return False
lib.store(item)
item.store()
return True

View file

@ -225,7 +225,7 @@ class ReplayGainPlugin(BeetsPlugin):
for item, info in zip(items, rgain_infos):
item.rg_track_gain = info['gain']
item.rg_track_peak = info['peak']
lib.store(item)
item.store()
log.debug(u'replaygain: applied track gain {0}, peak {1}'.format(
item.rg_track_gain,
@ -241,3 +241,4 @@ class ReplayGainPlugin(BeetsPlugin):
album.rg_album_gain,
album.rg_album_peak
))
album.store()

View file

@ -40,7 +40,7 @@ def remove_lib():
if os.path.exists(TEMP_LIB):
os.unlink(TEMP_LIB)
def boracay(l):
return beets.library.Item(
return beets.library.Item(l,
**l._connection().execute('select * from items where id=3').fetchone()
)
np = util.normpath
@ -56,12 +56,12 @@ class LoadTest(unittest.TestCase):
def test_load_restores_data_from_db(self):
original_title = self.i.title
self.i.title = 'something'
self.lib.load(self.i)
self.i.load()
self.assertEqual(original_title, self.i.title)
def test_load_clears_dirty_flags(self):
self.i.artist = 'something'
self.lib.load(self.i)
self.i.load()
self.assertTrue('artist' not in self.i._dirty)
class StoreTest(unittest.TestCase):
@ -74,7 +74,7 @@ class StoreTest(unittest.TestCase):
def test_store_changes_database_value(self):
self.i.year = 1987
self.lib.store(self.i)
self.i.store()
new_year = self.lib._connection().execute(
'select year from items where '
'title="Boracay"').fetchone()['year']
@ -83,7 +83,7 @@ class StoreTest(unittest.TestCase):
def test_store_only_writes_dirty_fields(self):
original_genre = self.i.genre
self.i._values_fixed['genre'] = 'beatboxing' # change w/o dirtying
self.lib.store(self.i)
self.i.store()
new_genre = self.lib._connection().execute(
'select genre from items where '
'title="Boracay"').fetchone()['genre']
@ -91,7 +91,7 @@ class StoreTest(unittest.TestCase):
def test_store_clears_dirty_flags(self):
self.i.composer = 'tvp'
self.lib.store(self.i)
self.i.store()
self.assertTrue('composer' not in self.i._dirty)
class AddTest(unittest.TestCase):
@ -884,7 +884,7 @@ class PathStringTest(_common.TestCase):
def test_special_chars_preserved_in_database(self):
path = 'b\xe1r'
self.i.path = path
self.lib.store(self.i)
self.i.store()
i = list(self.lib.items())[0]
self.assertEqual(i.path, path)

View file

@ -171,7 +171,7 @@ class AlbumFileTest(_common.TestCase):
self.ai.album = 'newAlbumName'
self.ai.move()
self.ai.store()
self.lib.load(self.i)
self.i.load()
self.assert_('newAlbumName' in self.i.path)
@ -180,7 +180,7 @@ class AlbumFileTest(_common.TestCase):
self.ai.album = 'newAlbumName'
self.ai.move()
self.ai.store()
self.lib.load(self.i)
self.i.load()
self.assertFalse(os.path.exists(oldpath))
self.assertTrue(os.path.exists(self.i.path))
@ -190,14 +190,14 @@ class AlbumFileTest(_common.TestCase):
self.ai.album = 'newAlbumName'
self.ai.move(True)
self.ai.store()
self.lib.load(self.i)
self.i.load()
self.assertTrue(os.path.exists(oldpath))
self.assertTrue(os.path.exists(self.i.path))
def test_albuminfo_move_to_custom_dir(self):
self.ai.move(basedir=self.otherdir)
self.lib.load(self.i)
self.i.load()
self.ai.store()
self.assertTrue('testotherdir' in self.i.path)
@ -234,7 +234,7 @@ class ArtFileTest(_common.TestCase):
oldpath = self.i.path
self.ai.album = 'newAlbum'
self.ai.move()
self.lib.load(self.i)
self.i.load()
self.assertNotEqual(self.i.path, oldpath)
self.assertFalse(os.path.exists(self.art))
@ -245,7 +245,7 @@ class ArtFileTest(_common.TestCase):
# Move the album to another directory.
self.ai.move(basedir=self.otherdir)
self.ai.store()
self.lib.load(self.i)
self.i.load()
# Art should be in new directory.
self.assertNotExists(self.art)

View file

@ -16,7 +16,7 @@ class IHatePluginTest(unittest.TestCase):
task = ImportTask()
task.cur_artist = u'Test Artist'
task.cur_album = u'Test Album'
task.items = [Item({'genre': 'Test Genre'})]
task.items = [Item(genre='Test Genre')]
self.assertFalse(IHatePlugin.do_i_hate_this(task, genre_p, artist_p,
album_p, white_p))
genre_p = 'some_genre test\sgenre'.split()

View file

@ -193,6 +193,7 @@ class ImportApplyTest(_common.TestCase):
shutil.copy(os.path.join(_common.RSRC, 'full.mp3'), self.srcpath)
self.i = library.Item.from_path(self.srcpath)
self.i.comp = False
self.lib.add(self.i)
trackinfo = TrackInfo('one', 'trackid', 'some artist',
'artistid', 1)

View file

@ -299,7 +299,7 @@ class MemoryGetTest(unittest.TestCase, AssertsMixin):
def test_unicode_query(self):
self.single_item.title = u'caf\xe9'
self.lib.store(self.single_item)
self.single_item.store()
q = u'title:caf\xe9'
results = self.lib.items(q)

View file

@ -54,7 +54,7 @@ class ListTest(_common.TestCase):
def test_list_unicode_query(self):
self.item.title = u'na\xefve'
self.lib.store(self.item)
self.item.store()
self.lib._connection().commit()
self._run_list([u'na\xefve'])
@ -241,42 +241,42 @@ class MoveTest(_common.TestCase):
def test_move_item(self):
self._move()
self.lib.load(self.i)
self.i.load()
self.assertTrue('testlibdir' in self.i.path)
self.assertExists(self.i.path)
self.assertNotExists(self.itempath)
def test_copy_item(self):
self._move(copy=True)
self.lib.load(self.i)
self.i.load()
self.assertTrue('testlibdir' in self.i.path)
self.assertExists(self.i.path)
self.assertExists(self.itempath)
def test_move_album(self):
self._move(album=True)
self.lib.load(self.i)
self.i.load()
self.assertTrue('testlibdir' in self.i.path)
self.assertExists(self.i.path)
self.assertNotExists(self.itempath)
def test_copy_album(self):
self._move(copy=True, album=True)
self.lib.load(self.i)
self.i.load()
self.assertTrue('testlibdir' in self.i.path)
self.assertExists(self.i.path)
self.assertExists(self.itempath)
def test_move_item_custom_dir(self):
self._move(dest=self.otherdir)
self.lib.load(self.i)
self.i.load()
self.assertTrue('testotherdir' in self.i.path)
self.assertExists(self.i.path)
self.assertNotExists(self.itempath)
def test_move_album_custom_dir(self):
self._move(dest=self.otherdir, album=True)
self.lib.load(self.i)
self.i.load()
self.assertTrue('testotherdir' in self.i.path)
self.assertExists(self.i.path)
self.assertNotExists(self.itempath)
@ -306,7 +306,7 @@ class UpdateTest(_common.TestCase):
self.io.addinput('y')
if reset_mtime:
self.i.mtime = 0
self.lib.store(self.i)
self.i.store()
commands.update_items(self.lib, query, album, move, False)
def test_delete_removes_item(self):
@ -376,7 +376,7 @@ class UpdateTest(_common.TestCase):
# Make in-memory mtime match on-disk mtime.
self.i.mtime = os.path.getmtime(self.i.path)
self.lib.store(self.i)
self.i.store()
self._update(reset_mtime=False)
item = self.lib.items().get()