PEP8 collection.py

This commit is contained in:
Damien Elmes 2021-06-27 15:12:22 +10:00
parent 17533e6a78
commit 1b15069b24
33 changed files with 329 additions and 377 deletions

View File

@ -48,4 +48,5 @@ disable=
good-names =
id,
tr,
db,
db,
ok,

View File

@ -1,6 +1,8 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
# pylint: enable=invalid-name
from __future__ import annotations
from typing import Any, Generator, List, Literal, Optional, Sequence, Tuple, Union, cast
@ -8,6 +10,8 @@ from typing import Any, Generator, List, Literal, Optional, Sequence, Tuple, Uni
import anki._backend.backend_pb2 as _pb
# protobuf we publicly export - listed first to avoid circular imports
from anki._legacy import DeprecatedNamesMixin, deprecated
SearchNode = _pb.SearchNode
Progress = _pb.Progress
EmptyCardsReport = _pb.EmptyCardsReport
@ -24,8 +28,6 @@ BrowserColumns = _pb.BrowserColumns
import copy
import os
import pprint
import re
import sys
import time
import traceback
@ -52,7 +54,6 @@ from anki.sync import SyncAuth, SyncOutput, SyncStatus
from anki.tags import TagManager
from anki.types import assert_exhaustive
from anki.utils import (
devMode,
from_json_bytes,
ids2str,
intTime,
@ -81,7 +82,7 @@ class LegacyCheckpoint:
LegacyUndoResult = Union[None, LegacyCheckpoint, LegacyReviewUndo]
class Collection:
class Collection(DeprecatedNamesMixin):
sched: Union[V1Scheduler, V2Scheduler, V3Scheduler]
def __init__(
@ -104,7 +105,7 @@ class Collection:
self.decks = DeckManager(self)
self.tags = TagManager(self)
self.conf = ConfigManager(self)
self._loadScheduler()
self._load_scheduler()
def name(self) -> Any:
return os.path.splitext(os.path.basename(self.path))[0]
@ -142,17 +143,17 @@ class Collection:
##########################################################################
# for backwards compatibility, v3 is represented as 2
supportedSchedulerVersions = (1, 2)
_supported_scheduler_versions = (1, 2)
def schedVer(self) -> Literal[1, 2]:
def sched_ver(self) -> Literal[1, 2]:
ver = self.conf.get("schedVer", 1)
if ver in self.supportedSchedulerVersions:
if ver in self._supported_scheduler_versions:
return ver
else:
raise Exception("Unsupported scheduler version")
def _loadScheduler(self) -> None:
ver = self.schedVer()
def _load_scheduler(self) -> None:
ver = self.sched_ver()
if ver == 1:
self.sched = V1Scheduler(self)
elif ver == 2:
@ -164,17 +165,17 @@ class Collection:
def upgrade_to_v2_scheduler(self) -> None:
self._backend.upgrade_scheduler()
self.clear_python_undo()
self._loadScheduler()
self._load_scheduler()
def v3_scheduler(self) -> bool:
return self.get_config_bool(Config.Bool.SCHED_2021)
def set_v3_scheduler(self, enabled: bool) -> None:
if self.v3_scheduler() != enabled:
if enabled and self.schedVer() != 2:
if enabled and self.sched_ver() != 2:
raise Exception("must upgrade to v2 scheduler first")
self.set_config_bool(Config.Bool.SCHED_2021, enabled)
self._loadScheduler()
self._load_scheduler()
# DB-related
##########################################################################
@ -193,14 +194,6 @@ class Collection:
def mod(self) -> int:
return self.db.scalar("select mod from col")
# legacy
def setMod(self) -> None:
# this is now a no-op, as modifications to things like the config
# will mark the collection modified automatically
pass
flush = setMod
def modified_by_backend(self) -> bool:
# Until we can move away from long-running transactions, the Python
# code needs to know if the transaction should be committed, so we need
@ -242,7 +235,6 @@ class Collection:
self._backend.close_collection(downgrade_to_schema11=downgrade)
self.db = None
self.media.close()
self._closeLog()
def close_for_full_sync(self) -> None:
# save and cleanup, but backend will take care of collection close
@ -251,7 +243,6 @@ class Collection:
self._clear_caches()
self.db = None
self.media.close()
self._closeLog()
def rollback(self) -> None:
self._clear_caches()
@ -273,7 +264,7 @@ class Collection:
log_path = ""
should_log = not self.server and self._should_log
if should_log:
log_path = self.path.replace(".anki2", "2.log")
log_path = self.path.replace(".anki2", ".log")
# connect
if not after_full_sync:
@ -288,17 +279,18 @@ class Collection:
self.db = DBProxy(weakref.proxy(self._backend))
self.db.begin()
self._openLog()
def modSchema(self, check: bool) -> None:
"Mark schema modified. Call this first so user can abort if necessary."
if not self.schemaChanged():
if check and not hooks.schema_will_change(proceed=True):
raise AbortSchemaModification()
def set_schema_modified(self) -> None:
self.db.execute("update col set scm=?", intTime(1000))
self.save()
def schemaChanged(self) -> bool:
def mod_schema(self, check: bool) -> None:
"Mark schema modified. GUI catches this and will ask user if required."
if not self.schema_changed():
if check and not hooks.schema_will_change(proceed=True):
raise AbortSchemaModification()
self.set_schema_modified()
def schema_changed(self) -> bool:
"True if schema changed since last sync."
return self.db.scalar("select scm > ls from col")
@ -308,12 +300,6 @@ class Collection:
else:
return -1
def beforeUpload(self) -> None:
"Called before a full upload."
self.save(trx=False)
self._backend.before_upload()
self.close(save=False, downgrade=True)
# Object helpers
##########################################################################
@ -341,7 +327,9 @@ class Collection:
# Utils
##########################################################################
def nextID(self, type: str, inc: bool = True) -> Any:
def nextID( # pylint: disable=invalid-name
self, type: str, inc: bool = True
) -> Any:
type = f"next{type.capitalize()}"
id = self.conf.get(type, 1)
if inc:
@ -353,15 +341,6 @@ class Collection:
self.autosave()
self.sched.reset()
# Deletion logging
##########################################################################
def _logRem(self, ids: List[Union[int, NoteId]], type: int) -> None:
self.db.executemany(
"insert into graves values (%d, ?, %d)" % (self.usn(), type),
([x] for x in ids),
)
# Notes
##########################################################################
@ -419,32 +398,16 @@ class Collection:
or None
)
# legacy
def noteCount(self) -> int:
def note_count(self) -> int:
return self.db.scalar("select count() from notes")
def newNote(self, forDeck: bool = True) -> Note:
"Return a new note with the current model."
return Note(self, self.models.current(forDeck))
def addNote(self, note: Note) -> int:
self.add_note(note, note.note_type()["did"])
return len(note.cards())
def remNotes(self, ids: Sequence[NoteId]) -> None:
self.remove_notes(ids)
def _remNotes(self, ids: List[NoteId]) -> None:
pass
# Cards
##########################################################################
def isEmpty(self) -> bool:
def is_empty(self) -> bool:
return not self.db.scalar("select 1 from cards limit 1")
def cardCount(self) -> Any:
def card_count(self) -> Any:
return self.db.scalar("select count() from cards")
def remove_cards_and_orphaned_notes(self, card_ids: Sequence[CardId]) -> None:
@ -457,36 +420,17 @@ class Collection:
def get_empty_cards(self) -> EmptyCardsReport:
return self._backend.get_empty_cards()
# legacy
def remCards(self, ids: List[CardId], notes: bool = True) -> None:
self.remove_cards_and_orphaned_notes(ids)
def emptyCids(self) -> List[CardId]:
print("emptyCids() will go away")
return []
# Card generation & field checksums/sort fields
##########################################################################
def after_note_updates(
self, nids: List[NoteId], mark_modified: bool, generate_cards: bool = True
) -> None:
"If notes modified directly in database, call this afterwards."
self._backend.after_note_updates(
nids=nids, generate_cards=generate_cards, mark_notes_modified=mark_modified
)
# legacy
def updateFieldCache(self, nids: List[NoteId]) -> None:
self.after_note_updates(nids, mark_modified=False, generate_cards=False)
# this also updates field cache
def genCards(self, nids: List[NoteId]) -> List[int]:
self.after_note_updates(nids, mark_modified=False, generate_cards=True)
# previously returned empty cards, no longer does
return []
# Finding cards
##########################################################################
@ -591,21 +535,21 @@ class Collection:
return self._backend.field_names_for_notes(nids)
# returns array of ("dupestr", [nids])
def findDupes(self, fieldName: str, search: str = "") -> List[Tuple[str, list]]:
def find_dupes(self, field_name: str, search: str = "") -> List[Tuple[str, list]]:
nids = self.find_notes(
self.build_search_string(search, SearchNode(field_name=fieldName))
self.build_search_string(search, SearchNode(field_name=field_name))
)
# go through notes
vals: Dict[str, List[int]] = {}
dupes = []
fields: Dict[int, int] = {}
def ordForMid(mid: NotetypeId) -> int:
def ord_for_mid(mid: NotetypeId) -> int:
if mid not in fields:
model = self.models.get(mid)
for c, f in enumerate(model["flds"]):
if f["name"].lower() == fieldName.lower():
fields[mid] = c
for idx, field in enumerate(model["flds"]):
if field["name"].lower() == field_name.lower():
fields[mid] = idx
break
return fields[mid]
@ -613,7 +557,7 @@ class Collection:
f"select id, mid, flds from notes where id in {ids2str(nids)}"
):
flds = splitFields(flds)
ord = ordForMid(mid)
ord = ord_for_mid(mid)
if ord is None:
continue
val = flds[ord]
@ -626,10 +570,6 @@ class Collection:
dupes.append((val, vals[val]))
return dupes
findCards = find_cards
findNotes = find_notes
findReplace = find_and_replace
# Search Strings
##########################################################################
@ -880,35 +820,6 @@ table.review-log {{ {revlog_style} }}
"Don't use this, it will likely go away in the future."
return self._backend.congrats_info().SerializeToString()
# legacy
def cardStats(self, card: Card) -> str:
return self.card_stats(card.id, include_revlog=False)
# Timeboxing
##########################################################################
# fixme: there doesn't seem to be a good reason why this code is in main.py
# instead of covered in reviewer, and the reps tracking is covered by both
# the scheduler and reviewer.py. in the future, we should probably move
# reps tracking to reviewer.py, and remove the startTimebox() calls from
# other locations like overview.py. We just need to make sure not to reset
# the count on things like edits, which we probably could do by checking
# the previous state in moveToState.
def startTimebox(self) -> None:
self._startTime = time.time()
self._startReps = self.sched.reps
def timeboxReached(self) -> Union[Literal[False], Tuple[Any, int]]:
"Return (elapsedTime, reps) if timebox reached, or False."
if not self.conf["timeLim"]:
# timeboxing disabled
return False
elapsed = time.time() - self._startTime
if elapsed > self.conf["timeLim"]:
return (self.conf["timeLim"], self.sched.reps - self._startReps)
return False
# Undo
##########################################################################
@ -1070,10 +981,10 @@ table.review-log {{ {revlog_style} }}
)
# update daily counts
n = card.queue
idx = card.queue
if card.queue in (QUEUE_TYPE_DAY_LEARN_RELEARN, QUEUE_TYPE_PREVIEW):
n = QUEUE_TYPE_LRN
type = ("new", "lrn", "rev")[n]
idx = QUEUE_TYPE_LRN
type = ("new", "lrn", "rev")[idx]
self.sched._updateStats(card, type, -1)
self.sched.reps -= 1
@ -1082,20 +993,10 @@ table.review-log {{ {revlog_style} }}
return entry
# legacy
clearUndo = clear_python_undo
markReview = save_card_review_undo_info
def undoName(self) -> Optional[str]:
"Undo menu item name, or None if undo unavailable."
status = self.undo_status()
return status.undo or None
# DB maintenance
##########################################################################
def fixIntegrity(self) -> Tuple[str, bool]:
def fix_integrity(self) -> Tuple[str, bool]:
"""Fix possible problems and rebuild caches.
Returns tuple of (error: str, ok: bool). 'ok' will be true if no
@ -1106,8 +1007,8 @@ table.review-log {{ {revlog_style} }}
problems = list(self._backend.check_database())
ok = not problems
problems.append(self.tr.database_check_rebuilt())
except DBError as e:
problems = [str(e.args[0])]
except DBError as err:
problems = [str(err.args[0])]
ok = False
finally:
try:
@ -1123,46 +1024,6 @@ table.review-log {{ {revlog_style} }}
self.db.execute("analyze")
self.db.begin()
# Logging
##########################################################################
def log(self, *args: Any, **kwargs: Any) -> None:
if not self._should_log:
return
def customRepr(x: Any) -> str:
if isinstance(x, str):
return x
return pprint.pformat(x)
path, num, fn, y = traceback.extract_stack(limit=2 + kwargs.get("stack", 0))[0]
buf = "[%s] %s:%s(): %s" % (
intTime(),
os.path.basename(path),
fn,
", ".join([customRepr(x) for x in args]),
)
self._logHnd.write(f"{buf}\n")
if devMode:
print(buf)
def _openLog(self) -> None:
if not self._should_log:
return
lpath = re.sub(r"\.anki2$", ".log", self.path)
if os.path.exists(lpath) and os.path.getsize(lpath) > 10 * 1024 * 1024:
lpath2 = f"{lpath}.old"
if os.path.exists(lpath2):
os.unlink(lpath2)
os.rename(lpath, lpath2)
self._logHnd = open(lpath, "a", encoding="utf8")
def _closeLog(self) -> None:
if not self._should_log:
return
self._logHnd.close()
self._logHnd = None
##########################################################################
def set_user_flag_for_cards(
@ -1210,6 +1071,104 @@ table.review-log {{ {revlog_style} }}
"Not intended for public consumption at this time."
return self._backend.render_markdown(markdown=text, sanitize=sanitize)
# Timeboxing
##########################################################################
# fixme: there doesn't seem to be a good reason why this code is in main.py
# instead of covered in reviewer, and the reps tracking is covered by both
# the scheduler and reviewer.py. in the future, we should probably move
# reps tracking to reviewer.py, and remove the startTimebox() calls from
# other locations like overview.py. We just need to make sure not to reset
# the count on things like edits, which we probably could do by checking
# the previous state in moveToState.
# pylint: disable=invalid-name
def startTimebox(self) -> None:
self._startTime = time.time()
self._startReps = self.sched.reps
def timeboxReached(self) -> Union[Literal[False], Tuple[Any, int]]:
"Return (elapsedTime, reps) if timebox reached, or False."
if not self.conf["timeLim"]:
# timeboxing disabled
return False
elapsed = time.time() - self._startTime
if elapsed > self.conf["timeLim"]:
return (self.conf["timeLim"], self.sched.reps - self._startReps)
return False
# Legacy
##########################################################################
@deprecated(info="no longer used")
def log(self, *args: Any, **kwargs: Any) -> None:
print(args, kwargs)
@deprecated(replaced_by=undo_status)
def undo_name(self) -> Optional[str]:
"Undo menu item name, or None if undo unavailable."
status = self.undo_status()
return status.undo or None
# @deprecated(replaced_by=new_note)
def newNote(self, forDeck: bool = True) -> Note:
"Return a new note with the current model."
return Note(self, self.models.current(forDeck))
# @deprecated(replaced_by=add_note)
def addNote(self, note: Note) -> int:
self.add_note(note, note.note_type()["did"])
return len(note.cards())
@deprecated(replaced_by=remove_notes)
def remNotes(self, ids: Sequence[NoteId]) -> None:
self.remove_notes(ids)
@deprecated(replaced_by=remove_notes)
def _remNotes(self, ids: List[NoteId]) -> None:
pass
@deprecated(replaced_by=card_stats)
def cardStats(self, card: Card) -> str:
return self.card_stats(card.id, include_revlog=False)
@deprecated(replaced_by=after_note_updates)
def updateFieldCache(self, nids: List[NoteId]) -> None:
self.after_note_updates(nids, mark_modified=False, generate_cards=False)
@deprecated(replaced_by=after_note_updates)
def genCards(self, nids: List[NoteId]) -> List[int]:
self.after_note_updates(nids, mark_modified=False, generate_cards=True)
# previously returned empty cards, no longer does
return []
@deprecated(info="no longer used")
def emptyCids(self) -> List[CardId]:
return []
@deprecated(info="handled by backend")
def _logRem(self, ids: List[Union[int, NoteId]], type: int) -> None:
self.db.executemany(
"insert into graves values (%d, ?, %d)" % (self.usn(), type),
([x] for x in ids),
)
@deprecated(info="no longer required")
def setMod(self) -> None:
pass
@deprecated(info="no longer required")
def flush(self) -> None:
pass
Collection.register_deprecated_aliases(
clearUndo=Collection.clear_python_undo,
markReview=Collection.save_card_review_undo_info,
findReplace=Collection.find_and_replace,
remCards=Collection.remove_cards_and_orphaned_notes,
)
# legacy name
_Collection = Collection

View File

@ -349,7 +349,7 @@ class DeckManager(DeprecatedNamesMixin):
def remove_config(self, id: DeckConfigId) -> None:
"Remove a configuration and update all decks using it."
self.col.modSchema(check=True)
self.col.mod_schema(check=True)
for deck in self.all():
# ignore cram decks
if "conf" not in deck:

View File

@ -197,7 +197,7 @@ class AnkiExporter(Exporter):
def exportInto(self, path: str) -> None:
# sched info+v2 scheduler not compatible w/ older clients
self._v2sched = self.col.schedVer() != 1 and self.includeSched
self._v2sched = self.col.sched_ver() != 1 and self.includeSched
# create a new collection at the target
try:
@ -246,7 +246,7 @@ class AnkiExporter(Exporter):
# need to reset card state
self.dst.sched.resetCards(cids)
# models - start with zero
self.dst.modSchema(check=False)
self.dst.mod_schema(check=False)
self.dst.models.remove_all_notetypes()
for m in self.src.models.all():
if int(m["id"]) in mids:
@ -298,7 +298,7 @@ class AnkiExporter(Exporter):
self.mediaFiles = list(media.keys())
self.dst.crt = self.src.crt
# todo: tags?
self.count = self.dst.cardCount()
self.count = self.dst.card_count()
self.postExport()
self.dst.close(downgrade=True)
@ -426,8 +426,8 @@ class AnkiCollectionPackageExporter(AnkiPackageExporter):
def doExport(self, z, path):
"Export collection. Caller must re-open afterwards."
# close our deck & write it into the zip file
self.count = self.col.cardCount()
v2 = self.col.schedVer() != 1
self.count = self.col.card_count()
v2 = self.col.sched_ver() != 1
mdir = self.col.media.dir()
self.col.close(downgrade=True)
if not v2:

View File

@ -53,11 +53,11 @@ class Anki2Importer(Importer):
self.dst = self.col
self.src = Collection(self.file)
if not self._importing_v2 and self.col.schedVer() != 1:
if not self._importing_v2 and self.col.sched_ver() != 1:
# any scheduling included?
if self.src.db.scalar("select 1 from cards where queue != 0 limit 1"):
self.source_needs_upgrade = True
elif self._importing_v2 and self.col.schedVer() == 1:
elif self._importing_v2 and self.col.sched_ver() == 1:
raise Exception("must upgrade to new scheduler to import this file")
def _import(self) -> None:
@ -186,7 +186,7 @@ class Anki2Importer(Importer):
self.dst.db.executemany(
"insert or replace into notes values (?,?,?,?,?,?,?,?,?,?,?)", update
)
self.dst.updateFieldCache(dirty)
self.dst.after_note_updates(dirty, mark_modified=False, generate_cards=False)
# determine if note is a duplicate, and adjust mid and/or guid as required
# returns true if note should be added

View File

@ -400,7 +400,7 @@ and notes.mid = ? and cards.ord = ?""",
cmap: Optional[Dict[int, Optional[int]]],
) -> None:
# - maps are ord->ord, and there should not be duplicate targets
self.col.modSchema(check=True)
self.col.mod_schema(check=True)
assert fmap
field_map = self._convert_legacy_map(fmap, len(newModel["flds"]))
if (

View File

@ -46,7 +46,6 @@ class Scheduler(V2):
self._haveQueues = False
def answerCard(self, card: Card, ease: int) -> None:
self.col.log()
assert 1 <= ease <= 4
self.col.save_card_review_undo_info(card)
if self._burySiblingsOnAnswer:

View File

@ -104,7 +104,6 @@ class Scheduler(SchedulerBaseWithLegacy):
self.reset()
card = self._getCard()
if card:
self.col.log(card)
if not self._burySiblingsOnAnswer:
self._burySiblings(card)
card.start_timer()
@ -452,7 +451,6 @@ limit ?"""
##########################################################################
def answerCard(self, card: Card, ease: int) -> None:
self.col.log()
assert 1 <= ease <= 4
assert 0 <= card.queue <= 4
self.col.save_card_review_undo_info(card)

View File

@ -665,7 +665,7 @@ select count(), avg(ivl), max(ivl) from cards where did in %s and queue = {QUEUE
[13, 3],
[14, 4],
]
if self.col.schedVer() != 1:
if self.col.sched_ver() != 1:
ticks.insert(3, [4, 4])
txt = self._title(
"Answer Buttons", "The number of times you have pressed each button."
@ -725,7 +725,7 @@ select count(), avg(ivl), max(ivl) from cards where did in %s and queue = {QUEUE
lim = "where " + " and ".join(lims)
else:
lim = ""
if self.col.schedVer() == 1:
if self.col.sched_ver() == 1:
ease4repl = "3"
else:
ease4repl = "ease"
@ -815,7 +815,7 @@ order by thetype, ease"""
lim = self._revlogLimit()
if lim:
lim = " and " + lim
if self.col.schedVer() == 1:
if self.col.sched_ver() == 1:
sd = datetime.datetime.fromtimestamp(self.col.crt)
rolloverHour = sd.hour
else:

View File

@ -16,8 +16,8 @@ def test_delete():
col.reset()
col.sched.answerCard(col.sched.getCard(), 2)
col.remove_cards_and_orphaned_notes([cid])
assert col.cardCount() == 0
assert col.noteCount() == 0
assert col.card_count() == 0
assert col.note_count() == 0
assert col.db.scalar("select count() from notes") == 0
assert col.db.scalar("select count() from cards") == 0
assert col.db.scalar("select count() from graves") == 2
@ -72,7 +72,7 @@ def test_gendeck():
note = col.new_note(cloze)
note["Text"] = "{{c1::one}}"
col.addNote(note)
assert col.cardCount() == 1
assert col.card_count() == 1
assert note.cards()[0].did == 1
# set the model to a new default col
newId = col.decks.id("new")

View File

@ -62,14 +62,14 @@ def test_noteAddDelete():
t["afmt"] = "{{Front}}"
mm.add_template(m, t)
mm.save(m)
assert col.cardCount() == 2
assert col.card_count() == 2
# creating new notes should use both cards
note = col.newNote()
note["Front"] = "three"
note["Back"] = "four"
n = col.addNote(note)
assert n == 2
assert col.cardCount() == 4
assert col.card_count() == 4
# check q/a generation
c0 = note.cards()[0]
assert "three" in c0.question()

View File

@ -57,9 +57,9 @@ def test_remove():
col.addNote(note)
c = note.cards()[0]
assert c.did == deck1
assert col.cardCount() == 1
assert col.card_count() == 1
col.decks.remove([deck1])
assert col.cardCount() == 0
assert col.card_count() == 0
# if we try to get it, we get the default
assert col.decks.name(c.did) == "[no deck]"

View File

@ -65,7 +65,7 @@ def test_export_anki():
assert conf["id"] != 1
# connect to new deck
col2 = aopen(newname)
assert col2.cardCount() == 2
assert col2.card_count() == 2
# as scheduling was reset, should also revert decks to default conf
did = col2.decks.id("test", create=False)
assert did
@ -82,7 +82,7 @@ def test_export_anki():
e.did = 1
e.exportInto(newname)
col2 = aopen(newname)
assert col2.cardCount() == 1
assert col2.card_count() == 1
def test_export_ankipkg():
@ -109,7 +109,6 @@ def test_export_anki_due():
note["Front"] = "foo"
col.addNote(note)
col.crt -= 86400 * 10
col.flush()
col.sched.reset()
c = col.sched.getCard()
col.sched.answerCard(c, 3)

View File

@ -14,7 +14,7 @@ class DummyCollection:
return None
def test_findCards():
def test_find_cards():
col = getEmptyCol()
note = col.newNote()
note["Front"] = "dog"
@ -49,84 +49,80 @@ def test_findCards():
col.save()
latestCardIds = [c.id for c in note.cards()]
# tag searches
assert len(col.findCards("tag:*")) == 5
assert len(col.findCards("tag:\\*")) == 1
assert len(col.findCards("tag:%")) == 1
assert len(col.findCards("tag:sheep_goat")) == 0
assert len(col.findCards('"tag:sheep goat"')) == 0
assert len(col.findCards('"tag:* *"')) == 0
assert len(col.findCards("tag:animal_1")) == 2
assert len(col.findCards("tag:animal\\_1")) == 1
assert not col.findCards("tag:donkey")
assert len(col.findCards("tag:sheep")) == 1
assert len(col.findCards("tag:sheep tag:goat")) == 1
assert len(col.findCards("tag:sheep tag:monkey")) == 0
assert len(col.findCards("tag:monkey")) == 1
assert len(col.findCards("tag:sheep -tag:monkey")) == 1
assert len(col.findCards("-tag:sheep")) == 4
assert len(col.find_cards("tag:*")) == 5
assert len(col.find_cards("tag:\\*")) == 1
assert len(col.find_cards("tag:%")) == 1
assert len(col.find_cards("tag:sheep_goat")) == 0
assert len(col.find_cards('"tag:sheep goat"')) == 0
assert len(col.find_cards('"tag:* *"')) == 0
assert len(col.find_cards("tag:animal_1")) == 2
assert len(col.find_cards("tag:animal\\_1")) == 1
assert not col.find_cards("tag:donkey")
assert len(col.find_cards("tag:sheep")) == 1
assert len(col.find_cards("tag:sheep tag:goat")) == 1
assert len(col.find_cards("tag:sheep tag:monkey")) == 0
assert len(col.find_cards("tag:monkey")) == 1
assert len(col.find_cards("tag:sheep -tag:monkey")) == 1
assert len(col.find_cards("-tag:sheep")) == 4
col.tags.bulk_add(col.db.list("select id from notes"), "foo bar")
assert len(col.findCards("tag:foo")) == len(col.findCards("tag:bar")) == 5
assert len(col.find_cards("tag:foo")) == len(col.find_cards("tag:bar")) == 5
col.tags.bulkRem(col.db.list("select id from notes"), "foo")
assert len(col.findCards("tag:foo")) == 0
assert len(col.findCards("tag:bar")) == 5
assert len(col.find_cards("tag:foo")) == 0
assert len(col.find_cards("tag:bar")) == 5
# text searches
assert len(col.findCards("cat")) == 2
assert len(col.findCards("cat -dog")) == 1
assert len(col.findCards("cat -dog")) == 1
assert len(col.findCards("are goats")) == 1
assert len(col.findCards('"are goats"')) == 0
assert len(col.findCards('"goats are"')) == 1
assert len(col.find_cards("cat")) == 2
assert len(col.find_cards("cat -dog")) == 1
assert len(col.find_cards("cat -dog")) == 1
assert len(col.find_cards("are goats")) == 1
assert len(col.find_cards('"are goats"')) == 0
assert len(col.find_cards('"goats are"')) == 1
# card states
c = note.cards()[0]
c.queue = c.type = CARD_TYPE_REV
assert col.findCards("is:review") == []
assert col.find_cards("is:review") == []
c.flush()
assert col.findCards("is:review") == [c.id]
assert col.findCards("is:due") == []
assert col.find_cards("is:review") == [c.id]
assert col.find_cards("is:due") == []
c.due = 0
c.queue = QUEUE_TYPE_REV
c.flush()
assert col.findCards("is:due") == [c.id]
assert len(col.findCards("-is:due")) == 4
assert col.find_cards("is:due") == [c.id]
assert len(col.find_cards("-is:due")) == 4
c.queue = QUEUE_TYPE_SUSPENDED
# ensure this card gets a later mod time
c.flush()
col.db.execute("update cards set mod = mod + 1 where id = ?", c.id)
assert col.findCards("is:suspended") == [c.id]
assert col.find_cards("is:suspended") == [c.id]
# nids
assert col.findCards("nid:54321") == []
assert len(col.findCards(f"nid:{note.id}")) == 2
assert len(col.findCards(f"nid:{n1id},{n2id}")) == 2
assert col.find_cards("nid:54321") == []
assert len(col.find_cards(f"nid:{note.id}")) == 2
assert len(col.find_cards(f"nid:{n1id},{n2id}")) == 2
# templates
assert len(col.findCards("card:foo")) == 0
assert len(col.findCards('"card:card 1"')) == 4
assert len(col.findCards("card:reverse")) == 1
assert len(col.findCards("card:1")) == 4
assert len(col.findCards("card:2")) == 1
assert len(col.find_cards("card:foo")) == 0
assert len(col.find_cards('"card:card 1"')) == 4
assert len(col.find_cards("card:reverse")) == 1
assert len(col.find_cards("card:1")) == 4
assert len(col.find_cards("card:2")) == 1
# fields
assert len(col.findCards("front:dog")) == 1
assert len(col.findCards("-front:dog")) == 4
assert len(col.findCards("front:sheep")) == 0
assert len(col.findCards("back:sheep")) == 2
assert len(col.findCards("-back:sheep")) == 3
assert len(col.findCards("front:do")) == 0
assert len(col.findCards("front:*")) == 5
assert len(col.find_cards("front:dog")) == 1
assert len(col.find_cards("-front:dog")) == 4
assert len(col.find_cards("front:sheep")) == 0
assert len(col.find_cards("back:sheep")) == 2
assert len(col.find_cards("-back:sheep")) == 3
assert len(col.find_cards("front:do")) == 0
assert len(col.find_cards("front:*")) == 5
# ordering
col.conf["sortType"] = "noteCrt"
col.flush()
assert col.findCards("front:*", order=True)[-1] in latestCardIds
assert col.findCards("", order=True)[-1] in latestCardIds
assert col.find_cards("front:*", order=True)[-1] in latestCardIds
assert col.find_cards("", order=True)[-1] in latestCardIds
col.conf["sortType"] = "noteFld"
col.flush()
assert col.findCards("", order=True)[0] == catCard.id
assert col.findCards("", order=True)[-1] in latestCardIds
assert col.find_cards("", order=True)[0] == catCard.id
assert col.find_cards("", order=True)[-1] in latestCardIds
col.conf["sortType"] = "cardMod"
col.flush()
assert col.findCards("", order=True)[-1] in latestCardIds
assert col.findCards("", order=True)[0] == firstCardId
assert col.find_cards("", order=True)[-1] in latestCardIds
assert col.find_cards("", order=True)[0] == firstCardId
col.set_config_bool(Config.Bool.BROWSER_SORT_BACKWARDS, True)
col.flush()
assert col.findCards("", order=True)[0] in latestCardIds
assert col.find_cards("", order=True)[0] in latestCardIds
assert (
col.find_cards("", order=col.get_browser_column("cardDue"), reverse=False)[0]
== firstCardId
@ -136,42 +132,42 @@ def test_findCards():
!= firstCardId
)
# model
assert len(col.findCards("note:basic")) == 3
assert len(col.findCards("-note:basic")) == 2
assert len(col.findCards("-note:foo")) == 5
assert len(col.find_cards("note:basic")) == 3
assert len(col.find_cards("-note:basic")) == 2
assert len(col.find_cards("-note:foo")) == 5
# col
assert len(col.findCards("deck:default")) == 5
assert len(col.findCards("-deck:default")) == 0
assert len(col.findCards("-deck:foo")) == 5
assert len(col.findCards("deck:def*")) == 5
assert len(col.findCards("deck:*EFAULT")) == 5
assert len(col.findCards("deck:*cefault")) == 0
assert len(col.find_cards("deck:default")) == 5
assert len(col.find_cards("-deck:default")) == 0
assert len(col.find_cards("-deck:foo")) == 5
assert len(col.find_cards("deck:def*")) == 5
assert len(col.find_cards("deck:*EFAULT")) == 5
assert len(col.find_cards("deck:*cefault")) == 0
# full search
note = col.newNote()
note["Front"] = "hello<b>world</b>"
note["Back"] = "abc"
col.addNote(note)
# as it's the sort field, it matches
assert len(col.findCards("helloworld")) == 2
# assert len(col.findCards("helloworld", full=True)) == 2
assert len(col.find_cards("helloworld")) == 2
# assert len(col.find_cards("helloworld", full=True)) == 2
# if we put it on the back, it won't
(note["Front"], note["Back"]) = (note["Back"], note["Front"])
note.flush()
assert len(col.findCards("helloworld")) == 0
# assert len(col.findCards("helloworld", full=True)) == 2
# assert len(col.findCards("back:helloworld", full=True)) == 2
assert len(col.find_cards("helloworld")) == 0
# assert len(col.find_cards("helloworld", full=True)) == 2
# assert len(col.find_cards("back:helloworld", full=True)) == 2
# searching for an invalid special tag should not error
with pytest.raises(Exception):
len(col.findCards("is:invalid"))
len(col.find_cards("is:invalid"))
# should be able to limit to parent col, no children
id = col.db.scalar("select id from cards limit 1")
col.db.execute(
"update cards set did = ? where id = ?", col.decks.id("Default::Child"), id
)
col.save()
assert len(col.findCards("deck:default")) == 7
assert len(col.findCards("deck:default::child")) == 1
assert len(col.findCards("deck:default -deck:default::*")) == 6
assert len(col.find_cards("deck:default")) == 7
assert len(col.find_cards("deck:default::child")) == 1
assert len(col.find_cards("deck:default -deck:default::*")) == 6
# properties
id = col.db.scalar("select id from cards limit 1")
col.db.execute(
@ -179,61 +175,61 @@ def test_findCards():
"where id = ?",
id,
)
assert len(col.findCards("prop:ivl>5")) == 1
assert len(col.findCards("prop:ivl<5")) > 1
assert len(col.findCards("prop:ivl>=5")) == 1
assert len(col.findCards("prop:ivl=9")) == 0
assert len(col.findCards("prop:ivl=10")) == 1
assert len(col.findCards("prop:ivl!=10")) > 1
assert len(col.findCards("prop:due>0")) == 1
assert len(col.find_cards("prop:ivl>5")) == 1
assert len(col.find_cards("prop:ivl<5")) > 1
assert len(col.find_cards("prop:ivl>=5")) == 1
assert len(col.find_cards("prop:ivl=9")) == 0
assert len(col.find_cards("prop:ivl=10")) == 1
assert len(col.find_cards("prop:ivl!=10")) > 1
assert len(col.find_cards("prop:due>0")) == 1
# due dates should work
assert len(col.findCards("prop:due=29")) == 0
assert len(col.findCards("prop:due=30")) == 1
assert len(col.find_cards("prop:due=29")) == 0
assert len(col.find_cards("prop:due=30")) == 1
# ease factors
assert len(col.findCards("prop:ease=2.3")) == 0
assert len(col.findCards("prop:ease=2.2")) == 1
assert len(col.findCards("prop:ease>2")) == 1
assert len(col.findCards("-prop:ease>2")) > 1
assert len(col.find_cards("prop:ease=2.3")) == 0
assert len(col.find_cards("prop:ease=2.2")) == 1
assert len(col.find_cards("prop:ease>2")) == 1
assert len(col.find_cards("-prop:ease>2")) > 1
# recently failed
if not isNearCutoff():
# rated
assert len(col.findCards("rated:1:1")) == 0
assert len(col.findCards("rated:1:2")) == 0
assert len(col.find_cards("rated:1:1")) == 0
assert len(col.find_cards("rated:1:2")) == 0
c = col.sched.getCard()
col.sched.answerCard(c, 2)
assert len(col.findCards("rated:1:1")) == 0
assert len(col.findCards("rated:1:2")) == 1
assert len(col.find_cards("rated:1:1")) == 0
assert len(col.find_cards("rated:1:2")) == 1
c = col.sched.getCard()
col.sched.answerCard(c, 1)
assert len(col.findCards("rated:1:1")) == 1
assert len(col.findCards("rated:1:2")) == 1
assert len(col.findCards("rated:1")) == 2
assert len(col.findCards("rated:2:2")) == 1
assert len(col.findCards("rated:0")) == len(col.findCards("rated:1"))
assert len(col.find_cards("rated:1:1")) == 1
assert len(col.find_cards("rated:1:2")) == 1
assert len(col.find_cards("rated:1")) == 2
assert len(col.find_cards("rated:2:2")) == 1
assert len(col.find_cards("rated:0")) == len(col.find_cards("rated:1"))
# added
col.db.execute("update cards set id = id - 86400*1000 where id = ?", id)
assert len(col.findCards("added:1")) == col.cardCount() - 1
assert len(col.findCards("added:2")) == col.cardCount()
assert len(col.findCards("added:0")) == len(col.findCards("added:1"))
assert len(col.find_cards("added:1")) == col.card_count() - 1
assert len(col.find_cards("added:2")) == col.card_count()
assert len(col.find_cards("added:0")) == len(col.find_cards("added:1"))
else:
print("some find tests disabled near cutoff")
# empty field
assert len(col.findCards("front:")) == 0
assert len(col.find_cards("front:")) == 0
note = col.newNote()
note["Front"] = ""
note["Back"] = "abc2"
assert col.addNote(note) == 1
assert len(col.findCards("front:")) == 1
assert len(col.find_cards("front:")) == 1
# OR searches and nesting
assert len(col.findCards("tag:monkey or tag:sheep")) == 2
assert len(col.findCards("(tag:monkey OR tag:sheep)")) == 2
assert len(col.findCards("-(tag:monkey OR tag:sheep)")) == 6
assert len(col.findCards("tag:monkey or (tag:sheep sheep)")) == 2
assert len(col.findCards("tag:monkey or (tag:sheep octopus)")) == 1
assert len(col.find_cards("tag:monkey or tag:sheep")) == 2
assert len(col.find_cards("(tag:monkey OR tag:sheep)")) == 2
assert len(col.find_cards("-(tag:monkey OR tag:sheep)")) == 6
assert len(col.find_cards("tag:monkey or (tag:sheep sheep)")) == 2
assert len(col.find_cards("tag:monkey or (tag:sheep octopus)")) == 1
# flag
with pytest.raises(Exception):
col.findCards("flag:12")
col.find_cards("flag:12")
def test_findReplace():
@ -304,15 +300,15 @@ def test_findDupes():
note4["Front"] = "quuux"
note4["Back"] = "nope"
col.addNote(note4)
r = col.findDupes("Back")
r = col.find_dupes("Back")
assert r[0][0] == "bar"
assert len(r[0][1]) == 3
# valid search
r = col.findDupes("Back", "bar")
r = col.find_dupes("Back", "bar")
assert r[0][0] == "bar"
assert len(r[0][1]) == 3
# excludes everything
r = col.findDupes("Back", "invalid")
r = col.find_dupes("Back", "invalid")
assert not r
# front isn't dupe
assert col.findDupes("Front") == []
assert col.find_dupes("Front") == []

View File

@ -17,16 +17,16 @@ def test_flags():
c.flush()
# no flags to start with
assert c.user_flag() == 0
assert len(col.findCards("flag:0")) == 1
assert len(col.findCards("flag:1")) == 0
assert len(col.find_cards("flag:0")) == 1
assert len(col.find_cards("flag:1")) == 0
# set flag 2
col.set_user_flag_for_cards(2, [c.id])
c.load()
assert c.user_flag() == 2
assert c.flags & origBits == origBits
assert len(col.findCards("flag:0")) == 0
assert len(col.findCards("flag:2")) == 1
assert len(col.findCards("flag:3")) == 0
assert len(col.find_cards("flag:0")) == 0
assert len(col.find_cards("flag:2")) == 1
assert len(col.find_cards("flag:3")) == 0
# change to 3
col.set_user_flag_for_cards(3, [c.id])
c.load()

View File

@ -115,9 +115,9 @@ def test_anki2_diffmodel_templates():
imp.dupeOnSchemaChange = True
imp.run()
# collection should contain the note we imported
assert dst.noteCount() == 1
assert dst.note_count() == 1
# the front template should contain the text added in the 2nd package
tcid = dst.findCards("")[0] # only 1 note in collection
tcid = dst.find_cards("")[0] # only 1 note in collection
tnote = dst.getCard(tcid).note()
assert "Changed Front Template" in tnote.cards()[0].template()["qfmt"]
@ -138,7 +138,7 @@ def test_anki2_updates():
assert imp.added == 0
assert imp.updated == 0
# importing a newer note should update
assert dst.noteCount() == 1
assert dst.note_count() == 1
assert dst.db.scalar("select flds from notes").startswith("hello")
col = getUpgradeDeckPath("update2.apkg")
imp = AnkiPackageImporter(dst, col)
@ -146,7 +146,7 @@ def test_anki2_updates():
assert imp.dupes == 0
assert imp.added == 0
assert imp.updated == 1
assert dst.noteCount() == 1
assert dst.note_count() == 1
assert dst.db.scalar("select flds from notes").startswith("goodbye")
@ -176,12 +176,12 @@ def test_csv():
i.run()
assert i.total == 0
# and if dupes mode, will reimport everything
assert col.cardCount() == 5
assert col.card_count() == 5
i.importMode = 2
i.run()
# includes repeated field
assert i.total == 6
assert col.cardCount() == 11
assert col.card_count() == 11
col.close()
@ -330,7 +330,7 @@ def test_mnemo():
file = str(os.path.join(testDir, "support", "mnemo.db"))
i = MnemosyneImporter(col, file)
i.run()
assert col.cardCount() == 7
assert col.card_count() == 7
assert "a_longer_tag" in col.tags.all()
assert col.db.scalar(f"select count() from cards where type = {CARD_TYPE_NEW}") == 1
col.close()

View File

@ -16,9 +16,9 @@ def test_modelDelete():
note["Front"] = "1"
note["Back"] = "2"
col.addNote(note)
assert col.cardCount() == 1
assert col.card_count() == 1
col.models.remove(col.models.current()["id"])
assert col.cardCount() == 0
assert col.card_count() == 0
def test_modelCopy():
@ -95,7 +95,7 @@ def test_templates():
note["Front"] = "1"
note["Back"] = "2"
col.addNote(note)
assert col.cardCount() == 2
assert col.card_count() == 2
(c, c2) = note.cards()
# first card should have first ord
assert c.ord == 0
@ -110,7 +110,7 @@ def test_templates():
# removing a template should delete its cards
col.models.remove_template(m, m["tmpls"][0])
col.models.update(m)
assert col.cardCount() == 1
assert col.card_count() == 1
# and should have updated the other cards' ordinals
c = note.cards()[0]
assert c.ord == 0
@ -146,7 +146,7 @@ def test_cloze_ordinals():
note = col.newNote()
note["Text"] = "{{c1::firstQ::firstA}}{{c2::secondQ::secondA}}"
col.addNote(note)
assert col.cardCount() == 2
assert col.card_count() == 2
(c, c2) = note.cards()
# first card should have first ord
assert c.ord == 0
@ -202,10 +202,10 @@ def test_cloze():
note.cards()[0].answer()
)
# if we add another cloze, a card should be generated
cnt = col.cardCount()
cnt = col.card_count()
note["Text"] = "{{c2::hello}} {{c1::foo}}"
note.flush()
assert col.cardCount() == cnt + 1
assert col.card_count() == cnt + 1
# 0 or negative indices are not supported
note["Text"] += "{{c0::zero}} {{c-1:foo}}"
note.flush()

