From eaeb51de6562de30585869746264a31be4f1412d Mon Sep 17 00:00:00 2001 From: Alessandro Date: Sat, 11 Apr 2020 15:27:05 +0200 Subject: [PATCH] Add some basic logging to the application. Also for severe errors, track them in info.log file in local folder --- .gitignore | 3 ++- src/acfvalue.py | 9 ++++---- src/artemis.py | 10 +++++++-- src/loggingconf.py | 45 ++++++++++++++++++++++++++++++++++++++++ src/settings.py | 4 +++- src/themesmanager.py | 14 ++++++------- src/updatescontroller.py | 3 +++ src/utilities.py | 4 +++- src/weatherdata.py | 2 ++ src/web_utilities.py | 12 +++++++++-- 10 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 src/loggingconf.py diff --git a/.gitignore b/.gitignore index bda3468..4e9cd78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -__pycache__ +__PYCache__ Data src/themes/__current_theme designer.bat @@ -8,3 +8,4 @@ launch.bat spec_files/**/output *.txt *.json +info.log diff --git a/src/acfvalue.py b/src/acfvalue.py index 3610153..81cf748 100644 --- a/src/acfvalue.py +++ b/src/acfvalue.py @@ -28,14 +28,13 @@ class ACFValue: self._description = "" self._value = value self._string = self._value - try: + if self._value.isdigit(): self.numeric_value = float(self._value) - except Exception: - self.is_numeric = False - self.numeric_value = 0.0 - else: self.is_numeric = True self._string += " ms" + else: + self.is_numeric = False + self.numeric_value = 0.0 @classmethod def list_from_series(cls, series): diff --git a/src/artemis.py b/src/artemis.py index 97e4259..dec8ff0 100644 --- a/src/artemis.py +++ b/src/artemis.py @@ -5,6 +5,7 @@ import webbrowser import os import sys from time import sleep, time +import logging from pandas import read_csv @@ -58,6 +59,7 @@ from downloadtargetfactory import get_download_target from settings import Settings from updatescontroller import UpdatesController from urlbutton import UrlButton +import loggingconf # noqa 401 # import default_imgs_rc @@ -256,6 +258,7 @@ class Artemis(QMainWindow, Ui_MainWindow): font.setUnderline(self.settings.font['underline']) self.apply_font(font) except Exception: # Invalid font + logging.warning("Invalid Font in settings.json") pass @pyqtSlot() @@ -357,6 +360,7 @@ class Artemis(QMainWindow, Ui_MainWindow): try: webbrowser.open(Constants.GFD_SITE + query.lower()) except Exception: + logging.error("Cannot open browser") pass def set_initial_size(self): @@ -445,7 +449,8 @@ class Artemis(QMainWindow, Ui_MainWindow): else: try: is_checksum_ok = checksum_ok(db, get_db_hash_code()) - except Exception: + except ValueError as e: + logging.info(e) pop_up(self, title=Messages.NO_CONNECTION, text=Messages.NO_CONNECTION_MSG).show() else: @@ -485,7 +490,8 @@ class Artemis(QMainWindow, Ui_MainWindow): else: try: is_checksum_ok = checksum_ok(db, get_db_hash_code()) - except Exception: + except ValueError as e: + logging.info(e) pop_up(self, title=Messages.NO_CONNECTION, text=Messages.NO_CONNECTION_MSG).show() else: diff --git a/src/loggingconf.py b/src/loggingconf.py new file mode 100644 index 0000000..5238922 --- /dev/null +++ b/src/loggingconf.py @@ -0,0 +1,45 @@ +import logging +import logging.config +from constants import __BASE_FOLDER__ +import os.path + +"""Import the module to initialize the logging configuration""" + +_LOGGING_CONFIG = { + 'version': 1, + 'formatters': { + 'general': { + 'format': '%(asctime)s::%(levelname)s::%(module)s::%(funcName)s::%(message)s', + 'datefmt': '%d/%m/%Y %I:%M:%S %p' + } + }, + 'handlers': { + 'console': { + 'level': 'INFO', + 'formatter': 'general', + 'class': 'logging.StreamHandler', + 'stream': 'ext://sys.stdout', + }, + 'file': { + 'class': 'logging.FileHandler', + 'level': 'ERROR', + 'filename': os.path.join(__BASE_FOLDER__, 'info.log'), + 'mode': 'w', + 'encoding': 'utf8', + 'formatter': 'general' + } + }, + 'root': { + 'level': 'DEBUG', + 'handlers': ['console', 'file'] + }, + 'loggers': { + 'root.sublogger': { + 'propagate': False, + 'level': 'DEBUG', + 'handlers': ['console', 'file'] + } + } +} + +logging.config.dictConfig(_LOGGING_CONFIG) diff --git a/src/settings.py b/src/settings.py index ac3aa2a..84edb1a 100644 --- a/src/settings.py +++ b/src/settings.py @@ -1,6 +1,7 @@ import os.path from constants import Constants import json +import logging class Settings: @@ -16,7 +17,8 @@ class Settings: try: with open(Constants.SETTINGS_FILE, 'r') as settings_file: self._dct = json.load(settings_file) - except Exception: + except FileNotFoundError: + logging.info("No settings.json file") pass # Invalid file. def save(self, **kwargs): diff --git a/src/themesmanager.py b/src/themesmanager.py index 60329cb..3979eb2 100644 --- a/src/themesmanager.py +++ b/src/themesmanager.py @@ -272,17 +272,15 @@ class ThemeManager: def apply_default_theme(self): """Apply the default theme if no theme is set or the theme name is invalid.""" - try: - self._theme_names[ - self._pretty_name(ThemeConstants.DEFAULT) - ].setChecked(True) - except Exception: + pretty_name = self._theme_names.get(self._pretty_name(ThemeConstants.DEFAULT), None) + if pretty_name is None: pop_up( self._owner, title=ThemeConstants.THEME_NOT_FOUND, text=ThemeConstants.MISSING_THEME ).show() else: + pretty_name.setChecked(True) self._apply(ThemeConstants.DEFAULT_THEME_PATH) def start(self): @@ -291,11 +289,11 @@ class ThemeManager: if self._owner.settings.theme is not None: theme_path = os.path.join(ThemeConstants.FOLDER, self._owner.settings.theme) theme_name = self._pretty_name(os.path.basename(theme_path)) - try: - self._theme_names[theme_name].setChecked(True) - except Exception: + theme = self._theme_names.get(theme_name, None) + if theme is None: self.apply_default_theme() else: + theme.setChecked(True) self._apply(theme_path, save=False) else: self.apply_default_theme() diff --git a/src/updatescontroller.py b/src/updatescontroller.py index d87baf7..49355b4 100644 --- a/src/updatescontroller.py +++ b/src/updatescontroller.py @@ -1,3 +1,4 @@ +import logging import subprocess as sp import webbrowser from PyQt5.QtCore import QObject, pyqtSlot, QProcess @@ -99,6 +100,7 @@ class UpdatesController(QObject): try: updater.startDetached(command) except BaseException: + logging.error("Unable to start updater") pass else: qApp.quit() @@ -122,6 +124,7 @@ class UpdatesController(QObject): ) as proc: updater_version = proc.stdout.read().rstrip("\r\n") # Strip any possible newline, to be sure. except Exception: + logging.error("Unable to query the updater") updater_version = latest_updater_version if latest_updater_version is None: return diff --git a/src/utilities.py b/src/utilities.py index dd08758..e860c3a 100644 --- a/src/utilities.py +++ b/src/utilities.py @@ -1,3 +1,4 @@ +import logging from functools import partial import hashlib from PyQt5.QtWidgets import QMessageBox @@ -107,7 +108,7 @@ def checksum_ok(data, reference_hash_code): Expects a sha256 code as argument.""" if reference_hash_code is None: - raise Exception("ERROR: Invalid hash code.") + raise ValueError("ERROR: Invalid hash code.") code = hashlib.sha256() code.update(data) return code.hexdigest() == reference_hash_code @@ -192,6 +193,7 @@ def safe_cast(value, cast_type, default=-1): try: r = cast_type(value) except Exception: + logging.error("Cast type failure") r = default finally: return r diff --git a/src/weatherdata.py b/src/weatherdata.py index 28f58b9..0b562dc 100644 --- a/src/weatherdata.py +++ b/src/weatherdata.py @@ -1,3 +1,4 @@ +import logging import re from PyQt5.QtGui import QPixmap from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject @@ -347,6 +348,7 @@ class ForecastData(_BaseWeatherData): self._set_dates(forecast, rows["solar_row"]) self._set_labels_values(labels_table) except Exception: + logging.error("Update ForecastData failure") pass def remove_data(self): diff --git a/src/web_utilities.py b/src/web_utilities.py index 70bd702..0896d6e 100644 --- a/src/web_utilities.py +++ b/src/web_utilities.py @@ -1,3 +1,4 @@ +import logging import os import sys import urllib3 @@ -39,12 +40,19 @@ def _download_multiline_file_as_list(url=Database.LINK_REF): try: return download_file(url, encoding="UTF-8").splitlines()[-1].split(Database.DELIMITER) except Exception: + logging.error("Database metadata download failure") return None def get_folder_hash_code(): - return _download_multiline_file_as_list()[0] + f = _download_multiline_file_as_list() + if f is not None: + return f[0] + return None def get_db_hash_code(): - return _download_multiline_file_as_list()[1] + f = _download_multiline_file_as_list() + if f is not None: + return f[1] + return None