diff --git a/beets/dbcore.py b/beets/dbcore.py index c8ae49490..12b95e015 100644 --- a/beets/dbcore.py +++ b/beets/dbcore.py @@ -119,11 +119,11 @@ class Model(object): # Basic operation. - def __init__(self, lib=None, **values): - """Create a new object with an optional Library association and + def __init__(self, db=None, **values): + """Create a new object with an optional Database association and initial field values. """ - self._lib = lib + self._db = db self._dirty = set() self._values_fixed = {} self._values_flex = {} @@ -146,11 +146,11 @@ class Model(object): def _check_db(self, need_id=True): """Ensure that this object is associated with a database row: it - has a reference to a library (`_lib`) and an id. A ValueError + has a reference to a database (`_db`) and an id. A ValueError exception is raised otherwise. """ - if not self._lib: - raise ValueError('{0} has no library'.format(type(self).__name__)) + if not self._db: + raise ValueError('{0} has no database'.format(type(self).__name__)) if need_id and not self.id: raise ValueError('{0} has no id'.format(type(self).__name__)) @@ -268,7 +268,7 @@ class Model(object): subvars.append(value) assignments = assignments[:-1] # Knock off last , - with self._lib.transaction() as tx: + with self._db.transaction() as tx: # Main table update. if assignments: query = 'UPDATE {0} SET {1} WHERE id=?'.format( @@ -293,7 +293,7 @@ class Model(object): """Refresh the object's metadata from the library database. """ self._check_db() - stored_obj = self._lib._get(type(self), self.id) + stored_obj = self._db._get(type(self), self.id) self.update(dict(stored_obj)) self.clear_dirty() @@ -301,7 +301,7 @@ class Model(object): """Remove the object's associated rows from the database. """ self._check_db() - with self._lib.transaction() as tx: + with self._db.transaction() as tx: tx.mutate( 'DELETE FROM {0} WHERE id=?'.format(self._table), (self.id,) @@ -311,19 +311,19 @@ class Model(object): (self.id,) ) - def add(self, lib=None): + def add(self, db=None): """Add the object to the library database. This object must be - associated with a library; you can provide one via the `lib` - parameter or use the currently associated library. + associated with a database; you can provide one via the `db` + parameter or use the currently associated database. The object's `id` and `added` fields are set along with any current field values. """ - if lib: - self._lib = lib + if db: + self._db = db self._check_db(False) - with self._lib.transaction() as tx: + with self._db.transaction() as tx: new_id = tx.mutate( 'INSERT INTO {0} DEFAULT VALUES'.format(self._table) ) @@ -462,17 +462,17 @@ class Results(object): """An item query result set. Iterating over the collection lazily constructs LibModel objects that reflect database rows. """ - def __init__(self, model_class, rows, lib, query=None): + def __init__(self, model_class, rows, db, query=None): """Create a result set that will construct objects of type `model_class`, which should be a subclass of `LibModel`, out of the query result mapping in `rows`. The new objects are - associated with the library `lib`. If `query` is provided, it is + associated with the database `db`. If `query` is provided, it is used as a predicate to filter the results for a "slow query" that cannot be evaluated by the database directly. """ self.model_class = model_class self.rows = rows - self.lib = lib + self.db = db self.query = query def __iter__(self): @@ -481,7 +481,7 @@ class Results(object): """ for row in self.rows: # Get the flexible attributes for the object. - with self.lib.transaction() as tx: + with self.db.transaction() as tx: flex_rows = tx.query( 'SELECT * FROM {0} WHERE entity_id=?'.format( self.model_class._flex_table @@ -495,7 +495,7 @@ class Results(object): # Construct the Python object and yield it if it passes the # predicate. - obj = self.model_class(self.lib, **values) + obj = self.model_class(self.db, **values) if not self.query or self.query.match(obj): yield obj @@ -545,20 +545,20 @@ class Transaction(object): """A context manager for safe, concurrent access to the database. All SQL commands should be executed through a transaction. """ - def __init__(self, lib): - self.lib = lib + def __init__(self, db): + self.db = db def __enter__(self): """Begin a transaction. This transaction may be created while another is active in a different thread. """ - with self.lib._tx_stack() as stack: + with self.db._tx_stack() as stack: first = not stack stack.append(self) if first: # Beginning a "root" transaction, which corresponds to an # SQLite transaction. - self.lib._db_lock.acquire() + self.db._db_lock.acquire() return self def __exit__(self, exc_type, exc_value, traceback): @@ -566,31 +566,31 @@ class Transaction(object): entered but not yet exited transaction. If it is the last active transaction, the database updates are committed. """ - with self.lib._tx_stack() as stack: + with self.db._tx_stack() as stack: assert stack.pop() is self empty = not stack if empty: # Ending a "root" transaction. End the SQLite transaction. - self.lib._connection().commit() - self.lib._db_lock.release() + self.db._connection().commit() + self.db._db_lock.release() def query(self, statement, subvals=()): """Execute an SQL statement with substitution values and return a list of rows from the database. """ - cursor = self.lib._connection().execute(statement, subvals) + cursor = self.db._connection().execute(statement, subvals) return cursor.fetchall() def mutate(self, statement, subvals=()): """Execute an SQL statement with substitution values and return the row ID of the last affected row. """ - cursor = self.lib._connection().execute(statement, subvals) + cursor = self.db._connection().execute(statement, subvals) return cursor.lastrowid def script(self, statements): """Execute a string containing multiple SQL statements.""" - self.lib._connection().executescript(statements) + self.db._connection().executescript(statements) class Database(object): @@ -670,7 +670,7 @@ class Database(object): # Schema setup and migration. def _make_table(self, table, fields): - """Set up the schema of the library file. `fields` is a mapping + """Set up the schema of the database. `fields` is a mapping from field names to `Type`s. Columns are added if necessary. """ # Get current schema. @@ -743,7 +743,7 @@ class Database(object): return Results(model_cls, rows, self, None if where else query) def _get(self, model_cls, id): - """Get a LibModel object by its id or None if the id does not + """Get a Model object by its id or None if the id does not exist. """ return self._fetch(model_cls, MatchQuery('id', id)).get() diff --git a/beets/library.py b/beets/library.py index fdb227769..3be543e3c 100644 --- a/beets/library.py +++ b/beets/library.py @@ -212,21 +212,21 @@ class LibModel(dbcore.Model): # FIXME should be able to replace this with field types. def _template_funcs(self): - funcs = DefaultTemplateFunctions(self, self._lib).functions() + funcs = DefaultTemplateFunctions(self, self._db).functions() funcs.update(plugins.template_funcs()) return funcs def store(self): super(LibModel, self).store() - plugins.send('database_change', lib=self._lib) + plugins.send('database_change', lib=self._db) def remove(self): super(LibModel, self).remove() - plugins.send('database_change', lib=self._lib) + plugins.send('database_change', lib=self._db) def add(self, lib=None): super(LibModel, self).add(lib) - plugins.send('database_change', lib=self._lib) + plugins.send('database_change', lib=self._db) class Item(LibModel): @@ -277,9 +277,9 @@ class Item(LibModel): None if the item is a singleton or is not associated with a library. """ - if not self._lib: + if not self._db: return None - return self._lib.get_album(self) + return self._db.get_album(self) # Interaction with file metadata. @@ -388,9 +388,9 @@ class Item(LibModel): # Delete the associated file. if delete: util.remove(self.path) - util.prune_dirs(os.path.dirname(self.path), self._lib.directory) + util.prune_dirs(os.path.dirname(self.path), self._db.directory) - self._lib._memotable = {} + self._db._memotable = {} def move(self, copy=False, basedir=None, with_album=True): """Move the item to its designated location within the library @@ -432,7 +432,7 @@ class Item(LibModel): # Prune vacated directory. if not copy: - util.prune_dirs(os.path.dirname(old_path), self._lib.directory) + util.prune_dirs(os.path.dirname(old_path), self._db.directory) # Templating. @@ -470,8 +470,8 @@ class Item(LibModel): """ self._check_db() platform = platform or sys.platform - basedir = basedir or self._lib.directory - path_formats = path_formats or self._lib.path_formats + basedir = basedir or self._db.directory + path_formats = path_formats or self._db.path_formats # Use a path format based on a query, falling back on the # default. @@ -504,7 +504,7 @@ class Item(LibModel): else: subpath = unicodedata.normalize('NFC', subpath) # Truncate components and remove forbidden characters. - subpath = util.sanitize_path(subpath, self._lib.replacements) + subpath = util.sanitize_path(subpath, self._db.replacements) # Encode for the filesystem. if not fragment: subpath = bytestring_path(subpath) @@ -520,7 +520,7 @@ class Item(LibModel): maxlen = beets.config['max_filename_length'].get(int) if not maxlen: # When zero, try to determine from filesystem. - maxlen = util.max_filename_length(self._lib.directory) + maxlen = util.max_filename_length(self._db.directory) subpath = util.truncate_path(subpath, maxlen) if fragment: @@ -560,7 +560,7 @@ class Album(LibModel): """Returns an iterable over the items associated with this album. """ - return self._lib.items(dbcore.MatchQuery('album_id', self.id)) + return self._db.items(dbcore.MatchQuery('album_id', self.id)) def remove(self, delete=False, with_items=True): """Removes this album and all its associated items from the @@ -605,7 +605,7 @@ class Album(LibModel): # Prune old path when moving. if not copy: util.prune_dirs(os.path.dirname(old_art), - self._lib.directory) + self._db.directory) def move(self, copy=False, basedir=None): """Moves (or copies) all items to their destination. Any album @@ -613,7 +613,7 @@ class Album(LibModel): directory for the destination. The album is stored to the database, persisting any modifications to its metadata. """ - basedir = basedir or self._lib.directory + basedir = basedir or self._db.directory # Ensure new metadata is available to items for destination # computation. @@ -652,7 +652,7 @@ class Album(LibModel): filename_tmpl = Template(beets.config['art_filename'].get(unicode)) subpath = self.evaluate_template(filename_tmpl, True) subpath = util.sanitize_path(subpath, - replacements=self._lib.replacements) + replacements=self._db.replacements) subpath = bytestring_path(subpath) _, ext = os.path.splitext(image) @@ -697,7 +697,7 @@ class Album(LibModel): if key in self._dirty: track_updates[key] = self[key] - with self._lib.transaction(): + with self._db.transaction(): super(Album, self).store() if track_updates: for item in self.items(): diff --git a/beetsplug/chroma.py b/beetsplug/chroma.py index acdb71350..d1624c6be 100644 --- a/beetsplug/chroma.py +++ b/beetsplug/chroma.py @@ -271,7 +271,7 @@ def fingerprint_item(item, write=False): util.displayable_path(item.path) )) item.write() - if item._lib: + if item._db: item.store() return item.acoustid_fingerprint except acoustid.FingerprintGenerationError as exc: diff --git a/test/test_dbcore.py b/test/test_dbcore.py index 7b59b4b87..0b2b2b944 100644 --- a/test/test_dbcore.py +++ b/test/test_dbcore.py @@ -1,5 +1,5 @@ # This file is part of beets. -# Copyright 2013, Adrian Sampson. +# Copyright 2014, Adrian Sampson. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the