Kobo driver: Use the closing context manager for sqlite connections

This commit is contained in:
Kovid Goyal 2011-07-17 07:39:59 -06:00
parent 75172aa9cb
commit 8a21f74f32

View File

@ -7,6 +7,7 @@ __docformat__ = 'restructuredtext en'
import os import os
import sqlite3 as sqlite import sqlite3 as sqlite
from contextlib import closing
from calibre.devices.usbms.books import BookList from calibre.devices.usbms.books import BookList
from calibre.devices.kobo.books import Book from calibre.devices.kobo.books import Book
@ -192,77 +193,78 @@ class KOBO(USBMS):
traceback.print_exc() traceback.print_exc()
return changed return changed
connection = sqlite.connect(self.normalize_path(self._main_prefix + '.kobo/KoboReader.sqlite')) with closing(sqlite.connect(
self.normalize_path(self._main_prefix +
'.kobo/KoboReader.sqlite'))) as connection:
# return bytestrings if the content cannot the decoded as unicode # return bytestrings if the content cannot the decoded as unicode
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore") connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
cursor = connection.cursor() cursor = connection.cursor()
#query = 'select count(distinct volumeId) from volume_shortcovers' #query = 'select count(distinct volumeId) from volume_shortcovers'
#cursor.execute(query) #cursor.execute(query)
#for row in (cursor): #for row in (cursor):
# numrows = row[0] # numrows = row[0]
#cursor.close() #cursor.close()
# Determine the database version # Determine the database version
# 4 - Bluetooth Kobo Rev 2 (1.4) # 4 - Bluetooth Kobo Rev 2 (1.4)
# 8 - WIFI KOBO Rev 1 # 8 - WIFI KOBO Rev 1
cursor.execute('select version from dbversion') cursor.execute('select version from dbversion')
result = cursor.fetchone() result = cursor.fetchone()
self.dbversion = result[0] self.dbversion = result[0]
debug_print("Database Version: ", self.dbversion) debug_print("Database Version: ", self.dbversion)
if self.dbversion >= 16: if self.dbversion >= 16:
query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \ query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
'ImageID, ReadStatus, ___ExpirationStatus, FavouritesIndex, Accessibility from content where ' \ 'ImageID, ReadStatus, ___ExpirationStatus, FavouritesIndex, Accessibility from content where ' \
'BookID is Null and ( ___ExpirationStatus <> "3" or ___ExpirationStatus is Null)' 'BookID is Null and ( ___ExpirationStatus <> "3" or ___ExpirationStatus is Null)'
elif self.dbversion < 16 and self.dbversion >= 14: elif self.dbversion < 16 and self.dbversion >= 14:
query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \ query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
'ImageID, ReadStatus, ___ExpirationStatus, FavouritesIndex, "-1" as Accessibility from content where ' \ 'ImageID, ReadStatus, ___ExpirationStatus, FavouritesIndex, "-1" as Accessibility from content where ' \
'BookID is Null and ( ___ExpirationStatus <> "3" or ___ExpirationStatus is Null)' 'BookID is Null and ( ___ExpirationStatus <> "3" or ___ExpirationStatus is Null)'
elif self.dbversion < 14 and self.dbversion >= 8: elif self.dbversion < 14 and self.dbversion >= 8:
query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \ query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
'ImageID, ReadStatus, ___ExpirationStatus, "-1" as FavouritesIndex, "-1" as Accessibility from content where ' \ 'ImageID, ReadStatus, ___ExpirationStatus, "-1" as FavouritesIndex, "-1" as Accessibility from content where ' \
'BookID is Null and ( ___ExpirationStatus <> "3" or ___ExpirationStatus is Null)' 'BookID is Null and ( ___ExpirationStatus <> "3" or ___ExpirationStatus is Null)'
else: else:
query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \ query= 'select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' \
'ImageID, ReadStatus, "-1" as ___ExpirationStatus, "-1" as FavouritesIndex, "-1" as Accessibility from content where BookID is Null' 'ImageID, ReadStatus, "-1" as ___ExpirationStatus, "-1" as FavouritesIndex, "-1" as Accessibility from content where BookID is Null'
try: try:
cursor.execute (query) cursor.execute (query)
except Exception as e: except Exception as e:
err = str(e) err = str(e)
if not ('___ExpirationStatus' in err or 'FavouritesIndex' in err or if not ('___ExpirationStatus' in err or 'FavouritesIndex' in err or
'Accessibility' in err): 'Accessibility' in err):
raise raise
query= ('select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ' query= ('select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, '
'ImageID, ReadStatus, "-1" as ___ExpirationStatus, "-1" as ' 'ImageID, ReadStatus, "-1" as ___ExpirationStatus, "-1" as '
'FavouritesIndex, "-1" as Accessibility from content where ' 'FavouritesIndex, "-1" as Accessibility from content where '
'BookID is Null') 'BookID is Null')
cursor.execute(query) cursor.execute(query)
changed = False changed = False
for i, row in enumerate(cursor): for i, row in enumerate(cursor):
# self.report_progress((i+1) / float(numrows), _('Getting list of books on device...')) # self.report_progress((i+1) / float(numrows), _('Getting list of books on device...'))
if row[3].startswith("file:///usr/local/Kobo/help/"): if row[3].startswith("file:///usr/local/Kobo/help/"):
# These are internal to the Kobo device and do not exist # These are internal to the Kobo device and do not exist
continue continue
path = self.path_from_contentid(row[3], row[5], row[4], oncard) path = self.path_from_contentid(row[3], row[5], row[4], oncard)
mime = mime_type_ext(path_to_ext(path)) if path.find('kepub') == -1 else 'application/epub+zip' mime = mime_type_ext(path_to_ext(path)) if path.find('kepub') == -1 else 'application/epub+zip'
# debug_print("mime:", mime) # debug_print("mime:", mime)
if oncard != 'carda' and oncard != 'cardb' and not row[3].startswith("file:///mnt/sd/"): if oncard != 'carda' and oncard != 'cardb' and not row[3].startswith("file:///mnt/sd/"):
changed = update_booklist(self._main_prefix, path, row[0], row[1], mime, row[2], row[5], row[6], row[7], row[4], row[8], row[9], row[10]) changed = update_booklist(self._main_prefix, path, row[0], row[1], mime, row[2], row[5], row[6], row[7], row[4], row[8], row[9], row[10])
# print "shortbook: " + path # print "shortbook: " + path
elif oncard == 'carda' and row[3].startswith("file:///mnt/sd/"): elif oncard == 'carda' and row[3].startswith("file:///mnt/sd/"):
changed = update_booklist(self._card_a_prefix, path, row[0], row[1], mime, row[2], row[5], row[6], row[7], row[4], row[8], row[9], row[10]) changed = update_booklist(self._card_a_prefix, path, row[0], row[1], mime, row[2], row[5], row[6], row[7], row[4], row[8], row[9], row[10])
if changed: if changed:
need_sync = True need_sync = True
cursor.close() cursor.close()
connection.close()
# Remove books that are no longer in the filesystem. Cache contains # Remove books that are no longer in the filesystem. Cache contains
# indices into the booklist if book not in filesystem, None otherwise # indices into the booklist if book not in filesystem, None otherwise
@ -292,56 +294,56 @@ class KOBO(USBMS):
# 2) content # 2) content
debug_print('delete_via_sql: ContentID: ', ContentID, 'ContentType: ', ContentType) debug_print('delete_via_sql: ContentID: ', ContentID, 'ContentType: ', ContentType)
connection = sqlite.connect(self.normalize_path(self._main_prefix + '.kobo/KoboReader.sqlite')) with closing(sqlite.connect(self.normalize_path(self._main_prefix +
'.kobo/KoboReader.sqlite'))) as connection:
# return bytestrings if the content cannot the decoded as unicode # return bytestrings if the content cannot the decoded as unicode
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore") connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
cursor = connection.cursor() cursor = connection.cursor()
t = (ContentID,) t = (ContentID,)
cursor.execute('select ImageID from content where ContentID = ?', t) cursor.execute('select ImageID from content where ContentID = ?', t)
ImageID = None ImageID = None
for row in cursor: for row in cursor:
# First get the ImageID to delete the images # First get the ImageID to delete the images
ImageID = row[0] ImageID = row[0]
cursor.close() cursor.close()
cursor = connection.cursor() cursor = connection.cursor()
if ContentType == 6 and self.dbversion < 8: if ContentType == 6 and self.dbversion < 8:
# Delete the shortcover_pages first # Delete the shortcover_pages first
cursor.execute('delete from shortcover_page where shortcoverid in (select ContentID from content where BookID = ?)', t) cursor.execute('delete from shortcover_page where shortcoverid in (select ContentID from content where BookID = ?)', t)
#Delete the volume_shortcovers second #Delete the volume_shortcovers second
cursor.execute('delete from volume_shortcovers where volumeid = ?', t) cursor.execute('delete from volume_shortcovers where volumeid = ?', t)
# Delete the rows from content_keys # Delete the rows from content_keys
if self.dbversion >= 8: if self.dbversion >= 8:
cursor.execute('delete from content_keys where volumeid = ?', t) cursor.execute('delete from content_keys where volumeid = ?', t)
# Delete the chapters associated with the book next # Delete the chapters associated with the book next
t = (ContentID,) t = (ContentID,)
# Kobo does not delete the Book row (ie the row where the BookID is Null) # Kobo does not delete the Book row (ie the row where the BookID is Null)
# The next server sync should remove the row # The next server sync should remove the row
cursor.execute('delete from content where BookID = ?', t) cursor.execute('delete from content where BookID = ?', t)
try: try:
cursor.execute('update content set ReadStatus=0, FirstTimeReading = \'true\', ___PercentRead=0, ___ExpirationStatus=3 ' \ cursor.execute('update content set ReadStatus=0, FirstTimeReading = \'true\', ___PercentRead=0, ___ExpirationStatus=3 ' \
'where BookID is Null and ContentID =?',t) 'where BookID is Null and ContentID =?',t)
except Exception as e: except Exception as e:
if 'no such column' not in str(e): if 'no such column' not in str(e):
raise raise
cursor.execute('update content set ReadStatus=0, FirstTimeReading = \'true\', ___PercentRead=0 ' \ cursor.execute('update content set ReadStatus=0, FirstTimeReading = \'true\', ___PercentRead=0 ' \
'where BookID is Null and ContentID =?',t) 'where BookID is Null and ContentID =?',t)
connection.commit() connection.commit()
cursor.close() cursor.close()
if ImageID == None: if ImageID == None:
print "Error condition ImageID was not found" print "Error condition ImageID was not found"
print "You likely tried to delete a book that the kobo has not yet added to the database" print "You likely tried to delete a book that the kobo has not yet added to the database"
connection.close()
# If all this succeeds we need to delete the images files via the ImageID # If all this succeeds we need to delete the images files via the ImageID
return ImageID return ImageID
@ -668,50 +670,49 @@ class KOBO(USBMS):
# Needs to be outside books collection as in the case of removing # Needs to be outside books collection as in the case of removing
# the last book from the collection the list of books is empty # the last book from the collection the list of books is empty
# and the removal of the last book would not occur # and the removal of the last book would not occur
connection = sqlite.connect(self.normalize_path(self._main_prefix + '.kobo/KoboReader.sqlite')) with closing(sqlite.connect(self.normalize_path(self._main_prefix +
'.kobo/KoboReader.sqlite'))) as connection:
# return bytestrings if the content cannot the decoded as unicode # return bytestrings if the content cannot the decoded as unicode
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore") connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
if collections: if collections:
# Need to reset the collections outside the particular loops # Need to reset the collections outside the particular loops
# otherwise the last item will not be removed # otherwise the last item will not be removed
self.reset_readstatus(connection, oncard) self.reset_readstatus(connection, oncard)
if self.dbversion >= 14: if self.dbversion >= 14:
self.reset_favouritesindex(connection, oncard) self.reset_favouritesindex(connection, oncard)
# Process any collections that exist # Process any collections that exist
for category, books in collections.items(): for category, books in collections.items():
debug_print("Category: ", category, " id = ", readstatuslist.get(category)) debug_print("Category: ", category, " id = ", readstatuslist.get(category))
for book in books: for book in books:
debug_print(' Title:', book.title, 'category: ', category) debug_print(' Title:', book.title, 'category: ', category)
if category not in book.device_collections: if category not in book.device_collections:
book.device_collections.append(category) book.device_collections.append(category)
extension = os.path.splitext(book.path)[1] extension = os.path.splitext(book.path)[1]
ContentType = self.get_content_type_from_extension(extension) if extension != '' else self.get_content_type_from_path(book.path) ContentType = self.get_content_type_from_extension(extension) if extension != '' else self.get_content_type_from_path(book.path)
ContentID = self.contentid_from_path(book.path, ContentType) ContentID = self.contentid_from_path(book.path, ContentType)
if category in readstatuslist.keys(): if category in readstatuslist.keys():
# Manage ReadStatus # Manage ReadStatus
self.set_readstatus(connection, ContentID, readstatuslist.get(category)) self.set_readstatus(connection, ContentID, readstatuslist.get(category))
elif category == 'Shortlist' and self.dbversion >= 14: elif category == 'Shortlist' and self.dbversion >= 14:
# Manage FavouritesIndex/Shortlist # Manage FavouritesIndex/Shortlist
self.set_favouritesindex(connection, ContentID) self.set_favouritesindex(connection, ContentID)
elif category in accessibilitylist.keys(): elif category in accessibilitylist.keys():
# Do not manage the Accessibility List # Do not manage the Accessibility List
pass pass
else: # No collections else: # No collections
# Since no collections exist the ReadStatus needs to be reset to 0 (Unread) # Since no collections exist the ReadStatus needs to be reset to 0 (Unread)
debug_print("No Collections - reseting ReadStatus") debug_print("No Collections - reseting ReadStatus")
self.reset_readstatus(connection, oncard) self.reset_readstatus(connection, oncard)
if self.dbversion >= 14: if self.dbversion >= 14:
debug_print("No Collections - reseting FavouritesIndex") debug_print("No Collections - reseting FavouritesIndex")
self.reset_favouritesindex(connection, oncard) self.reset_favouritesindex(connection, oncard)
connection.close()
# debug_print('Finished update_device_database_collections', collections_attributes) # debug_print('Finished update_device_database_collections', collections_attributes)