mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Improve exception handling (#3290)
* fix: except only non-system-exiting exceptions see https://youtu.be/zrVfY9SuO64 * chore: add myself to CONTRIBUTORS file * refactor: explicitly specify possible exceptions If an exception is not an Exception, there are only three options left. see https://docs.python.org/3/library/exceptions.html#exception-hierarchy * refactor: use BaseException for fallback Co-authored-by: Damien Elmes <dae@users.noreply.github.com> * chore: add myself to contributors
This commit is contained in:
parent
a5a39c9302
commit
c0349ea9da
20 changed files with 39 additions and 38 deletions
|
@ -35,7 +35,7 @@ def runHook(hook: str, *args: Any) -> None:
|
||||||
for func in hookFuncs:
|
for func in hookFuncs:
|
||||||
try:
|
try:
|
||||||
func(*args)
|
func(*args)
|
||||||
except:
|
except Exception:
|
||||||
hookFuncs.remove(func)
|
hookFuncs.remove(func)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ def runFilter(hook: str, arg: Any, *args: Any) -> Any:
|
||||||
for func in hookFuncs:
|
for func in hookFuncs:
|
||||||
try:
|
try:
|
||||||
arg = func(arg, *args)
|
arg = func(arg, *args)
|
||||||
except:
|
except Exception:
|
||||||
hookFuncs.remove(func)
|
hookFuncs.remove(func)
|
||||||
raise
|
raise
|
||||||
return arg
|
return arg
|
||||||
|
|
|
@ -99,15 +99,15 @@ class TextImporter(NoteImporter):
|
||||||
if not self.delimiter:
|
if not self.delimiter:
|
||||||
try:
|
try:
|
||||||
self.dialect = sniffer.sniff("\n".join(self.data[:10]), self.patterns)
|
self.dialect = sniffer.sniff("\n".join(self.data[:10]), self.patterns)
|
||||||
except:
|
except Exception:
|
||||||
try:
|
try:
|
||||||
self.dialect = sniffer.sniff(self.data[0], self.patterns)
|
self.dialect = sniffer.sniff(self.data[0], self.patterns)
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
if self.dialect:
|
if self.dialect:
|
||||||
try:
|
try:
|
||||||
reader = csv.reader(self.data, self.dialect, doublequote=True)
|
reader = csv.reader(self.data, self.dialect, doublequote=True)
|
||||||
except:
|
except Exception:
|
||||||
err()
|
err()
|
||||||
else:
|
else:
|
||||||
if not self.delimiter:
|
if not self.delimiter:
|
||||||
|
@ -126,7 +126,7 @@ class TextImporter(NoteImporter):
|
||||||
if row:
|
if row:
|
||||||
self.numFields = len(row)
|
self.numFields = len(row)
|
||||||
break
|
break
|
||||||
except:
|
except Exception:
|
||||||
err()
|
err()
|
||||||
self.initMapping()
|
self.initMapping()
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,7 @@ def get_def_lang(user_lang: str | None = None) -> tuple[int, str]:
|
||||||
# this will return a different format on Windows (e.g. Italian_Italy), resulting in us falling back to en_US
|
# this will return a different format on Windows (e.g. Italian_Italy), resulting in us falling back to en_US
|
||||||
# further below
|
# further below
|
||||||
(sys_lang, enc) = locale.getlocale()
|
(sys_lang, enc) = locale.getlocale()
|
||||||
except:
|
except Exception:
|
||||||
# fails on osx
|
# fails on osx
|
||||||
sys_lang = "en_US"
|
sys_lang = "en_US"
|
||||||
if user_lang in compatMap:
|
if user_lang in compatMap:
|
||||||
|
|
|
@ -170,7 +170,7 @@ def _err_msg(col: anki.collection.Collection, type: str, texpath: str) -> str:
|
||||||
if not log:
|
if not log:
|
||||||
raise Exception()
|
raise Exception()
|
||||||
msg += f"<small><pre>{html.escape(log)}</pre></small>"
|
msg += f"<small><pre>{html.escape(log)}</pre></small>"
|
||||||
except:
|
except Exception:
|
||||||
msg += col.tr.media_have_you_installed_latex_and_dvipngdvisvgm()
|
msg += col.tr.media_have_you_installed_latex_and_dvipngdvisvgm()
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
|
@ -722,7 +722,7 @@ select count(), avg(ivl), max(ivl) from cards where did in %s and queue = {QUEUE
|
||||||
tot = bad + good
|
tot = bad + good
|
||||||
try:
|
try:
|
||||||
pct = good / float(tot) * 100
|
pct = good / float(tot) * 100
|
||||||
except:
|
except Exception:
|
||||||
pct = 0
|
pct = 0
|
||||||
i.append(
|
i.append(
|
||||||
"Correct: <b>%(pct)0.2f%%</b><br>(%(good)d of %(tot)d)"
|
"Correct: <b>%(pct)0.2f%%</b><br>(%(good)d of %(tot)d)"
|
||||||
|
|
|
@ -29,7 +29,7 @@ try:
|
||||||
|
|
||||||
to_json_bytes: Callable[[Any], bytes] = orjson.dumps
|
to_json_bytes: Callable[[Any], bytes] = orjson.dumps
|
||||||
from_json_bytes = orjson.loads
|
from_json_bytes = orjson.loads
|
||||||
except:
|
except Exception:
|
||||||
print("orjson is missing; DB operations will be slower")
|
print("orjson is missing; DB operations will be slower")
|
||||||
|
|
||||||
def to_json_bytes(obj: Any) -> bytes:
|
def to_json_bytes(obj: Any) -> bytes:
|
||||||
|
@ -215,7 +215,7 @@ def call(argv: list[str], wait: bool = True, **kwargs: Any) -> int:
|
||||||
info = subprocess.STARTUPINFO() # type: ignore
|
info = subprocess.STARTUPINFO() # type: ignore
|
||||||
try:
|
try:
|
||||||
info.dwFlags |= subprocess.STARTF_USESHOWWINDOW # type: ignore
|
info.dwFlags |= subprocess.STARTF_USESHOWWINDOW # type: ignore
|
||||||
except:
|
except Exception:
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
info.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW # type: ignore
|
info.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW # type: ignore
|
||||||
else:
|
else:
|
||||||
|
@ -286,7 +286,7 @@ def plat_desc() -> str:
|
||||||
else:
|
else:
|
||||||
theos = system
|
theos = system
|
||||||
break
|
break
|
||||||
except:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
return theos
|
return theos
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ def clear_tempfile(tf):
|
||||||
try:
|
try:
|
||||||
tf.close()
|
tf.close()
|
||||||
os.unlink(tf.name)
|
os.unlink(tf.name)
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ class {self.classname()}:
|
||||||
for hook in self._hooks:
|
for hook in self._hooks:
|
||||||
try:
|
try:
|
||||||
hook({", ".join(arg_names)})
|
hook({", ".join(arg_names)})
|
||||||
except:
|
except Exception:
|
||||||
# if the hook fails, remove it
|
# if the hook fails, remove it
|
||||||
self._hooks.remove(hook)
|
self._hooks.remove(hook)
|
||||||
raise
|
raise
|
||||||
|
@ -163,7 +163,7 @@ class {self.classname()}:
|
||||||
for filter in self._hooks:
|
for filter in self._hooks:
|
||||||
try:
|
try:
|
||||||
{arg_names[0]} = filter({", ".join(arg_names)})
|
{arg_names[0]} = filter({", ".join(arg_names)})
|
||||||
except:
|
except Exception:
|
||||||
# if the hook fails, remove it
|
# if the hook fails, remove it
|
||||||
self._hooks.remove(filter)
|
self._hooks.remove(filter)
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -232,7 +232,7 @@ def setupLangAndBackend(
|
||||||
global _qtrans
|
global _qtrans
|
||||||
try:
|
try:
|
||||||
locale.setlocale(locale.LC_ALL, "")
|
locale.setlocale(locale.LC_ALL, "")
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# add _ and ngettext globals used by legacy code
|
# add _ and ngettext globals used by legacy code
|
||||||
|
@ -630,7 +630,7 @@ def _run(argv: list[str] | None = None, exec: bool = True) -> AnkiApp | None:
|
||||||
pmLoadResult = pm.setupMeta()
|
pmLoadResult = pm.setupMeta()
|
||||||
|
|
||||||
Collection.initialize_backend_logging()
|
Collection.initialize_backend_logging()
|
||||||
except:
|
except Exception:
|
||||||
# will handle below
|
# will handle below
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
pm = None
|
pm = None
|
||||||
|
@ -720,7 +720,7 @@ def _run(argv: list[str] | None = None, exec: bool = True) -> AnkiApp | None:
|
||||||
# we must have a usable temp dir
|
# we must have a usable temp dir
|
||||||
try:
|
try:
|
||||||
tempfile.gettempdir()
|
tempfile.gettempdir()
|
||||||
except:
|
except Exception:
|
||||||
QMessageBox.critical(
|
QMessageBox.critical(
|
||||||
None,
|
None,
|
||||||
tr.qt_misc_error(),
|
tr.qt_misc_error(),
|
||||||
|
|
|
@ -87,6 +87,7 @@ def show(mw: aqt.AnkiQt) -> QDialog:
|
||||||
"Christian Krause",
|
"Christian Krause",
|
||||||
"Christian Rusche",
|
"Christian Rusche",
|
||||||
"Dave Druelinger",
|
"Dave Druelinger",
|
||||||
|
"David Culley",
|
||||||
"David Smith",
|
"David Smith",
|
||||||
"Dmitry Mikheev",
|
"Dmitry Mikheev",
|
||||||
"Dotan Cohen",
|
"Dotan Cohen",
|
||||||
|
|
|
@ -248,7 +248,7 @@ class AddonManager:
|
||||||
__import__(addon.dir_name)
|
__import__(addon.dir_name)
|
||||||
except AbortAddonImport:
|
except AbortAddonImport:
|
||||||
pass
|
pass
|
||||||
except:
|
except Exception:
|
||||||
name = html.escape(addon.human_name())
|
name = html.escape(addon.human_name())
|
||||||
page = addon.page()
|
page = addon.page()
|
||||||
if page:
|
if page:
|
||||||
|
@ -341,7 +341,7 @@ class AddonManager:
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
print(f"json error in add-on {module}:\n{e}")
|
print(f"json error in add-on {module}:\n{e}")
|
||||||
return dict()
|
return dict()
|
||||||
except:
|
except Exception:
|
||||||
# missing meta file, etc
|
# missing meta file, etc
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
|
@ -644,7 +644,7 @@ class AddonManager:
|
||||||
try:
|
try:
|
||||||
with open(path, encoding="utf8") as f:
|
with open(path, encoding="utf8") as f:
|
||||||
return json.load(f)
|
return json.load(f)
|
||||||
except:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set_config_help_action(self, module: str, action: Callable[[], str]) -> None:
|
def set_config_help_action(self, module: str, action: Callable[[], str]) -> None:
|
||||||
|
|
|
@ -243,7 +243,7 @@ class DataModel(QAbstractTableModel):
|
||||||
self._state = self._state.toggle_state()
|
self._state = self._state.toggle_state()
|
||||||
try:
|
try:
|
||||||
self._search_inner(context)
|
self._search_inner(context)
|
||||||
except:
|
except Exception:
|
||||||
# rollback to prevent inconsistent state
|
# rollback to prevent inconsistent state
|
||||||
self._state = self._state.toggle_state()
|
self._state = self._state.toggle_state()
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -293,7 +293,7 @@ class DebugConsole(QDialog):
|
||||||
try:
|
try:
|
||||||
# pylint: disable=exec-used
|
# pylint: disable=exec-used
|
||||||
exec(text, vars)
|
exec(text, vars)
|
||||||
except:
|
except Exception:
|
||||||
self._output += traceback.format_exc()
|
self._output += traceback.format_exc()
|
||||||
self._captureOutput(False)
|
self._captureOutput(False)
|
||||||
buf = ""
|
buf = ""
|
||||||
|
|
|
@ -267,7 +267,7 @@ class DeckConf(QDialog):
|
||||||
if i == int(i):
|
if i == int(i):
|
||||||
i = int(i)
|
i = int(i)
|
||||||
ret.append(i)
|
ret.append(i)
|
||||||
except:
|
except Exception:
|
||||||
# invalid, don't update
|
# invalid, don't update
|
||||||
showWarning(tr.scheduling_steps_must_be_numbers())
|
showWarning(tr.scheduling_steps_must_be_numbers())
|
||||||
return
|
return
|
||||||
|
|
|
@ -200,7 +200,7 @@ class AnkiQt(QMainWindow):
|
||||||
self.setupUI()
|
self.setupUI()
|
||||||
self.setupAddons(args)
|
self.setupAddons(args)
|
||||||
self.finish_ui_setup()
|
self.finish_ui_setup()
|
||||||
except:
|
except Exception:
|
||||||
showInfo(tr.qt_misc_error_during_startup(val=traceback.format_exc()))
|
showInfo(tr.qt_misc_error_during_startup(val=traceback.format_exc()))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
# must call this after ui set up
|
# must call this after ui set up
|
||||||
|
@ -351,7 +351,7 @@ class AnkiQt(QMainWindow):
|
||||||
f.profiles.addItems(profs)
|
f.profiles.addItems(profs)
|
||||||
try:
|
try:
|
||||||
idx = profs.index(self.pm.name)
|
idx = profs.index(self.pm.name)
|
||||||
except:
|
except Exception:
|
||||||
idx = 0
|
idx = 0
|
||||||
f.profiles.setCurrentRow(idx)
|
f.profiles.setCurrentRow(idx)
|
||||||
|
|
||||||
|
@ -681,7 +681,7 @@ class AnkiQt(QMainWindow):
|
||||||
self.maybeOptimize()
|
self.maybeOptimize()
|
||||||
if not dev_mode:
|
if not dev_mode:
|
||||||
corrupt = self.col.db.scalar("pragma quick_check") != "ok"
|
corrupt = self.col.db.scalar("pragma quick_check") != "ok"
|
||||||
except:
|
except Exception:
|
||||||
corrupt = True
|
corrupt = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -693,7 +693,7 @@ class AnkiQt(QMainWindow):
|
||||||
force=False,
|
force=False,
|
||||||
wait_for_completion=False,
|
wait_for_completion=False,
|
||||||
)
|
)
|
||||||
except:
|
except Exception:
|
||||||
print("backup on close failed")
|
print("backup on close failed")
|
||||||
self.col.close(downgrade=False)
|
self.col.close(downgrade=False)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -44,7 +44,7 @@ def _patch_pkgutil() -> None:
|
||||||
reader = module.__loader__.get_resource_reader(package) # type: ignore[attr-defined]
|
reader = module.__loader__.get_resource_reader(package) # type: ignore[attr-defined]
|
||||||
with reader.open_resource(resource) as f:
|
with reader.open_resource(resource) as f:
|
||||||
return f.read()
|
return f.read()
|
||||||
except:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
pkgutil.get_data = get_data_custom
|
pkgutil.get_data = get_data_custom
|
||||||
|
|
|
@ -384,7 +384,7 @@ class Preferences(QDialog):
|
||||||
lang = lang.replace("-", "_")
|
lang = lang.replace("-", "_")
|
||||||
try:
|
try:
|
||||||
return codes.index(lang)
|
return codes.index(lang)
|
||||||
except:
|
except Exception:
|
||||||
return codes.index("en_US")
|
return codes.index("en_US")
|
||||||
|
|
||||||
def on_language_index_changed(self, idx: int) -> None:
|
def on_language_index_changed(self, idx: int) -> None:
|
||||||
|
|
|
@ -216,7 +216,7 @@ class ProfileManager:
|
||||||
self.name = name
|
self.name = name
|
||||||
try:
|
try:
|
||||||
self.profile = self._unpickle(data)
|
self.profile = self._unpickle(data)
|
||||||
except:
|
except Exception:
|
||||||
print(traceback.format_exc())
|
print(traceback.format_exc())
|
||||||
QMessageBox.warning(
|
QMessageBox.warning(
|
||||||
None,
|
None,
|
||||||
|
@ -285,7 +285,7 @@ class ProfileManager:
|
||||||
showWarning(tr.profiles_anki_could_not_rename_your_profile())
|
showWarning(tr.profiles_anki_could_not_rename_your_profile())
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
except:
|
except BaseException:
|
||||||
self.db.rollback()
|
self.db.rollback()
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
|
@ -386,7 +386,7 @@ class ProfileManager:
|
||||||
if self.db:
|
if self.db:
|
||||||
try:
|
try:
|
||||||
self.db.close()
|
self.db.close()
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
for suffix in ("", "-journal"):
|
for suffix in ("", "-journal"):
|
||||||
fpath = path + suffix
|
fpath = path + suffix
|
||||||
|
@ -406,7 +406,7 @@ create table if not exists profiles
|
||||||
data = self.db.scalar(
|
data = self.db.scalar(
|
||||||
"select cast(data as blob) from profiles where name = '_global'"
|
"select cast(data as blob) from profiles where name = '_global'"
|
||||||
)
|
)
|
||||||
except:
|
except Exception:
|
||||||
traceback.print_stack()
|
traceback.print_stack()
|
||||||
if result.loadError:
|
if result.loadError:
|
||||||
# already failed, prevent infinite loop
|
# already failed, prevent infinite loop
|
||||||
|
@ -420,7 +420,7 @@ create table if not exists profiles
|
||||||
try:
|
try:
|
||||||
self.meta = self._unpickle(data)
|
self.meta = self._unpickle(data)
|
||||||
return result
|
return result
|
||||||
except:
|
except Exception:
|
||||||
traceback.print_stack()
|
traceback.print_stack()
|
||||||
print("resetting corrupt _global")
|
print("resetting corrupt _global")
|
||||||
result.loadError = True
|
result.loadError = True
|
||||||
|
|
|
@ -13,7 +13,7 @@ from typing import TypeVar, Union
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import PyQt6
|
import PyQt6
|
||||||
except:
|
except Exception:
|
||||||
from .qt5 import * # type: ignore
|
from .qt5 import * # type: ignore
|
||||||
else:
|
else:
|
||||||
if os.getenv("ENABLE_QT5_COMPAT"):
|
if os.getenv("ENABLE_QT5_COMPAT"):
|
||||||
|
|
|
@ -504,13 +504,13 @@ if is_win:
|
||||||
def _voice_to_objects(self, voice: Any) -> list[WindowsVoice]:
|
def _voice_to_objects(self, voice: Any) -> list[WindowsVoice]:
|
||||||
try:
|
try:
|
||||||
langs = voice.GetAttribute("language")
|
langs = voice.GetAttribute("language")
|
||||||
except:
|
except Exception:
|
||||||
# no associated language; ignore
|
# no associated language; ignore
|
||||||
return []
|
return []
|
||||||
langs = lcid_hex_str_to_lang_codes(langs)
|
langs = lcid_hex_str_to_lang_codes(langs)
|
||||||
try:
|
try:
|
||||||
name = voice.GetAttribute("name")
|
name = voice.GetAttribute("name")
|
||||||
except:
|
except Exception:
|
||||||
# some voices may not have a name
|
# some voices may not have a name
|
||||||
name = "unknown"
|
name = "unknown"
|
||||||
name = self._tidy_name(name)
|
name = self._tidy_name(name)
|
||||||
|
|
Loading…
Reference in a new issue