convert invariant assertions to if statements

The packaged builds of 2.1.50 use python -OO, which means our assertion
statements won't be run. This is not an issue for unit tests (as we
don't run them from a packaged build), or for type assertions (which are
added for mypy's benefit), but we do need to ensure that invariant checks
are still run.
This commit is contained in:
Damien Elmes 2021-11-25 17:47:50 +10:00
parent 88392634a8
commit 9ed13eee80
15 changed files with 53 additions and 30 deletions

View file

@ -40,7 +40,8 @@ from .fluent import GeneratedTranslations, LegacyTranslationEnum
# the following comment is required to suppress a warning that only shows up
# when there are other pylint failures
# pylint: disable=c-extension-no-member
assert rsbridge.buildhash() == anki.buildinfo.buildhash
if rsbridge.buildhash() != anki.buildinfo.buildhash:
raise Exception("rsbridge and anki build hashes do not match")
class RustBackend(RustBackendGenerated):

View file

@ -201,7 +201,8 @@ class Card(DeprecatedNamesMixin):
def set_user_flag(self, flag: int) -> None:
print("use col.set_user_flag_for_cards() instead")
assert 0 <= flag <= 7
if not 0 <= flag <= 7:
raise Exception("invalid flag")
self.flags = (self.flags & ~0b111) | flag
@deprecated(info="use card.render_output() directly")

View file

@ -264,8 +264,8 @@ class Collection(DeprecatedNamesMixin):
self.models._clear_cache()
def reopen(self, after_full_sync: bool = False) -> None:
assert not self.db
assert self.path.endswith(".anki2")
if self.db:
raise Exception("reopen() called with open db")
self._last_checkpoint_at = time.time()
self._undo: _UndoInfo = None

View file

