Fix file encoding inconsistencies, windows defaults to cp1252, which is
not Unicode compatible.
Add logging for all exceptions in the comicapi package
Ensure that all exceptions are logged and shown to the user
This commit is contained in:
Timmy Welch 2022-04-11 14:52:41 -07:00
parent 5658f261b0
commit 6da177471b
8 changed files with 72 additions and 25 deletions

View File

@ -92,6 +92,7 @@ class SevenZipArchiver:
try:
self.rebuild_zip_file([archive_file])
except:
logger.exception("Failed to remove %s from 7zip archive", archive_file)
return False
else:
return True
@ -110,6 +111,7 @@ class SevenZipArchiver:
zf.writestr(data, archive_file)
return True
except:
logger.exception("Writing zip file failed")
return False
def get_filename_list(self):
@ -194,6 +196,7 @@ class ZipArchiver:
try:
self.rebuild_zip_file([archive_file])
except:
logger.exception("Failed to remove %s from zip archive", archive_file)
return False
else:
return True
@ -306,7 +309,7 @@ class ZipArchiver:
else:
raise Exception("Failed to write comment to zip file!")
except Exception:
logger.exception()
logger.exception("Writing comment to %s failed", filename)
return False
else:
return True
@ -342,7 +345,7 @@ class RarArchiver:
self.rar_exe_path = rar_exe_path
if RarArchiver.devnull is None:
RarArchiver.devnull = open(os.devnull, "w")
RarArchiver.devnull = open(os.devnull, "bw")
# windows only, keeps the cmd.exe from popping up
if platform.system() == "Windows":
@ -360,9 +363,8 @@ class RarArchiver:
try:
# write comment to temp file
tmp_fd, tmp_name = tempfile.mkstemp()
f = os.fdopen(tmp_fd, "w+")
f.write(comment)
f.close()
with os.fdopen(tmp_fd, "wb") as f:
f.write(comment.encode("utf-8"))
working_dir = os.path.dirname(os.path.abspath(self.path))
@ -441,7 +443,7 @@ class RarArchiver:
# TODO: will this break if 'archive_file' is in a subfolder. i.e. "foo/bar.txt"
# will need to create the subfolder above, I guess...
with open(tmp_file, "w") as f:
with open(tmp_file, "wb") as f:
f.write(data)
# use external program to write file to Rar archive
@ -457,7 +459,9 @@ class RarArchiver:
time.sleep(1)
os.remove(tmp_file)
os.rmdir(tmp_folder)
except:
except Exception as e:
logger.info(str(e))
logger.exception("Failed write %s to rar archive", archive_file)
return False
else:
return True
@ -479,6 +483,7 @@ class RarArchiver:
if platform.system() == "Darwin":
time.sleep(1)
except:
logger.exception("Failed to remove %s from rar archive", archive_file)
return False
else:
return True
@ -543,7 +548,6 @@ class FolderArchiver:
try:
with open(fname, "rb") as f:
data = f.read()
f.close()
except IOError:
logger.exception("Failed to read: %s", fname)
@ -553,11 +557,10 @@ class FolderArchiver:
fname = os.path.join(self.path, archive_file)
try:
with open(fname, "w+") as f:
with open(fname, "wb") as f:
f.write(data)
f.close()
except:
logger.exception("Failed to read: %s", fname)
logger.exception("Failed to write: %s", fname)
return False
else:
return True
@ -568,7 +571,7 @@ class FolderArchiver:
try:
os.remove(fname)
except:
logger.exception("Failed to read: %s", fname)
logger.exception("Failed to remove: %s", fname)
return False
else:
return True
@ -976,7 +979,7 @@ class ComicArchive:
if raw_cix == "":
raw_cix = None
cix_string = ComicInfoXml().string_from_metadata(metadata, xml=raw_cix)
write_success = self.archiver.write_file(self.ci_xml_filename, cix_string)
write_success = self.archiver.write_file(self.ci_xml_filename, cix_string.encode("utf-8"))
if write_success:
self.has__cix = True
self.cix_md = metadata
@ -1088,8 +1091,7 @@ class ComicArchive:
data = self.archiver.read_file(n)
except Exception as e:
data = ""
err_msg = f"Error reading in Comet XML for validation!: {e}"
logger.warning(err_msg)
logger.warning("Error reading in Comet XML for validation!: %s", e)
if CoMet().validate_string(data):
# since we found it, save it!
self.comet_filename = n

View File

@ -119,5 +119,5 @@ class ComicBookInfo:
cbi_container = self.create_json_dictionary(metadata)
with open(filename, "w") as f:
with open(filename, "w", encoding="utf-8") as f:
f.write(json.dumps(cbi_container, indent=4))