View File

@ -15,7 +15,7 @@ def getEmptyCol() -> Collection:
col = getEmptyColOrig()
# only safe in test environment
col.set_config("schedVer", 1)
col._loadScheduler()
col._load_scheduler()
return col
@ -820,7 +820,7 @@ def test_ordcycle():
note["Front"] = "1"
note["Back"] = "1"
col.addNote(note)
assert col.cardCount() == 3
assert col.card_count() == 3
col.reset()
# ordinals should arrive in order
assert col.sched.getCard().ord == 0

View File

@ -894,7 +894,7 @@ def test_ordcycle():
note["Front"] = "1"
note["Back"] = "1"
col.addNote(note)
assert col.cardCount() == 3
assert col.card_count() == 3
conf = col.decks.get_config(1)
conf["new"]["bury"] = False

View File

@ -14,12 +14,12 @@ def test_stats():
col.addNote(note)
c = note.cards()[0]
# card stats
assert col.cardStats(c)
assert col.card_stats(c.id, include_revlog=True)
col.reset()
c = col.sched.getCard()
col.sched.answerCard(c, 3)
col.sched.answerCard(c, 2)
assert col.cardStats(c)
assert col.card_stats(c.id, include_revlog=True)
def test_graphs_empty():

View File

@ -16,33 +16,33 @@ def getEmptyCol():
def test_op():
col = getEmptyCol()
# should have no undo by default
assert not col.undoName()
assert not col.undo_status().undo
# let's adjust a study option
col.save("studyopts")
col.conf["abc"] = 5
# it should be listed as undoable
assert col.undoName() == "studyopts"
assert col.undo_status().undo == "studyopts"
# with about 5 minutes until it's clobbered
assert time.time() - col._last_checkpoint_at < 1
# undoing should restore the old value
col.undo_legacy()
assert not col.undoName()
assert not col.undo_status().undo
assert "abc" not in col.conf
# an (auto)save will clear the undo
col.save("foo")
assert col.undoName() == "foo"
assert col.undo_status().undo == "foo"
col.save()
assert not col.undoName()
assert not col.undo_status().undo
# and a review will, too
col.save("add")
note = col.newNote()
note["Front"] = "one"
col.addNote(note)
col.reset()
assert "add" in col.undoName().lower()
assert "add" in col.undo_status().undo.lower()
c = col.sched.getCard()
col.sched.answerCard(c, 2)
assert col.undoName() == "Review"
assert col.undo_status().undo == "Review"
def test_review():
@ -64,14 +64,14 @@ def test_review():
assert col.sched.counts() == (1, 1, 0)
assert c.queue == QUEUE_TYPE_LRN
# undo
assert col.undoName()
assert col.undo_status().undo
col.undo_legacy()
col.reset()
assert col.sched.counts() == (2, 0, 0)
c.load()
assert c.queue == QUEUE_TYPE_NEW
assert c.left % 1000 != 1
assert not col.undoName()
assert not col.undo_status().undo
# we should be able to undo multiple answers too
c = col.sched.getCard()
col.sched.answerCard(c, 3)
@ -87,8 +87,8 @@ def test_review():
# performing a normal op will clear the review queue
c = col.sched.getCard()
col.sched.answerCard(c, 3)
assert col.undoName() == "Review"
assert col.undo_status().undo == "Review"
col.save("foo")
assert col.undoName() == "foo"
assert col.undo_status().undo == "foo"
col.undo_legacy()
assert not col.undoName()
assert not col.undo_status().undo

