diff --git a/beets/dbcore/db.py b/beets/dbcore/db.py index ef7231a76..a714d9492 100755 --- a/beets/dbcore/db.py +++ b/beets/dbcore/db.py @@ -236,7 +236,7 @@ class Model(object): if key in getters: # Computed. return getters[key](self) elif key in self._fields: # Fixed. - return self._values_fixed.get(key) + return self._values_fixed.get(key, self._type(key).null) elif key in self._values_flex: # Flexible. return self._values_flex[key] else: diff --git a/beets/library.py b/beets/library.py index 0a64516ad..f294e6d4f 100644 --- a/beets/library.py +++ b/beets/library.py @@ -144,10 +144,27 @@ class DateType(types.Float): class PathType(types.Type): + """A dbcore type for filesystem paths. These are represented as + `bytes` objects, in keeping with the Unix filesystem abstraction. + """ + sql = u'BLOB' query = PathQuery model_type = bytes + def __init__(self, nullable=False): + """Create a path type object. `nullable` controls whether the + type may be missing, i.e., None. + """ + self.nullable = nullable + + @property + def null(self): + if self.nullable: + return None + else: + return b'' + def format(self, value): return util.displayable_path(value) @@ -188,6 +205,8 @@ class MusicalKey(types.String): r'bb': 'a#', } + null = None + def parse(self, key): key = key.lower() for flat, sharp in self.ENHARMONIC.items(): @@ -873,7 +892,7 @@ class Album(LibModel): _always_dirty = True _fields = { 'id': types.PRIMARY_ID, - 'artpath': PathType(), + 'artpath': PathType(True), 'added': DateType(), 'albumartist': types.STRING, diff --git a/test/test_dbcore.py b/test/test_dbcore.py index d070e257e..d2d97d4b3 100644 --- a/test/test_dbcore.py +++ b/test/test_dbcore.py @@ -320,7 +320,7 @@ class ModelTest(unittest.TestCase): def test_items(self): model = TestModel1(self.db) model.id = 5 - self.assertEqual({('id', 5), ('field_one', None)}, + self.assertEqual({('id', 5), ('field_one', 0)}, set(model.items())) def test_delete_internal_field(self): diff --git a/test/test_ipfs.py b/test/test_ipfs.py index 9c523d6e5..d670bfc25 100644 --- a/test/test_ipfs.py +++ b/test/test_ipfs.py @@ -67,17 +67,17 @@ class IPFSPluginTest(unittest.TestCase, TestHelper): def mk_test_album(self): items = [_common.item() for _ in range(3)] items[0].title = 'foo bar' - items[0].artist = 'one' + items[0].artist = '1one' items[0].album = 'baz' items[0].year = 2001 items[0].comp = True items[1].title = 'baz qux' - items[1].artist = 'two' + items[1].artist = '2two' items[1].album = 'baz' items[1].year = 2002 items[1].comp = True items[2].title = 'beets 4 eva' - items[2].artist = 'three' + items[2].artist = '3three' items[2].album = 'foo' items[2].year = 2003 items[2].comp = False diff --git a/test/test_query.py b/test/test_query.py index 61df3ca10..c0ab2a171 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -79,10 +79,10 @@ class AnyFieldQueryTest(_common.LibTestCase): class AssertsMixin(object): def assert_items_matched(self, results, titles): - self.assertEqual([i.title for i in results], titles) + self.assertEqual(set([i.title for i in results]), set(titles)) def assert_albums_matched(self, results, albums): - self.assertEqual([a.album for a in results], albums) + self.assertEqual(set([a.album for a in results]), set(albums)) # A test case class providing a library with some dummy data and some