View File

@ -59,11 +59,11 @@ class ComicVineCacher:
def create_cache_db(self):
# create the version file
with open(self.version_file, "w") as f:
with open(self.version_file, "w", encoding="utf-8") as f:
f.write(ctversion.version)
# this will wipe out any existing version
open(self.db_file, "w").close()
open(self.db_file, "wb").close()
con = lite.connect(self.db_file)

View File

@ -120,7 +120,7 @@ class ImageFetcher:
def create_image_db(self):
# this will wipe out any existing version
open(self.db_file, "w").close()
open(self.db_file, "wb").close()
# wipe any existing image cache folder too
if os.path.isdir(self.cache_folder):

View File

@ -37,8 +37,52 @@ logger.setLevel(logging.DEBUG)
try:
qt_available = True
from PyQt5 import QtGui, QtWidgets
from PyQt5 import QtCore, QtGui, QtWidgets
def show_exception_box(log_msg):
"""Checks if a QApplication instance is available and shows a messagebox with the exception message.
If unavailable (non-console application), log an additional notice.
"""
if QtWidgets.QApplication.instance() is not None:
errorbox = QtWidgets.QMessageBox()
errorbox.setText("Oops. An unexpected error occured:\n{0}".format(log_msg))
errorbox.exec_()
QtWidgets.QApplication.exit(1)
else:
logger.debug("No QApplication instance available.")
class UncaughtHook(QtCore.QObject):
_exception_caught = QtCore.pyqtSignal(object)
def __init__(self, *args, **kwargs):
super(UncaughtHook, self).__init__(*args, **kwargs)
# this registers the exception_hook() function as hook with the Python interpreter
sys.excepthook = self.exception_hook
# connect signal to execute the message box function always on main thread
self._exception_caught.connect(show_exception_box)
def exception_hook(self, exc_type, exc_value, exc_traceback):
"""Function handling uncaught exceptions.
It is triggered each time an uncaught exception occurs.
"""
if issubclass(exc_type, KeyboardInterrupt):
# ignore keyboard interrupt to support console applications
sys.__excepthook__(exc_type, exc_value, exc_traceback)
else:
exc_info = (exc_type, exc_value, exc_traceback)
log_msg = "\n".join(
["".join(traceback.format_tb(exc_traceback)), "{0}: {1}".format(exc_type.__name__, exc_value)]
)
logger.critical(
"Uncaught exception: %s", "{0}: {1}".format(exc_type.__name__, exc_value), exc_info=exc_info
)
# trigger message box show
self._exception_caught.emit(log_msg)
qt_exception_hook = UncaughtHook()
from comictaggerlib.taggerwindow import TaggerWindow
except ImportError as e:
logging.debug(e)
@ -106,7 +150,7 @@ def ctmain():
try:
cli.cli_mode(opts, SETTINGS)
except:
logger.exception()
logger.exception("CLI mode failed")
else:
os.environ["QtWidgets.QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
args = []
@ -149,7 +193,7 @@ def ctmain():
sys.exit(app.exec())
except Exception:
logger.exception()
logger.exception("GUI mode failed")
QtWidgets.QMessageBox.critical(
QtWidgets.QMainWindow(), "Error", "Unhandled exception in app:\n" + traceback.format_exc()
)

View File

@ -239,7 +239,7 @@ class ComicTaggerSettings:
yield line
line = f.readline()
with open(self.settings_file, "r") as f:
with open(self.settings_file, "r", encoding="utf-8") as f:
self.config.read_file(readline_generator(f))
self.rar_exe_path = self.config.get("settings", "rar_exe_path")
@ -451,5 +451,5 @@ class ComicTaggerSettings:
self.config.set("autotag", "remove_archive_after_successful_match", self.remove_archive_after_successful_match)
self.config.set("autotag", "wait_and_retry_on_rate_limit", self.wait_and_retry_on_rate_limit)
with open(self.settings_file, "w") as configfile:
with open(self.settings_file, "w", encoding="utf-8") as configfile:
self.config.write(configfile)

View File

@ -4,4 +4,5 @@ setuptools_scm[toml]>=3.4
wheel
black>=22
flake8==4.*
flake8-encodings
isort>=5.10

View File

@ -24,7 +24,7 @@ def read(fname):
str
File contents.
"""
with open(os.path.join(os.path.dirname(__file__), fname)) as f:
with open(os.path.join(os.path.dirname(__file__), fname), encoding="utf-8") as f:
return f.read()