View File

@ -521,7 +521,7 @@ class Browser(QMainWindow):
def createFilteredDeck(self) -> None:
search = self.current_search()
if self.mw.col.schedVer() != 1 and KeyboardModifiersPressed().alt:
if self.mw.col.sched_ver() != 1 and KeyboardModifiersPressed().alt:
aqt.dialogs.open("FilteredDeckConfigDialog", self.mw, search_2=search)
else:
aqt.dialogs.open("FilteredDeckConfigDialog", self.mw, search=search)

View File

@ -65,7 +65,7 @@ class FindDuplicatesDialog(QDialog):
field = fields[form.fields.currentIndex()]
QueryOp(
parent=self.browser,
op=lambda col: col.findDupes(field, search_text),
op=lambda col: col.find_dupes(field, search_text),
success=self.show_duplicates_report,
).run_in_background()

View File

@ -53,4 +53,4 @@ def check_db(mw: aqt.AnkiQt) -> None:
n += 1
continue
mw.taskman.with_progress(mw.col.fixIntegrity, on_future_done)
mw.taskman.with_progress(mw.col.fix_integrity, on_future_done)

View File

@ -349,7 +349,7 @@ class DeckBrowser:
######################################################################
def _v1_upgrade_message(self) -> str:
if self.mw.col.schedVer() == 2:
if self.mw.col.sched_ver() == 2:
return ""
return f"""
@ -371,7 +371,7 @@ class DeckBrowser:
"""
def _confirm_upgrade(self) -> None:
self.mw.col.modSchema(check=True)
self.mw.col.mod_schema(check=True)
self.mw.col.upgrade_to_v2_scheduler()
showInfo(tr.scheduling_update_done())

