From a45e183914e082ab25b126d391b3ecb3baae11d9 Mon Sep 17 00:00:00 2001 From: BasioMeusPuga Date: Sat, 19 Jan 2019 20:31:19 +0530 Subject: [PATCH] Implement logging --- lector/__main__.py | 48 +++++++++++++++++++------------------ lector/database.py | 1 - lector/library.py | 2 +- lector/models.py | 31 ++---------------------- lector/readers/read_epub.py | 10 ++++---- lector/settings.py | 9 ++++++- lector/settingsdialog.py | 2 +- lector/sorter.py | 7 +++--- lector/threaded.py | 5 ++-- lector/widgets.py | 2 +- 10 files changed, 51 insertions(+), 66 deletions(-) diff --git a/lector/__main__.py b/lector/__main__.py index 792bdd1..914d529 100755 --- a/lector/__main__.py +++ b/lector/__main__.py @@ -23,8 +23,6 @@ import logging import hashlib import pathlib -from PyQt5 import QtWidgets, QtGui, QtCore - # This allows for the program to be launched from the # dir where it's been copied instead of needing to be # installed @@ -32,20 +30,7 @@ install_dir = os.path.realpath(__file__) install_dir = pathlib.Path(install_dir).parents[1] sys.path.append(str(install_dir)) -# Initialize logging -# This is outside the UI declaration to allow sharing -# the object across modules without explicit redeclaration -logger_filename = os.path.join( - QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.AppDataLocation), - 'Lector', - 'Lector.log') -logging.basicConfig( - filename=logger_filename, - filemode='a', - format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s', - datefmt='%H:%M:%S', - level=logging.ERROR) -logger = logging.getLogger('lector.main') +from PyQt5 import QtWidgets, QtGui, QtCore from lector import database from lector import sorter @@ -100,6 +85,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): Settings(self).read_settings() # This should populate all variables that need # to be remembered across sessions + # Initialize logging + self.logger = init_logging(self.settings['log_level']) + self.logger.log(60, 'Application started') + # Initialize icon factory self.QImageFactory = QImageFactory(self) @@ -256,7 +245,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): # Get list of available parsers self.available_parsers = '*.' + ' *.'.join(sorter.available_parsers) - logger.info('Available parsers: ' + self.available_parsers) + self.logger.info('Available parsers: ' + self.available_parsers) # The Library tab gets no button self.tabWidget.tabBar().setTabButton( @@ -423,7 +412,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): if not file_paths: return - logger.info( + self.logger.info( 'Attempting to open: ' + ', '.join(file_paths)) contents = sorter.BookSorter( @@ -437,7 +426,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): # Notification feedback in case all books return nothing if not contents: - logger.error('No parseable files found') + self.logger.error('No parseable files found') return successfully_opened = [] @@ -447,7 +436,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): file_data = contents[i] Tab(file_data, self) successfully_opened.append(file_data['path']) - logger.info( + self.logger.info( 'Successfully opened: ' + ', '.join(file_paths)) if self.settings['last_open_tab'] == 'library': @@ -1049,6 +1038,21 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): QtWidgets.qApp.exit() +def init_logging(log_level): + location_prefix = QtCore.QStandardPaths.writableLocation( + QtCore.QStandardPaths.AppDataLocation) + os.makedirs(location_prefix, exist_ok=True) + logger_filename = os.path.join(location_prefix, 'Lector.log') + logging.basicConfig( + filename=logger_filename, + filemode='a', + format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s', + datefmt='%Y/%M/%d %H:%M:%S', + level=log_level) + logging.addLevelName(60, 'HammerTime') ## Messages that MUST be logged + return logging.getLogger('lector.main') + + def main(): app = QtWidgets.QApplication(sys.argv) app.setApplicationName('Lector') # This is needed for QStandardPaths @@ -1063,8 +1067,7 @@ def main(): translations_out_string = '(Translations found)' if not translations_found: translations_out_string = '(No translations found)' - log_string = f'Locale: {QtCore.QLocale.system().name()}' + translations_out_string - logger.info(log_string) + print(f'Locale: {QtCore.QLocale.system().name()}' + translations_out_string) form = MainUI() form.show() @@ -1073,5 +1076,4 @@ def main(): if __name__ == '__main__': - logger.info('Application start') main() diff --git a/lector/database.py b/lector/database.py index 4687b45..27deaec 100644 --- a/lector/database.py +++ b/lector/database.py @@ -26,7 +26,6 @@ logger = logging.getLogger(__name__) class DatabaseInit: def __init__(self, location_prefix): - os.makedirs(location_prefix, exist_ok=True) self.database_path = os.path.join(location_prefix, 'Lector.db') self.books_table_columns = { diff --git a/lector/library.py b/lector/library.py index fbd8b26..d8897ed 100644 --- a/lector/library.py +++ b/lector/library.py @@ -50,7 +50,7 @@ class Library: 'LIKE') if not books: - logger.error('Database returned nothing') + logger.warning('Database returned nothing') return elif mode == 'addition': diff --git a/lector/models.py b/lector/models.py index 536a4c9..4e33fcf 100644 --- a/lector/models.py +++ b/lector/models.py @@ -102,7 +102,8 @@ class TableProxyModel(QtCore.QSortFilterProxyModel): try: return self.header_data[column] except IndexError: - print('Table proxy model: Can\'t find header for column', column) + logger.error( + 'Table proxy model: Can\'t find header for column' + str(column)) # The column will be called IndexError. Not a typo. return 'IndexError' @@ -347,31 +348,3 @@ class MostExcellentFileSystemModel(QtWidgets.QFileSystemModel): for i in deletable: del self.tag_data[i] - -# TODO -# Unbork this -class FileSystemProxyModel(QtCore.QSortFilterProxyModel): - def __init__(self, parent=None): - super(FileSystemProxyModel, self).__init__(parent) - - def filterAcceptsRow(self, row_num, parent): - model = self.sourceModel() - filter_out = [ - 'boot', 'dev', 'etc', 'lost+found', 'opt', 'pdb', - 'proc', 'root', 'run', 'srv', 'sys', 'tmp', 'twonky', - 'usr', 'var', 'bin', 'kdeinit5__0', 'lib', 'lib64', 'sbin'] - - name_index = model.index(row_num, 0) - valid_data = model.data(name_index) - - print(valid_data) - - return True - - try: - if valid_data in filter_out: - return False - except AttributeError: - pass - - return True diff --git a/lector/readers/read_epub.py b/lector/readers/read_epub.py index ca5ad18..40aaeab 100644 --- a/lector/readers/read_epub.py +++ b/lector/readers/read_epub.py @@ -53,7 +53,7 @@ class EPUB: self.zip_file = zipfile.ZipFile( self.filename, mode='r', allowZip64=True) except (KeyError, AttributeError, zipfile.BadZipFile): - print('Cannot parse ' + self.filename) + logger.error('Malformed zip file ' + self.filename) return def parse_xml(self, filename, parser): @@ -61,7 +61,8 @@ class EPUB: this_xml = self.zip_file.read(filename).decode() except KeyError: short_filename = os.path.basename(self.filename) - print(f'{str(filename)} not found in {short_filename}') + warning_string = f'{str(filename)} not found in {short_filename}' + logger.warning(warning_string) return root = BeautifulSoup(this_xml, parser) @@ -82,7 +83,8 @@ class EPUB: try: return root_item.get('full-path') except AttributeError: - print(f'ePub module: {self.filename} has a malformed container.xml') + error_string = f'ePub module: {self.filename} has a malformed container.xml' + logger.error(error_string) return None possible_filenames = ('content.opf', 'package.opf') @@ -107,7 +109,7 @@ class EPUB: if file_path_actual: return self.zip_file.read(file_path_actual) else: - print('ePub module can\'t find ' + filename) + logger.error('ePub module can\'t find ' + filename) #______________________________________________________ diff --git a/lector/settings.py b/lector/settings.py index 3666637..949cb71 100644 --- a/lector/settings.py +++ b/lector/settings.py @@ -88,6 +88,11 @@ class Settings: 'currentProfileIndex', 0)) self.parent.comic_profile = self.settings.value( 'comicProfile', self.default_comic_profile) + try: + log_level = int(self.settings.value('logLevel', logging.WARNING)) + except ValueError: + log_level = 30 + self.parent.settings['log_level'] = log_level self.settings.endGroup() self.settings.beginGroup('lastOpen') @@ -149,7 +154,6 @@ class Settings: self.settings.endGroup() def save_settings(self): - print('Saving settings...') current_settings = self.parent.settings self.settings.beginGroup('mainWindow') @@ -183,6 +187,7 @@ class Settings: current_profile3]) self.settings.setValue('currentProfileIndex', current_profile_index) self.settings.setValue('comicProfile', self.parent.comic_profile) + self.settings.setValue('logLevel', self.parent.settings['log_level']) self.settings.endGroup() current_tab_index = self.parent.tabWidget.currentIndex() @@ -228,3 +233,5 @@ class Settings: self.settings.beginGroup('annotations') self.settings.setValue('annotationList', current_settings['annotations']) self.settings.endGroup() + + logger.info('Settings saved') diff --git a/lector/settingsdialog.py b/lector/settingsdialog.py index 85e1d6c..be1f6b1 100644 --- a/lector/settingsdialog.py +++ b/lector/settingsdialog.py @@ -192,7 +192,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog): self.main_window.generate_library_filter_menu(paths) directory_data = {} if not paths: - logger.error('Database: No paths for settings...') + logger.warning('No paths saved for books') else: # Convert to the dictionary format that is # to be fed into the QFileSystemModel diff --git a/lector/sorter.py b/lector/sorter.py index 5cda05a..06e5392 100644 --- a/lector/sorter.py +++ b/lector/sorter.py @@ -177,7 +177,8 @@ class BookSorter: or os.path.exists(self.hashes_and_paths[file_md5])): if not self.hashes_and_paths[file_md5] == filename: - print(f'{os.path.basename(filename)} is already in database') + warning_string = f'{os.path.basename(filename)} is already in database' + logger.warning(warning_string) return # This allows for eliminating issues with filenames that have @@ -190,7 +191,7 @@ class BookSorter: break if not valid_extension: - print(filename + ' has an unsupported extension') + logger.error(filename + ' has an unsupported extension') return book_ref = sorter[file_extension](filename, self.temp_dir, file_md5) @@ -317,7 +318,7 @@ class BookSorter: del self.processed_books processing_time = str(time.time() - start_time) - logger.info('Finished processing in:' + processing_time) + logger.info('Finished processing in ' + processing_time) return return_books diff --git a/lector/threaded.py b/lector/threaded.py index f812898..63aee44 100644 --- a/lector/threaded.py +++ b/lector/threaded.py @@ -124,9 +124,10 @@ class BackGroundBookSearch(QtCore.QThread): if self.valid_directories: initiate_threads() - print(len(self.valid_files), 'books found') + info_string = str(len(self.valid_files)) + ' books found' + logger.info(info_string) else: - print('No valid directories') + logger.error('No valid directories') class BackGroundCacheRefill(QtCore.QThread): diff --git a/lector/widgets.py b/lector/widgets.py index 5b240d3..9b2796f 100644 --- a/lector/widgets.py +++ b/lector/widgets.py @@ -319,7 +319,7 @@ class Tab(QtWidgets.QWidget): try: required_position = self.metadata['position']['cursor_position'] except KeyError: - print('Database: Cursor position error. Recommend retry.') + logging.error('Database: Cursor position error. Recommend retry.') return if cursor_position: