Improve logging
requirements.txt Small UI fixes
This commit is contained in:
@@ -19,7 +19,6 @@
|
||||
import os
|
||||
import gc
|
||||
import sys
|
||||
import logging
|
||||
import hashlib
|
||||
import pathlib
|
||||
|
||||
@@ -30,6 +29,13 @@ install_dir = os.path.realpath(__file__)
|
||||
install_dir = pathlib.Path(install_dir).parents[1]
|
||||
sys.path.append(str(install_dir))
|
||||
|
||||
# Init logging
|
||||
# Must be done first and at the module level
|
||||
# or it won't work properly in case of the imports below
|
||||
from lector.logger import init_logging
|
||||
logger = init_logging(sys.argv)
|
||||
logger.log(60, 'Application started')
|
||||
|
||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
|
||||
from lector import database
|
||||
@@ -85,10 +91,6 @@ 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)
|
||||
|
||||
@@ -245,7 +247,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
|
||||
# Get list of available parsers
|
||||
self.available_parsers = '*.' + ' *.'.join(sorter.available_parsers)
|
||||
self.logger.info('Available parsers: ' + self.available_parsers)
|
||||
logger.info('Available parsers: ' + self.available_parsers)
|
||||
|
||||
# The Library tab gets no button
|
||||
self.tabWidget.tabBar().setTabButton(
|
||||
@@ -412,7 +414,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
if not file_paths:
|
||||
return
|
||||
|
||||
self.logger.info(
|
||||
logger.info(
|
||||
'Attempting to open: ' + ', '.join(file_paths))
|
||||
|
||||
contents = sorter.BookSorter(
|
||||
@@ -426,7 +428,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
# Notification feedback in case all books return nothing
|
||||
|
||||
if not contents:
|
||||
self.logger.error('No parseable files found')
|
||||
logger.error('No parseable files found')
|
||||
return
|
||||
|
||||
successfully_opened = []
|
||||
@@ -436,7 +438,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
file_data = contents[i]
|
||||
Tab(file_data, self)
|
||||
successfully_opened.append(file_data['path'])
|
||||
self.logger.info(
|
||||
logger.info(
|
||||
'Successfully opened: ' + ', '.join(file_paths))
|
||||
|
||||
if self.settings['last_open_tab'] == 'library':
|
||||
@@ -1038,21 +1040,6 @@ 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
|
||||
|
54
lector/logger.py
Normal file
54
lector/logger.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# This file is a part of Lector, a Qt based ebook reader
|
||||
# Copyright (C) 2017-2019 BasioMeusPuga
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
|
||||
def init_logging(cli_arguments):
|
||||
# This needs a separate 'Lector' in the os.path.join because
|
||||
# application name isn't explicitly set in this module
|
||||
location_prefix = os.path.join(
|
||||
QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.AppDataLocation),
|
||||
'Lector')
|
||||
os.makedirs(location_prefix, exist_ok=True)
|
||||
logger_filename = os.path.join(location_prefix, 'Lector.log')
|
||||
|
||||
log_level = 30 # Warning and above
|
||||
# Set log level according to command line arguments
|
||||
try:
|
||||
if cli_arguments[1] == 'debug':
|
||||
log_level = 10 # Debug and above
|
||||
print('Debug logging enabled')
|
||||
try:
|
||||
os.remove(logger_filename) # Remove old log for clarity
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
# Create logging object
|
||||
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')
|
@@ -88,11 +88,6 @@ 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')
|
||||
@@ -153,6 +148,8 @@ class Settings:
|
||||
self.parent.settings['annotations'] = list()
|
||||
self.settings.endGroup()
|
||||
|
||||
logger.info('Settings loaded')
|
||||
|
||||
def save_settings(self):
|
||||
current_settings = self.parent.settings
|
||||
|
||||
@@ -187,7 +184,6 @@ 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()
|
||||
|
@@ -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.warning('No paths saved for books')
|
||||
logger.warning('No book paths saved')
|
||||
else:
|
||||
# Convert to the dictionary format that is
|
||||
# to be fed into the QFileSystemModel
|
||||
@@ -264,9 +264,14 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
|
||||
self.database_path).set_library_paths(data_pairs)
|
||||
|
||||
if not data_pairs:
|
||||
logger.error('Can\'t scan - No book paths saved')
|
||||
try:
|
||||
if self.sender().objectName() == 'reloadLibrary':
|
||||
self.show()
|
||||
treeViewIndex = self.listModel.index(0, 0)
|
||||
self.listView.setCurrentIndex(treeViewIndex)
|
||||
self.page_switch(treeViewIndex)
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
@@ -39,6 +39,7 @@ import pickle
|
||||
import logging
|
||||
import hashlib
|
||||
import threading
|
||||
import importlib
|
||||
|
||||
# The multiprocessing module does not work correctly on Windows
|
||||
if sys.platform.startswith('win'):
|
||||
@@ -57,26 +58,38 @@ from lector.parsers.comicbooks import ParseCOMIC
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
sorter = {
|
||||
'epub': ParseEPUB,
|
||||
'mobi': ParseMOBI,
|
||||
'azw': ParseMOBI,
|
||||
'azw3': ParseMOBI,
|
||||
'azw4': ParseMOBI,
|
||||
'prc': ParseMOBI,
|
||||
'fb2': ParseFB2,
|
||||
'fb2.zip': ParseFB2,
|
||||
'cbz': ParseCOMIC,
|
||||
'cbr': ParseCOMIC}
|
||||
|
||||
# The following imports are for optional dependencies
|
||||
try:
|
||||
# Check what dependencies are installed
|
||||
# python-poppler-qt5 - Optional
|
||||
poppler_check = importlib.util.find_spec('popplerqt5')
|
||||
if poppler_check:
|
||||
from lector.parsers.pdf import ParsePDF
|
||||
sorter['pdf'] = ParsePDF
|
||||
except ImportError:
|
||||
error_string = 'python-poppler-qt5 is not installed. Pdf files will not work.'
|
||||
else:
|
||||
error_string = 'python-poppler-qt5 is not installed. Will be unable to load PDFs.'
|
||||
print(error_string)
|
||||
logger.error(error_string)
|
||||
|
||||
# python-lxml - Required for everything except comics
|
||||
lxml_check = importlib.util.find_spec('lxml')
|
||||
if lxml_check:
|
||||
lxml_dependent = {
|
||||
'epub': ParseEPUB,
|
||||
'mobi': ParseMOBI,
|
||||
'azw': ParseMOBI,
|
||||
'azw3': ParseMOBI,
|
||||
'azw4': ParseMOBI,
|
||||
'prc': ParseMOBI,
|
||||
'fb2': ParseFB2,
|
||||
'fb2.zip': ParseFB2}
|
||||
sorter.update(lxml_dependent)
|
||||
else:
|
||||
critical_sting = 'python-lxml is not installed. Only comics will load.'
|
||||
print(critical_sting)
|
||||
logger.critical(critical_sting)
|
||||
|
||||
available_parsers = [i for i in sorter]
|
||||
progressbar = None # This is populated by __main__
|
||||
progress_emitter = None # This is to be made into a global variable
|
||||
|
@@ -124,8 +124,11 @@ class BackGroundBookSearch(QtCore.QThread):
|
||||
|
||||
if self.valid_directories:
|
||||
initiate_threads()
|
||||
info_string = str(len(self.valid_files)) + ' books found'
|
||||
logger.info(info_string)
|
||||
if self.valid_files:
|
||||
info_string = str(len(self.valid_files)) + ' books found'
|
||||
logger.info(info_string)
|
||||
else:
|
||||
logger.error('No books found on scan')
|
||||
else:
|
||||
logger.error('No valid directories')
|
||||
|
||||
|
@@ -407,6 +407,7 @@ class LibraryToolBar(QtWidgets.QToolBar):
|
||||
image_factory.get_image('reload'),
|
||||
self._translate('LibraryToolBar', 'Scan Library'),
|
||||
self)
|
||||
self.reloadLibraryButton.setObjectName('reloadLibrary')
|
||||
|
||||
self.libraryFilterButton = QtWidgets.QToolButton(self)
|
||||
self.libraryFilterButton.setIcon(image_factory.get_image('view-readermode'))
|
||||
|
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
beautifulsoup4==4.7.1
|
||||
lxml==4.3.0
|
||||
PyQt5==5.11.3
|
||||
PyQt5-sip==4.19.13
|
||||
soupsieve==1.7.2
|
Reference in New Issue
Block a user