diff --git a/CHANGES.md b/CHANGES.md index 6077c4ce..b578cd8d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -23,6 +23,7 @@ * Remove unused force variable from code and PEP8 * Change browser, bs4 parser and classes code to PEP8 standards * Change common and config code to PEP8 standards +* Change database code to PEP8 standards [develop changelog] * Fix traceback error when using the menu item Manage/Update Kodi diff --git a/sickbeard/db.py b/sickbeard/db.py index 5e76ab89..0818f5c1 100644 --- a/sickbeard/db.py +++ b/sickbeard/db.py @@ -25,15 +25,15 @@ import time import threading import sickbeard - from sickbeard import encodingKludge as ek from sickbeard import logger from sickbeard.exceptions import ex + db_lock = threading.Lock() -def dbFilename(filename="sickbeard.db", suffix=None): +def dbFilename(filename='sickbeard.db', suffix=None): """ @param filename: The sqlite database filename to use. If not specified, will be made to be sickbeard.db @@ -42,16 +42,16 @@ def dbFilename(filename="sickbeard.db", suffix=None): @return: the correct location of the database file. """ if suffix: - filename = "%s.%s" % (filename, suffix) + filename = '%s.%s' % (filename, suffix) return ek.ek(os.path.join, sickbeard.DATA_DIR, filename) class DBConnection(object): - def __init__(self, filename="sickbeard.db", suffix=None, row_type=None): + def __init__(self, filename='sickbeard.db', suffix=None, row_type=None): self.filename = filename self.connection = sqlite3.connect(dbFilename(filename), 20) - if row_type == "dict": + if row_type == 'dict': self.connection.row_factory = self._dict_factory else: self.connection.row_factory = sqlite3.Row @@ -62,12 +62,12 @@ class DBConnection(object): try: if self.hasTable('db_version'): - result = self.select("SELECT db_version FROM db_version") + result = self.select('SELECT db_version FROM db_version') except: return 0 if result: - return int(result[0]["db_version"]) + return int(result[0]['db_version']) else: return 0 @@ -90,27 +90,26 @@ class DBConnection(object): sqlResult.append(self.connection.execute(qu[0]).fetchall()) elif len(qu) > 1: if logTransaction: - logger.log(qu[0] + " with args " + str(qu[1]), logger.DB) + logger.log(qu[0] + ' with args ' + str(qu[1]), logger.DB) sqlResult.append(self.connection.execute(qu[0], qu[1]).fetchall()) self.connection.commit() - logger.log(u"Transaction with " + str(len(querylist)) + u" query's executed", logger.DEBUG) + logger.log(u'Transaction with ' + str(len(querylist)) + u' queries executed', logger.DEBUG) return sqlResult except sqlite3.OperationalError, e: sqlResult = [] if self.connection: self.connection.rollback() - if "unable to open database file" in e.args[0] or "database is locked" in e.args[0]: - logger.log(u"DB error: " + ex(e), logger.WARNING) + if 'unable to open database file' in e.args[0] or 'database is locked' in e.args[0]: + logger.log(u'DB error: ' + ex(e), logger.WARNING) attempt += 1 time.sleep(1) else: - logger.log(u"DB error: " + ex(e), logger.ERROR) + logger.log(u'DB error: ' + ex(e), logger.ERROR) raise except sqlite3.DatabaseError, e: - sqlResult = [] if self.connection: self.connection.rollback() - logger.log(u"Fatal error executing query: " + ex(e), logger.ERROR) + logger.log(u'Fatal error executing query: ' + ex(e), logger.ERROR) raise return sqlResult @@ -128,24 +127,24 @@ class DBConnection(object): while attempt < 5: try: if args is None: - logger.log(self.filename + ": " + query, logger.DB) + logger.log(self.filename + ': ' + query, logger.DB) sqlResult = self.connection.execute(query) else: - logger.log(self.filename + ": " + query + " with args " + str(args), logger.DB) + logger.log(self.filename + ': ' + query + ' with args ' + str(args), logger.DB) sqlResult = self.connection.execute(query, args) self.connection.commit() # get out of the connection attempt loop since we were successful break except sqlite3.OperationalError, e: - if "unable to open database file" in e.args[0] or "database is locked" in e.args[0]: - logger.log(u"DB error: " + ex(e), logger.WARNING) + if 'unable to open database file' in e.args[0] or 'database is locked' in e.args[0]: + logger.log(u'DB error: ' + ex(e), logger.WARNING) attempt += 1 time.sleep(1) else: - logger.log(u"DB error: " + ex(e), logger.ERROR) + logger.log(u'DB error: ' + ex(e), logger.ERROR) raise except sqlite3.DatabaseError, e: - logger.log(u"Fatal error executing query: " + ex(e), logger.ERROR) + logger.log(u'Fatal error executing query: ' + ex(e), logger.ERROR) raise return sqlResult @@ -159,41 +158,41 @@ class DBConnection(object): return sqlResults - def upsert(self, tableName, valueDict, keyDict): changesBefore = self.connection.total_changes - genParams = lambda myDict: [x + " = ?" for x in myDict.keys()] + genParams = lambda myDict: [x + ' = ?' for x in myDict.keys()] - query = "UPDATE [" + tableName + "] SET " + ", ".join(genParams(valueDict)) + " WHERE " + " AND ".join( - genParams(keyDict)) + query = 'UPDATE [%s] SET %s WHERE %s' % ( + tableName, ', '.join(genParams(valueDict)), ' AND '.join(genParams(keyDict))) self.action(query, valueDict.values() + keyDict.values()) if self.connection.total_changes == changesBefore: - query = "INSERT INTO [" + tableName + "] (" + ", ".join(valueDict.keys() + keyDict.keys()) + ")" + \ - " VALUES (" + ", ".join(["?"] * len(valueDict.keys() + keyDict.keys())) + ")" + query = 'INSERT INTO [' + tableName + '] (' + ', '.join(valueDict.keys() + keyDict.keys()) + ')' + \ + ' VALUES (' + ', '.join(['?'] * len(valueDict.keys() + keyDict.keys())) + ')' self.action(query, valueDict.values() + keyDict.values()) def tableInfo(self, tableName): # FIXME ? binding is not supported here, but I cannot find a way to escape a string manually - sqlResult = self.select("PRAGMA table_info([%s])" % tableName) + sqlResult = self.select('PRAGMA table_info([%s])' % tableName) columns = {} for column in sqlResult: columns[column['name']] = {'type': column['type']} return columns # http://stackoverflow.com/questions/3300464/how-can-i-get-dict-from-sqlite-query - def _dict_factory(self, cursor, row): + @staticmethod + def _dict_factory(cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d def hasTable(self, tableName): - return len(self.select("SELECT 1 FROM sqlite_master WHERE name = ?;", (tableName, ))) > 0 + return len(self.select('SELECT 1 FROM sqlite_master WHERE name = ?;', (tableName, ))) > 0 def hasColumn(self, tableName, column): return column in self.tableInfo(tableName) @@ -205,17 +204,17 @@ class DBConnection(object): return True return False - - def addColumn(self, table, column, type="NUMERIC", default=0): - self.action("ALTER TABLE [%s] ADD %s %s" % (table, column, type)) - self.action("UPDATE [%s] SET %s = ?" % (table, column), (default,)) + def addColumn(self, table, column, type='NUMERIC', default=0): + self.action('ALTER TABLE [%s] ADD %s %s' % (table, column, type)) + self.action('UPDATE [%s] SET %s = ?' % (table, column), (default,)) def close(self): """Close database connection""" - if getattr(self, "connection", None) is not None: + if getattr(self, 'connection', None) is not None: self.connection.close() self.connection = None + def sanityCheckDatabase(connection, sanity_check): sanity_check(connection).check() @@ -228,23 +227,19 @@ class DBSanityCheck(object): pass -# =============== -# = Upgrade API = -# =============== - def upgradeDatabase(connection, schema): - logger.log(u"Checking database structure...", logger.MESSAGE) + logger.log(u'Checking database structure...', logger.MESSAGE) _processUpgrade(connection, schema) def prettyName(class_name): - return ' '.join([x.group() for x in re.finditer("([A-Z])([a-z0-9]+)", class_name)]) + return ' '.join([x.group() for x in re.finditer('([A-Z])([a-z0-9]+)', class_name)]) def restoreDatabase(version): - logger.log(u"Restoring database before trying upgrade again") - if not sickbeard.helpers.restoreVersionedFile(dbFilename(suffix='v' + str(version)), version): - logger.log_error_and_exit(u"Database restore failed, abort upgrading database") + logger.log(u'Restoring database before trying upgrade again') + if not sickbeard.helpers.restoreVersionedFile(dbFilename(suffix='v%s' % version), version): + logger.log_error_and_exit(u'Database restore failed, abort upgrading database') return False else: return True @@ -252,9 +247,9 @@ def restoreDatabase(version): def _processUpgrade(connection, upgradeClass): instance = upgradeClass(connection) - logger.log(u"Checking " + prettyName(upgradeClass.__name__) + " database upgrade", logger.DEBUG) + logger.log(u'Checking %s database upgrade' % prettyName(upgradeClass.__name__), logger.DEBUG) if not instance.test(): - logger.log(u"Database upgrade required: " + prettyName(upgradeClass.__name__), logger.MESSAGE) + logger.log(u'Database upgrade required: %s' % prettyName(upgradeClass.__name__), logger.MESSAGE) try: instance.execute() except sqlite3.DatabaseError, e: @@ -263,9 +258,9 @@ def _processUpgrade(connection, upgradeClass): instance.execute() except: restored = False - result = connection.select("SELECT db_version FROM db_version") + result = connection.select('SELECT db_version FROM db_version') if result: - version = int(result[0]["db_version"]) + version = int(result[0]['db_version']) # close db before attempting restore connection.close() @@ -276,11 +271,11 @@ def _processUpgrade(connection, upgradeClass): restored = True if not restored: - print "Error in " + str(upgradeClass.__name__) + ": " + ex(e) + print 'Error in %s: %s ' % (upgradeClass.__name__, ex(e)) raise - logger.log(upgradeClass.__name__ + " upgrade completed", logger.DEBUG) + logger.log('%s upgrade completed' % upgradeClass.__name__, logger.DEBUG) else: - logger.log(upgradeClass.__name__ + " upgrade not required", logger.DEBUG) + logger.log('%s upgrade not required' % upgradeClass.__name__, logger.DEBUG) for upgradeSubClass in upgradeClass.__subclasses__(): _processUpgrade(connection, upgradeSubClass) @@ -292,14 +287,14 @@ class SchemaUpgrade(object): self.connection = connection def hasTable(self, tableName): - return len(self.connection.select("SELECT 1 FROM sqlite_master WHERE name = ?;", (tableName, ))) > 0 + return len(self.connection.select('SELECT 1 FROM sqlite_master WHERE name = ?;', (tableName, ))) > 0 def hasColumn(self, tableName, column): return column in self.connection.tableInfo(tableName) - def addColumn(self, table, column, type="NUMERIC", default=0): - self.connection.action("ALTER TABLE [%s] ADD %s %s" % (table, column, type)) - self.connection.action("UPDATE [%s] SET %s = ?" % (table, column), (default,)) + def addColumn(self, table, column, type='NUMERIC', default=0): + self.connection.action('ALTER TABLE [%s] ADD %s %s' % (table, column, type)) + self.connection.action('UPDATE [%s] SET %s = ?' % (table, column), (default,)) def dropColumn(self, table, column): # get old table columns and store the ones we want to keep @@ -315,9 +310,7 @@ class SchemaUpgrade(object): keptColumnsNames.append(column['name']) - cl = [] - cl.append(column['name']) - cl.append(column['type']) + cl = [column['name'], column['type']] ''' To be implemented if ever required @@ -350,7 +343,7 @@ class SchemaUpgrade(object): self.connection.action('INSERT INTO [%s_new] SELECT %s FROM [%s]' % (table, keptColumnsNames, table)) # copy the old indexes from the old table - result = self.connection.select('SELECT sql FROM sqlite_master WHERE tbl_name=? and type="index"', [table]) + result = self.connection.select("SELECT sql FROM sqlite_master WHERE tbl_name=? and type='index'", [table]) # remove the old table and rename the new table to take it's place self.connection.action('DROP TABLE [%s]' % table) @@ -362,25 +355,24 @@ class SchemaUpgrade(object): self.connection.action(index['sql']) # vacuum the db as we will have a lot of space to reclaim after dropping tables - self.connection.action("VACUUM") + self.connection.action('VACUUM') def checkDBVersion(self): return self.connection.checkDBVersion() def incDBVersion(self): new_version = self.checkDBVersion() + 1 - self.connection.action("UPDATE db_version SET db_version = ?", [new_version]) + self.connection.action('UPDATE db_version SET db_version = ?', [new_version]) return new_version def setDBVersion(self, new_version): - self.connection.action("UPDATE db_version SET db_version = ?", [new_version]) + self.connection.action('UPDATE db_version SET db_version = ?', [new_version]) return new_version def MigrationCode(myDB): - schema = { - 0: sickbeard.mainDB.InitialSchema, # 0->20000 + 0: sickbeard.mainDB.InitialSchema, 9: sickbeard.mainDB.AddSizeAndSceneNameFields, 10: sickbeard.mainDB.RenameSeasonFolders, 11: sickbeard.mainDB.Add1080pAndRawHDQualities, @@ -420,12 +412,12 @@ def MigrationCode(myDB): 10001: sickbeard.mainDB.RemoveDefaultEpStatusFromTvShows, 20000: sickbeard.mainDB.DBIncreaseTo20001, - #20001: sickbeard.mainDB.AddCoolSickGearFeature2, - #20002: sickbeard.mainDB.AddCoolSickGearFeature3, + # 20001: sickbeard.mainDB.AddCoolSickGearFeature2, + # 20002: sickbeard.mainDB.AddCoolSickGearFeature3, } db_version = myDB.checkDBVersion() - logger.log(u'Detected database version: v' + str(db_version), logger.DEBUG) + logger.log(u'Detected database version: v%s' % db_version, logger.DEBUG) if not (db_version in schema): if db_version == sickbeard.mainDB.MAX_DB_VERSION: @@ -443,10 +435,10 @@ def MigrationCode(myDB): db_version = update.execute() except Exception, e: myDB.close() - logger.log(u'Failed to update database with error: ' + ex(e) + ' attempting recovery...', logger.ERROR) + logger.log(u'Failed to update database with error: %s attempting recovery...' % ex(e), logger.ERROR) if restoreDatabase(db_version): # initialize the main SB database - logger.log_error_and_exit(u'Successfully restored database version:' + str(db_version)) + logger.log_error_and_exit(u'Successfully restored database version: %s' % db_version) else: - logger.log_error_and_exit(u'Failed to restore database version:' + str(db_version)) \ No newline at end of file + logger.log_error_and_exit(u'Failed to restore database version: %s' % db_version) \ No newline at end of file