@ -109,7 +109,8 @@ class DeckManager(DeprecatedNamesMixin):
def add_deck_legacy(self, deck: DeckDict) -> OpChangesWithId:
"Add a deck created with new_deck_legacy(). Must have id of 0."
assert deck["id"] == 0
if not deck["id"] == 0:
raise Exception("id should be 0")
return self.col._backend.add_deck_legacy(to_json_bytes(deck))
def id(

View file

@ -117,7 +117,8 @@ class NoteImporter(Importer):
def importNotes(self, notes: list[ForeignNote]) -> None:
"Convert each card into a note, apply attributes and add to col."
assert self.mappingOk()
if not self.mappingOk():
raise Exception("mapping not ok")
# note whether tags are mapped
self._tagsMapped = False
for f in self.mapping:

View file

@ -304,12 +304,14 @@ class ModelManager(DeprecatedNamesMixin):
def rename_field(
self, notetype: NotetypeDict, field: FieldDict, new_name: str
) -> None:
assert field in notetype["flds"]
if not field in notetype["flds"]:
raise Exception("invalid field")
field["name"] = new_name
def set_sort_index(self, notetype: NotetypeDict, idx: int) -> None:
"Modifies schema."
assert 0 <= idx < len(notetype["flds"])
if not 0 <= idx < len(notetype["flds"]):
raise Exception("invalid sort index")
notetype["sortf"] = idx
# Adding & changing templates
@ -332,7 +334,8 @@ class ModelManager(DeprecatedNamesMixin):
def remove_template(self, notetype: NotetypeDict, template: TemplateDict) -> None:
"Modifies schema."
assert len(notetype["tmpls"]) > 1
if not len(notetype["tmpls"]) > 1:
raise Exception("must have 1 template")
notetype["tmpls"].remove(template)
def reposition_template(

View file

@ -34,7 +34,8 @@ class Note(DeprecatedNamesMixin):
model: NotetypeDict | NotetypeId | None = None,
id: NoteId | None = None,
) -> None:
assert not (model and id)
if model and id:
raise Exception("only model or id should be provided")
notetype_id = model["id"] if isinstance(model, dict) else model
self.col = col.weakref()
@ -76,7 +77,8 @@ class Note(DeprecatedNamesMixin):
def flush(self) -> None:
"""This preserves any current checkpoint.
For an undo entry, use col.update_note() instead."""
assert self.id != 0
if self.id == 0:
raise Exception("can't flush a new note")
self.col._backend.update_notes(
notes=[self._to_backend_note()], skip_undo_entry=True
)

View file

@ -449,8 +449,8 @@ limit ?"""
##########################################################################
def answerCard(self, card: Card, ease: int) -> None:
assert 1 <= ease <= 4
assert 0 <= card.queue <= 4
if (not 1 <= ease <= 4) or (not 0 <= card.queue <= 4):
raise Exception("invalid ease or queue")
self.col.save_card_review_undo_info(card)
if self._burySiblingsOnAnswer:
self._burySiblings(card)
@ -772,7 +772,8 @@ limit ?"""
# note: when adding revlog entries in the future, make sure undo
# code deletes the entries
def _answerCardPreview(self, card: Card, ease: int) -> None:
assert 1 <= ease <= 2
if not 1 <= ease <= 2:
raise Exception("invalid ease")
if ease == BUTTON_ONE:
# repeat after delay
@ -799,7 +800,8 @@ limit ?"""
card.odid = DeckId(0)
def _restorePreviewCard(self, card: Card) -> None:
assert card.odid
if not card.odid:
raise Exception("card should have odid set")
card.due = card.odue
@ -965,9 +967,12 @@ limit ?"""
# next interval for card when answered early+correctly
def _earlyReviewIvl(self, card: Card, ease: int) -> int:
assert card.odid and card.type == CARD_TYPE_REV
assert card.factor
assert ease > 1
if (
not (card.odid and card.type == CARD_TYPE_REV)
or not card.factor
or not ease > 1
):
raise Exception("invalid input to earlyReviewIvl")
elapsed = card.ivl - (card.odue - self.today)

View file

@ -72,7 +72,7 @@ class Scheduler(SchedulerBaseWithLegacy):
elif rating == CardAnswer.EASY:
new_state = states.easy
else:
assert False, "invalid rating"
raise Exception("invalid rating")
return CardAnswer(
card_id=card.id,
@ -157,7 +157,7 @@ class Scheduler(SchedulerBaseWithLegacy):
elif ease == BUTTON_FOUR:
rating = CardAnswer.EASY
else:
assert False, "invalid ease"
raise Exception("invalid ease")
states = self.col._backend.get_next_card_states(card.id)
changes = self.answer_card(
@ -223,7 +223,7 @@ class Scheduler(SchedulerBaseWithLegacy):
elif ease == BUTTON_FOUR:
new_state = states.easy
else:
assert False, "invalid ease"
raise Exception("invalid ease")
return self._interval_for_state(new_state)

View file

@ -267,7 +267,8 @@ class DeckConf(QDialog):
continue
try:
i = float(item)
assert i > 0
if not i > 0:
raise Exception("0 invalid")
if i == int(i):
i = int(i)
ret.append(i)

View file

@ -333,7 +333,8 @@ class FilteredDeckConfigDialog(QDialog):
continue
try:
i = float(item)
assert i > 0
if not i > 0:
raise Exception("0 invalid")
ret.append(i)
except:
# invalid, don't update

View file

@ -608,7 +608,8 @@ class AnkiQt(QMainWindow):
def backup(self) -> None:
"Read data into memory, and complete backup on a background thread."
assert not self.col or not self.col.db
if self.col and self.col.db:
raise Exception("collection must be closed")
nbacks = self.pm.profile["numBackups"]
if not nbacks or dev_mode:
@ -706,7 +707,8 @@ class AnkiQt(QMainWindow):
self._background_op_count -= 1
if not self._background_op_count:
gui_hooks.backend_did_block()
assert self._background_op_count >= 0
if not self._background_op_count >= 0:
raise Exception("no background ops active")
def _synthesize_op_did_execute_from_reset(self) -> None:
"""Fire the `operation_did_execute` hook with everything marked as changed,
@ -1357,7 +1359,8 @@ title="{}" {}>{}</button>""".format(
# this will gradually be phased out
def onSchemaMod(self, arg: bool) -> bool:
assert self.inMainThread()
if not self.inMainThread():
raise Exception("not in main thread")
progress_shown = self.progress.busy()
if progress_shown:
self.progress.finish()

View file

@ -199,7 +199,8 @@ class ProfileManager:
return pickle.dumps(obj, protocol=4)
def load(self, name: str) -> bool:
assert name != "_global"
if name == "_global":
raise Exception("_global is not a valid name")
data = self.db.scalar(
"select cast(data as blob) from profiles where name = ?", name
)
@ -381,7 +382,8 @@ class ProfileManager:
# open DB file and read data
try:
self.db = DB(path)
assert self.db.scalar("pragma integrity_check") == "ok"
if not self.db.scalar("pragma integrity_check") == "ok":
raise Exception("corrupt db")
self.db.execute(
"""
create table if not exists profiles

View file

@ -88,7 +88,8 @@ def on_normal_sync_timer(mw: aqt.main.AnkiQt) -> None:
def sync_collection(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
auth = mw.pm.sync_auth()
assert auth
if not auth:
raise Exception("expected auth")
def on_timer() -> None:
on_normal_sync_timer(mw)

View file

@ -431,7 +431,8 @@ def getFile(
multi: bool = False, # controls whether a single or multiple files is returned
) -> Sequence[str] | str | None:
"Ask the user for a file."
assert not dir or not key
if dir and key:
raise Exception("expected dir or key")
if not dir:
dirkey = f"{key}Directory"
dir = aqt.mw.pm.profile.get(dirkey, "")