mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
648456293b
@ -306,7 +306,8 @@ class DB(object):
|
|||||||
|
|
||||||
# Initialize database {{{
|
# Initialize database {{{
|
||||||
|
|
||||||
def __init__(self, library_path, default_prefs=None, read_only=False):
|
def __init__(self, library_path, default_prefs=None, read_only=False,
|
||||||
|
restore_all_prefs=False, progress_callback=lambda x, y:True):
|
||||||
try:
|
try:
|
||||||
if isbytestring(library_path):
|
if isbytestring(library_path):
|
||||||
library_path = library_path.decode(filesystem_encoding)
|
library_path = library_path.decode(filesystem_encoding)
|
||||||
@ -377,23 +378,27 @@ class DB(object):
|
|||||||
UPDATE authors SET sort=author_to_author_sort(name) WHERE sort IS NULL;
|
UPDATE authors SET sort=author_to_author_sort(name) WHERE sort IS NULL;
|
||||||
''')
|
''')
|
||||||
|
|
||||||
self.initialize_prefs(default_prefs)
|
self.initialize_prefs(default_prefs, restore_all_prefs, progress_callback)
|
||||||
self.initialize_custom_columns()
|
self.initialize_custom_columns()
|
||||||
self.initialize_tables()
|
self.initialize_tables()
|
||||||
|
|
||||||
def initialize_prefs(self, default_prefs): # {{{
|
def initialize_prefs(self, default_prefs, restore_all_prefs, progress_callback): # {{{
|
||||||
self.prefs = DBPrefs(self)
|
self.prefs = DBPrefs(self)
|
||||||
|
|
||||||
if default_prefs is not None and not self._exists:
|
if default_prefs is not None and not self._exists:
|
||||||
|
progress_callback(None, len(default_prefs))
|
||||||
# Only apply default prefs to a new database
|
# Only apply default prefs to a new database
|
||||||
for key in default_prefs:
|
for i, key in enumerate(default_prefs):
|
||||||
# be sure that prefs not to be copied are listed below
|
# be sure that prefs not to be copied are listed below
|
||||||
if key not in frozenset(['news_to_be_synced']):
|
if restore_all_prefs or key not in frozenset(['news_to_be_synced']):
|
||||||
self.prefs[key] = default_prefs[key]
|
self.prefs[key] = default_prefs[key]
|
||||||
|
progress_callback(_('restored preference ') + key, i+1)
|
||||||
if 'field_metadata' in default_prefs:
|
if 'field_metadata' in default_prefs:
|
||||||
fmvals = [f for f in default_prefs['field_metadata'].values()
|
fmvals = [f for f in default_prefs['field_metadata'].values()
|
||||||
if f['is_custom']]
|
if f['is_custom']]
|
||||||
for f in fmvals:
|
progress_callback(None, len(fmvals))
|
||||||
|
for i, f in enumerate(fmvals):
|
||||||
|
progress_callback(_('creating custom column ') + f['label'], i)
|
||||||
self.create_custom_column(f['label'], f['name'],
|
self.create_custom_column(f['label'], f['name'],
|
||||||
f['datatype'],
|
f['datatype'],
|
||||||
(f['is_multiple'] is not None and
|
(f['is_multiple'] is not None and
|
||||||
@ -774,6 +779,11 @@ class DB(object):
|
|||||||
self._conn = Connection(self.dbpath)
|
self._conn = Connection(self.dbpath)
|
||||||
return self._conn
|
return self._conn
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self._conn is not None:
|
||||||
|
self._conn.close()
|
||||||
|
del self._conn
|
||||||
|
|
||||||
@dynamic_property
|
@dynamic_property
|
||||||
def user_version(self):
|
def user_version(self):
|
||||||
doc = 'The user version of this database'
|
doc = 'The user version of this database'
|
||||||
|
77
src/calibre/db/legacy.py
Normal file
77
src/calibre/db/legacy.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from calibre.db.backend import DB
|
||||||
|
from calibre.db.cache import Cache
|
||||||
|
from calibre.db.view import View
|
||||||
|
|
||||||
|
class LibraryDatabase(object):
|
||||||
|
|
||||||
|
PATH_LIMIT = DB.PATH_LIMIT
|
||||||
|
WINDOWS_LIBRARY_PATH_LIMIT = DB.WINDOWS_LIBRARY_PATH_LIMIT
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def exists_at(cls, path):
|
||||||
|
return path and os.path.exists(os.path.join(path, 'metadata.db'))
|
||||||
|
|
||||||
|
def __init__(self, library_path,
|
||||||
|
default_prefs=None, read_only=False, is_second_db=False,
|
||||||
|
progress_callback=lambda x, y:True, restore_all_prefs=False):
|
||||||
|
|
||||||
|
self.is_second_db = is_second_db # TODO: Use is_second_db
|
||||||
|
|
||||||
|
backend = self.backend = DB(library_path, default_prefs=default_prefs,
|
||||||
|
read_only=read_only, restore_all_prefs=restore_all_prefs,
|
||||||
|
progress_callback=progress_callback)
|
||||||
|
cache = Cache(backend)
|
||||||
|
cache.init()
|
||||||
|
self.data = View(cache)
|
||||||
|
|
||||||
|
self.get_property = self.data.get_property
|
||||||
|
self.all_ids = self.data.cache.all_book_ids
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.backend.close()
|
||||||
|
|
||||||
|
def break_cycles(self):
|
||||||
|
self.data.cache.backend = None
|
||||||
|
self.data.cache = None
|
||||||
|
self.data = self.backend = self.field_metadata = self.prefs = self.listeners = self.refresh_ondevice = None
|
||||||
|
|
||||||
|
# Library wide properties {{{
|
||||||
|
@property
|
||||||
|
def field_metadata(self):
|
||||||
|
return self.backend.field_metadata
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user_version(self):
|
||||||
|
return self.backend.user_version
|
||||||
|
|
||||||
|
@property
|
||||||
|
def library_id(self):
|
||||||
|
return self.backend.library_id
|
||||||
|
|
||||||
|
def last_modified(self):
|
||||||
|
return self.backend.last_modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def custom_column_num_map(self):
|
||||||
|
return self.backend.custom_column_num_map
|
||||||
|
|
||||||
|
@property
|
||||||
|
def custom_column_label_map(self):
|
||||||
|
return self.backend.custom_column_label_map
|
||||||
|
|
||||||
|
@property
|
||||||
|
def FIELD_MAP(self):
|
||||||
|
return self.backend.FIELD_MAP
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
@ -16,6 +16,9 @@ rmtree = partial(shutil.rmtree, ignore_errors=True)
|
|||||||
|
|
||||||
class BaseTest(unittest.TestCase):
|
class BaseTest(unittest.TestCase):
|
||||||
|
|
||||||
|
longMessage = True
|
||||||
|
maxDiff = None
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.library_path = self.mkdtemp()
|
self.library_path = self.mkdtemp()
|
||||||
self.create_db(self.library_path)
|
self.create_db(self.library_path)
|
||||||
@ -40,10 +43,10 @@ class BaseTest(unittest.TestCase):
|
|||||||
db.conn.close()
|
db.conn.close()
|
||||||
return dest
|
return dest
|
||||||
|
|
||||||
def init_cache(self, library_path):
|
def init_cache(self, library_path=None):
|
||||||
from calibre.db.backend import DB
|
from calibre.db.backend import DB
|
||||||
from calibre.db.cache import Cache
|
from calibre.db.cache import Cache
|
||||||
backend = DB(library_path)
|
backend = DB(library_path or self.library_path)
|
||||||
cache = Cache(backend)
|
cache = Cache(backend)
|
||||||
cache.init()
|
cache.init()
|
||||||
return cache
|
return cache
|
||||||
@ -53,9 +56,13 @@ class BaseTest(unittest.TestCase):
|
|||||||
atexit.register(rmtree, ans)
|
atexit.register(rmtree, ans)
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
def init_old(self, library_path):
|
def init_old(self, library_path=None):
|
||||||
from calibre.library.database2 import LibraryDatabase2
|
from calibre.library.database2 import LibraryDatabase2
|
||||||
return LibraryDatabase2(library_path)
|
return LibraryDatabase2(library_path or self.library_path)
|
||||||
|
|
||||||
|
def init_legacy(self, library_path=None):
|
||||||
|
from calibre.db.legacy import LibraryDatabase
|
||||||
|
return LibraryDatabase(library_path or self.library_path)
|
||||||
|
|
||||||
def clone_library(self, library_path):
|
def clone_library(self, library_path):
|
||||||
if not hasattr(self, 'clone_dir'):
|
if not hasattr(self, 'clone_dir'):
|
||||||
@ -81,7 +88,8 @@ class BaseTest(unittest.TestCase):
|
|||||||
'ondevice_col', 'last_modified', 'has_cover',
|
'ondevice_col', 'last_modified', 'has_cover',
|
||||||
'cover_data'}.union(allfk1)
|
'cover_data'}.union(allfk1)
|
||||||
for attr in all_keys:
|
for attr in all_keys:
|
||||||
if attr == 'user_metadata': continue
|
if attr == 'user_metadata':
|
||||||
|
continue
|
||||||
attr1, attr2 = getattr(mi1, attr), getattr(mi2, attr)
|
attr1, attr2 = getattr(mi1, attr), getattr(mi2, attr)
|
||||||
if attr == 'formats':
|
if attr == 'formats':
|
||||||
attr1, attr2 = map(lambda x:tuple(x) if x else (), (attr1, attr2))
|
attr1, attr2 = map(lambda x:tuple(x) if x else (), (attr1, attr2))
|
||||||
|
53
src/calibre/db/tests/legacy.py
Normal file
53
src/calibre/db/tests/legacy.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
|
from calibre.db.tests.base import BaseTest
|
||||||
|
|
||||||
|
class LegacyTest(BaseTest):
|
||||||
|
|
||||||
|
''' Test the emulation of the legacy interface. '''
|
||||||
|
|
||||||
|
def test_library_wide_properties(self): # {{{
|
||||||
|
'Test library wide properties'
|
||||||
|
old = self.init_old()
|
||||||
|
props = ('user_version', 'is_second_db', 'library_id', 'field_metadata',
|
||||||
|
'custom_column_label_map', 'custom_column_num_map')
|
||||||
|
oldvals = {x:getattr(old, x) for x in props}
|
||||||
|
oldvals['last_modified'] = old.last_modified()
|
||||||
|
old.close()
|
||||||
|
old = None
|
||||||
|
db = self.init_legacy()
|
||||||
|
newvals = {x:getattr(db, x) for x in props}
|
||||||
|
newvals['last_modified'] = db.last_modified()
|
||||||
|
self.assertEqual(oldvals, newvals)
|
||||||
|
db.close()
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
def test_get_property(self): # {{{
|
||||||
|
'Test the get_property interface for reading data'
|
||||||
|
def get_values(db):
|
||||||
|
ans = {}
|
||||||
|
for label, loc in db.FIELD_MAP.iteritems():
|
||||||
|
if isinstance(label, int):
|
||||||
|
label = '#'+db.custom_column_num_map[label]['label']
|
||||||
|
label = type('')(label)
|
||||||
|
ans[label] = tuple(db.get_property(i, index_is_id=True, loc=loc)
|
||||||
|
for i in db.all_ids())
|
||||||
|
return ans
|
||||||
|
|
||||||
|
old = self.init_old()
|
||||||
|
old_vals = get_values(old)
|
||||||
|
old.close()
|
||||||
|
old = None
|
||||||
|
db = self.init_legacy()
|
||||||
|
new_vals = get_values(db)
|
||||||
|
db.close()
|
||||||
|
self.assertEqual(old_vals, new_vals)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
@ -72,6 +72,10 @@ class View(object):
|
|||||||
self._map = tuple(self.cache.all_book_ids())
|
self._map = tuple(self.cache.all_book_ids())
|
||||||
self._map_filtered = tuple(self._map)
|
self._map_filtered = tuple(self._map)
|
||||||
|
|
||||||
|
def get_property(self, id_or_index, index_is_id=False, loc=-1):
|
||||||
|
book_id = id_or_index if index_is_id else self._map_filtered[id_or_index]
|
||||||
|
return self._field_getters[loc](book_id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def field_metadata(self):
|
def field_metadata(self):
|
||||||
return self.cache.field_metadata
|
return self.cache.field_metadata
|
||||||
|
@ -117,7 +117,7 @@ class CreateVirtualLibrary(QDialog): # {{{
|
|||||||
'<a href="tag.{1}">{1}</a>, '
|
'<a href="tag.{1}">{1}</a>, '
|
||||||
'<a href="publisher.{2}">{2}</a>, '
|
'<a href="publisher.{2}">{2}</a>, '
|
||||||
'<a href="series.{3}">{3}</a>, '
|
'<a href="series.{3}">{3}</a>, '
|
||||||
'<a href="search.{4}">{4}</a>, ').format(_('Authors'), _('Tags'),
|
'<a href="search.{4}">{4}</a>.').format(_('Authors'), _('Tags'),
|
||||||
_('Publishers'), _('Series'), _('Saved Searches')))
|
_('Publishers'), _('Series'), _('Saved Searches')))
|
||||||
sl.setWordWrap(True)
|
sl.setWordWrap(True)
|
||||||
sl.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
|
sl.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user