diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index ce0582f893..b94258b1ef 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -1140,7 +1140,12 @@ class Cache(object): path_map[book_id] = path self.backend.remove_books(path_map, permanent=permanent) for field in self.fields.itervalues(): - field.table.remove_books(book_ids, self.backend) + try: + table = field.table + except AttributeError: + continue # Some fields like ondevice do not have tables + else: + table.remove_books(book_ids, self.backend) # }}} diff --git a/src/calibre/db/tests/add_remove.py b/src/calibre/db/tests/add_remove.py index 5744d63635..5d490a2bcb 100644 --- a/src/calibre/db/tests/add_remove.py +++ b/src/calibre/db/tests/add_remove.py @@ -204,3 +204,42 @@ class AddRemoveTest(BaseTest): self.assertEqual(cache.format(book_id, 'FMT2'), FMT2) # }}} + def test_remove_books(self): # {{{ + 'Test removal of books' + cache = self.init_cache() + af, ae, at = self.assertFalse, self.assertEqual, self.assertTrue + authors = cache.fields['authors'].table + + # Delete a single book, with no formats and check cleaning + self.assertIn(_('Unknown'), set(authors.id_map.itervalues())) + olen = len(authors.id_map) + item_id = {v:k for k, v in authors.id_map.iteritems()}[_('Unknown')] + cache.remove_books((3,)) + for c in (cache, self.init_cache()): + table = c.fields['authors'].table + self.assertNotIn(3, c.all_book_ids()) + self.assertNotIn(_('Unknown'), set(table.id_map.itervalues())) + self.assertNotIn(item_id, table.asort_map) + self.assertNotIn(item_id, table.alink_map) + ae(len(table.id_map), olen-1) + + # Check that files are removed + fmtpath = cache.format_abspath(1, 'FMT1') + bookpath = os.path.dirname(fmtpath) + authorpath = os.path.dirname(bookpath) + item_id = {v:k for k, v in cache.fields['#series'].table.id_map.iteritems()}['My Series Two'] + cache.remove_books((1,), permanent=True) + for x in (fmtpath, bookpath, authorpath): + af(os.path.exists(x)) + for c in (cache, self.init_cache()): + table = c.fields['authors'].table + self.assertNotIn(1, c.all_book_ids()) + self.assertNotIn('Author Two', set(table.id_map.itervalues())) + self.assertNotIn(6, set(c.fields['rating'].table.id_map.itervalues())) + self.assertIn('A Series One', set(c.fields['series'].table.id_map.itervalues())) + self.assertNotIn('My Series Two', set(c.fields['#series'].table.id_map.itervalues())) + self.assertNotIn(item_id, c.fields['#series'].table.col_book_map) + self.assertNotIn(1, c.fields['#series'].table.book_col_map) + # }}} + +