View File

@ -144,7 +144,7 @@ class DeckConf(QDialog):
showInfo(tr.scheduling_the_default_configuration_cant_be_removed(), self)
else:
gui_hooks.deck_conf_will_remove_config(self, self.deck, self.conf)
self.mw.col.modSchema(check=True)
self.mw.col.mod_schema(check=True)
self.mw.col.decks.remove_config(self.conf["id"])
self.conf = None
self.deck["conf"] = 1
@ -220,7 +220,7 @@ class DeckConf(QDialog):
f.revplim.setText(self.parentLimText("rev"))
f.buryRev.setChecked(c.get("bury", True))
f.hardFactor.setValue(int(c.get("hardFactor", 1.2) * 100))
if self.mw.col.schedVer() == 1:
if self.mw.col.sched_ver() == 1:
f.hardFactor.setVisible(False)
f.hardFactorLabel.setVisible(False)
# lapse

View File

@ -106,7 +106,7 @@ def display_options_for_deck_id(deck_id: DeckId) -> None:
def display_options_for_deck(deck: DeckDict) -> None:
if not deck["dyn"]:
if KeyboardModifiersPressed().shift or aqt.mw.col.schedVer() == 1:
if KeyboardModifiersPressed().shift or aqt.mw.col.sched_ver() == 1:
deck_legacy = aqt.mw.col.decks.get(DeckId(deck["id"]))
aqt.deckconf.DeckConf(aqt.mw, deck_legacy)
else:

View File

@ -95,7 +95,7 @@ class FilteredDeckConfigDialog(QDialog):
self.form.buttonBox.helpRequested, lambda: openHelp(HelpPage.FILTERED_DECK)
)
if self.col.schedVer() == 1:
if self.col.sched_ver() == 1:
self.form.secondFilter.setVisible(False)
restoreGeom(self, self.GEOMETRY_KEY)
@ -127,7 +127,7 @@ class FilteredDeckConfigDialog(QDialog):
form.order.setCurrentIndex(term1.order)
form.limit.setValue(term1.limit)
if self.col.schedVer() == 1:
if self.col.sched_ver() == 1:
if config.delays:
form.steps.setText(self.listToUser(list(config.delays)))
form.stepsOn.setChecked(True)
@ -227,7 +227,7 @@ class FilteredDeckConfigDialog(QDialog):
"""Return a search node that matches learning cards if the old scheduler is enabled.
If it's a rebuild, exclude cards from this filtered deck as those will be reset.
"""
if self.col.schedVer() == 1:
if self.col.sched_ver() == 1:
if self.deck.id:
return (
self.col.group_searches(
@ -252,7 +252,7 @@ class FilteredDeckConfigDialog(QDialog):
def _onReschedToggled(self, _state: int) -> None:
self.form.previewDelayWidget.setVisible(
not self.form.resched.isChecked() and self.col.schedVer() > 1
not self.form.resched.isChecked() and self.col.sched_ver() > 1
)
def _update_deck(self) -> bool:
@ -266,7 +266,7 @@ class FilteredDeckConfigDialog(QDialog):
config.reschedule = form.resched.isChecked()
del config.delays[:]
if self.col.schedVer() == 1 and form.stepsOn.isChecked():
if self.col.sched_ver() == 1 and form.stepsOn.isChecked():
if (delays := self.userToList(form.steps)) is None:
return False
config.delays.extend(delays)

View File

@ -499,7 +499,7 @@ def _replaceWithApkg(mw: aqt.AnkiQt, filename: str, backup: bool) -> None:
if not mw.loadCollection():
return
if backup:
mw.col.modSchema(check=False)
mw.col.mod_schema(check=False)
tooltip(tr.importing_importing_complete())

View File

@ -527,7 +527,7 @@ class AnkiQt(QMainWindow):
def _loadCollection(self) -> None:
cpath = self.pm.collectionPath()
self.col = Collection(cpath, backend=self.backend, log=True)
self.col = Collection(cpath, backend=self.backend)
self.setEnabled(True)
def reopen(self) -> None:
@ -1358,7 +1358,7 @@ title="%s" %s>%s</button>""" % (
def confirm_schema_modification(self) -> bool:
"""If schema unmodified, ask user to confirm change.
True if confirmed or already modified."""
if self.col.schemaChanged():
if self.col.schema_changed():
return True
return askUser(tr.qt_misc_the_requested_change_will_require_a())

View File

@ -143,7 +143,7 @@ class Overview:
def on_unbury(self) -> None:
mode = UnburyDeck.Mode.ALL
if self.mw.col.schedVer() != 1:
if self.mw.col.sched_ver() != 1:
info = self.mw.col.sched.congratulations_info()
if info.have_sched_buried and info.have_user_buried:
opts = [

View File

@ -203,7 +203,7 @@ for you than the default driver, please let us know on the Anki forums."""
self.form.autoSyncMedia.isChecked() and 15 or 0
)
if self.form.fullSync.isChecked():
self.mw.col.modSchema(check=False)
self.mw.col.mod_schema(check=False)
# Profile: backup
######################################################################

View File

@ -891,7 +891,7 @@ def supportText() -> str:
def schedVer() -> str:
try:
return str(mw.col.schedVer())
return str(mw.col.sched_ver())
except:
return "?"