Strip out v1/v2 code

This commit is contained in:
Damien Elmes 2023-09-24 14:19:25 +10:00
parent 7f56836295
commit 558c75493f
16 changed files with 85 additions and 1595 deletions

View file

@ -75,8 +75,7 @@ from anki.lang import FormatTimeSpan
from anki.media import MediaManager, media_paths_from_col_path
from anki.models import ModelManager, NotetypeDict, NotetypeId
from anki.notes import Note, NoteId
from anki.scheduler.v1 import Scheduler as V1Scheduler
from anki.scheduler.v2 import Scheduler as V2Scheduler
from anki.scheduler.dummy import DummyScheduler
from anki.scheduler.v3 import Scheduler as V3Scheduler
from anki.sync import SyncAuth, SyncOutput, SyncStatus
from anki.tags import TagManager
@ -135,7 +134,7 @@ class AddNoteRequest:
class Collection(DeprecatedNamesMixin):
sched: V1Scheduler | V2Scheduler | V3Scheduler
sched: V3Scheduler | DummyScheduler
@staticmethod
def initialize_backend_logging(path: str | None = None) -> None:
@ -213,12 +212,17 @@ class Collection(DeprecatedNamesMixin):
def _load_scheduler(self) -> None:
ver = self.sched_ver()
if ver == 1:
self.sched = V1Scheduler(self)
self.sched = DummyScheduler(self)
elif ver == 2:
if self.v3_scheduler():
self.sched = V3Scheduler(self)
# enable new timezone if not already enabled
if self.conf.get("creationOffset") is None:
prefs = self._backend.get_preferences()
prefs.scheduling.new_timezone = True
self._backend.set_preferences(prefs)
else:
self.sched = V2Scheduler(self)
self.sched = DummyScheduler(self)
def upgrade_to_v2_scheduler(self) -> None:
self._backend.upgrade_scheduler()

View file

@ -118,17 +118,6 @@ def new_card_order_labels(col: anki.collection.Collection | None) -> dict[int, A
}
def new_card_scheduling_labels(
col: anki.collection.Collection | None,
) -> dict[int, Any]:
tr = _tr(col)
return {
0: tr.scheduling_mix_new_cards_and_reviews(),
1: tr.scheduling_show_new_cards_after_reviews(),
2: tr.scheduling_show_new_cards_before_reviews(),
}
_deprecated_names = DeprecatedNamesMixinForModule(globals())

View file

@ -3,8 +3,6 @@
from __future__ import annotations
import sys
import anki.scheduler.base as _base
UnburyDeck = _base.UnburyDeck
@ -12,12 +10,3 @@ CongratsInfo = _base.CongratsInfo
BuryOrSuspend = _base.BuryOrSuspend
FilteredDeckForUpdate = _base.FilteredDeckForUpdate
CustomStudyRequest = _base.CustomStudyRequest
# add aliases to the legacy pathnames
import anki.scheduler.v1
import anki.scheduler.v2
sys.modules["anki.sched"] = sys.modules["anki.scheduler.v1"]
sys.modules["anki.schedv2"] = sys.modules["anki.scheduler.v2"]
anki.sched = sys.modules["anki.scheduler.v1"] # type: ignore
anki.schedv2 = sys.modules["anki.scheduler.v2"] # type: ignore

View file

@ -7,6 +7,7 @@ import anki
import anki.collection
from anki import decks_pb2, scheduler_pb2
from anki._legacy import DeprecatedNamesMixin
from anki.cards import Card
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId
from anki.config import Config
@ -25,7 +26,14 @@ from typing import Sequence
from anki import config_pb2
from anki.cards import CardId
from anki.consts import CARD_TYPE_NEW, NEW_CARDS_RANDOM, QUEUE_TYPE_NEW
from anki.consts import (
CARD_TYPE_NEW,
NEW_CARDS_RANDOM,
QUEUE_TYPE_DAY_LEARN_RELEARN,
QUEUE_TYPE_LRN,
QUEUE_TYPE_NEW,
QUEUE_TYPE_PREVIEW,
)
from anki.decks import DeckConfigDict, DeckId, DeckTreeNode
from anki.notes import NoteId
from anki.utils import ids2str, int_time
@ -49,6 +57,11 @@ class SchedulerBase(DeprecatedNamesMixin):
def day_cutoff(self) -> int:
return self._timing_today().next_day_at
def countIdx(self, card: Card) -> int:
if card.queue in (QUEUE_TYPE_DAY_LEARN_RELEARN, QUEUE_TYPE_PREVIEW):
return QUEUE_TYPE_LRN
return card.queue
# Deck list
##########################################################################

View file

@ -0,0 +1,33 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
# pylint: disable=invalid-name
from __future__ import annotations
from anki.cards import Card
from anki.decks import DeckId
from anki.scheduler.legacy import SchedulerBaseWithLegacy
class DummyScheduler(SchedulerBaseWithLegacy):
reps = 0
def reset(self) -> None:
pass
def getCard(self) -> Card | None:
raise Exception("v1 scheduler no longer supported")
def answerCard(self, card: Card, ease: int) -> None:
raise Exception("v1 scheduler no longer supported")
def _is_finished(self) -> bool:
return False
@property
def active_decks(self) -> list[DeckId]:
return []
def counts(self) -> list[int]:
return [0, 0, 0]

View file

@ -3,6 +3,8 @@
# pylint: disable=invalid-name
from __future__ import annotations
from typing import Optional
from anki._legacy import deprecated
@ -127,6 +129,9 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
self.today,
)
def answerButtons(self, card: Card) -> int:
return 4
# legacy in v3 but used by unit tests; redefined in v2/v1
def _cardConf(self, card: Card) -> DeckConfigDict:

View file

@ -1,85 +0,0 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
# pylint: disable=invalid-name
from __future__ import annotations
import anki
import anki.collection
from anki.cards import Card
from anki.consts import *
from anki.decks import DeckId
from .v2 import QueueConfig
from .v2 import Scheduler as V2
class Scheduler(V2):
version = 1
name = "std"
haveCustomStudy = True
_spreadRev = True
_burySiblingsOnAnswer = True
def __init__( # pylint: disable=super-init-not-called
self, col: anki.collection.Collection
) -> None:
super().__init__(col)
self.queueLimit = 0
self.reportLimit = 0
self.dynReportLimit = 0
self.reps = 0
self.lrnCount = 0
self.revCount = 0
self.newCount = 0
self._haveQueues = False
def reset(self) -> None:
pass
def getCard(self) -> Card | None:
raise Exception("v1 scheduler no longer supported")
def answerCard(self, card: Card, ease: int) -> None:
raise Exception("v1 scheduler no longer supported")
def _is_finished(self) -> bool:
return False
# stubs of v1-specific routines that add-ons may be overriding
def _graduatingIvl(
self, card: Card, conf: QueueConfig, early: bool, adj: bool = True
) -> int:
return 0
def removeLrn(self, ids: list[int] | None = None) -> None:
pass
def _lrnForDeck(self, did: DeckId) -> int:
return 0
def _deckRevLimit(self, did: DeckId) -> int:
return 0
def _nextLapseIvl(self, card: Card, conf: QueueConfig) -> int:
return 0
def _rescheduleRev(self, card: Card, ease: int) -> None: # type: ignore[override]
pass
def _nextRevIvl(self, card: Card, ease: int) -> int: # type: ignore[override]
return 0
def _constrainedIvl(self, ivl: float, conf: QueueConfig, prev: int) -> int: # type: ignore[override]
return 0
def _adjRevIvl(self, card: Card, idealIvl: int) -> int:
return 0
def _dynIvlBoost(self, card: Card) -> int:
return 0
def _resched(self, card: Card) -> bool:
return False

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,6 @@ from __future__ import annotations
from typing import Literal, Optional, Sequence
from anki import frontend_pb2, scheduler_pb2
from anki._legacy import deprecated
from anki.cards import Card
from anki.collection import OpChanges
from anki.consts import *
@ -140,14 +139,6 @@ class Scheduler(SchedulerBaseWithLegacy):
def reviewCount(self) -> int:
return self.counts()[2]
def countIdx(self, card: Card) -> int:
if card.queue in (QUEUE_TYPE_DAY_LEARN_RELEARN, QUEUE_TYPE_PREVIEW):
return QUEUE_TYPE_LRN
return card.queue
def answerButtons(self, card: Card) -> int:
return 4
def nextIvlStr(self, card: Card, ease: int, short: bool = False) -> str:
"Return the next interval for CARD as a string."
states = self.col._backend.get_scheduling_states(card.id)
@ -246,10 +237,3 @@ class Scheduler(SchedulerBaseWithLegacy):
return self.col.db.list("select id from active_decks")
except DBError:
return []
@deprecated(info="no longer used by Anki; will be removed in the future")
def totalNewForCurrentDeck(self) -> int:
return self.col.db.scalar(
f"""
select count() from cards where queue={QUEUE_TYPE_NEW} and did in (select id from active_decks)"""
)

View file

@ -23,21 +23,17 @@ def test_basic():
# we start with the default col selected
assert col.decks.selected() == 1
col.reset()
assert col.decks.active() == [1]
# we can select a different col
col.decks.select(parentId)
assert col.decks.selected() == parentId
assert col.decks.active() == [parentId]
# let's create a child
childId = col.decks.id("new deck::child")
col.sched.reset()
# it should have been added to the active list
assert col.decks.selected() == parentId
assert col.decks.active() == [parentId, childId]
# we can select the child individually too
col.decks.select(childId)
assert col.decks.selected() == childId
assert col.decks.active() == [childId]
# parents with a different case should be handled correctly
col.decks.id("ONE")
m = col.models.current()

View file

@ -1,4 +0,0 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from .test_schedv2 import *

View file

@ -16,20 +16,8 @@ from anki.utils import int_time
from tests.shared import getEmptyCol as getEmptyColOrig
# This file is used to exercise both the legacy Python 2.1 scheduler,
# and the experimental new one in Rust. Most tests run on both, but a few
# tests have been implemented separately where the behaviour differs.
def is_2021() -> bool:
return "2021" in os.getenv("PYTEST_CURRENT_TEST")
def getEmptyCol():
col = getEmptyColOrig()
col.upgrade_to_v2_scheduler()
if is_2021():
col.set_v3_scheduler(True)
else:
col.set_v3_scheduler(False)
return col
@ -39,13 +27,6 @@ def test_clock():
raise Exception("Unit tests will fail around the day rollover.")
def checkRevIvl(col, c, targetIvl):
if is_2021():
return
min, max = col.sched._fuzzIvlRange(targetIvl)
assert min <= c.ivl <= max
def test_basics():
col = getEmptyCol()
col.reset()
@ -205,7 +186,6 @@ def test_learn():
col.sched.answerCard(c, 4)
assert c.type == CARD_TYPE_REV
assert c.queue == QUEUE_TYPE_REV
checkRevIvl(col, c, 4)
# revlog should have been updated each time
assert col.db.scalar("select count() from revlog where type = 0") == 5
@ -328,10 +308,7 @@ def test_learn_day():
# if we fail it, it should be back in the correct queue
col.sched.answerCard(c, 1)
assert c.queue == QUEUE_TYPE_LRN
if is_2021():
col.undo()
else:
col.undo_legacy()
col.undo()
col.reset()
c = col.sched.getCard()
col.sched.answerCard(c, 3)
@ -386,7 +363,6 @@ def test_reviews():
col.sched.answerCard(c, 2)
assert c.queue == QUEUE_TYPE_REV
# the new interval should be (100) * 1.2 = 120
checkRevIvl(col, c, 120)
assert c.due == col.sched.today + c.ivl
# factor should have been decremented
assert c.factor == 2350
@ -399,7 +375,6 @@ def test_reviews():
c.flush()
col.sched.answerCard(c, 3)
# the new interval should be (100 + 8/2) * 2.5 = 260
checkRevIvl(col, c, 260)
assert c.due == col.sched.today + c.ivl
# factor should have been left alone
assert c.factor == STARTING_FACTOR
@ -409,7 +384,6 @@ def test_reviews():
c.flush()
col.sched.answerCard(c, 4)
# the new interval should be (100 + 8) * 2.5 * 1.3 = 351
checkRevIvl(col, c, 351)
assert c.due == col.sched.today + c.ivl
# factor should have been increased
assert c.factor == 2650
@ -429,8 +403,6 @@ def test_reviews():
hooks.card_did_leech.append(onLeech)
col.sched.answerCard(c, 1)
if not is_2021():
assert hooked
assert c.queue == QUEUE_TYPE_SUSPENDED
c.load()
assert c.queue == QUEUE_TYPE_SUSPENDED
@ -719,12 +691,6 @@ def test_suspend():
def test_filt_reviewing_early_normal():
def to_int(val: float) -> int:
if is_2021():
return round(val)
else:
return int(val)
col = getEmptyCol()
note = col.newNote()
note["Front"] = "one"
@ -753,13 +719,12 @@ def test_filt_reviewing_early_normal():
c = col.sched.getCard()
assert col.sched.answerButtons(c) == 4
assert col.sched.nextIvl(c, 1) == 600
assert col.sched.nextIvl(c, 2) == to_int(75 * 1.2) * 86400
assert col.sched.nextIvl(c, 3) == to_int(75 * 2.5) * 86400
assert col.sched.nextIvl(c, 4) == to_int(75 * 2.5 * 1.15) * 86400
assert col.sched.nextIvl(c, 2) == round(75 * 1.2) * 86400
assert col.sched.nextIvl(c, 3) == round(75 * 2.5) * 86400
assert col.sched.nextIvl(c, 4) == round(75 * 2.5 * 1.15) * 86400
# answer 'good'
col.sched.answerCard(c, 3)
checkRevIvl(col, c, int(75 * 2.5))
assert c.due == col.sched.today + c.ivl
assert not c.odue
# should not be in learning
@ -777,7 +742,7 @@ def test_filt_reviewing_early_normal():
assert col.sched.nextIvl(c, 2) == 100 * 1.2 / 2 * 86400
assert col.sched.nextIvl(c, 3) == 100 * 86400
assert col.sched.nextIvl(c, 4) == to_int(100 * (1.3 - (1.3 - 1) / 2)) * 86400
assert col.sched.nextIvl(c, 4) == round(100 * (1.3 - (1.3 - 1) / 2)) * 86400
def test_filt_keep_lrn_state():
@ -845,11 +810,7 @@ def test_preview():
# grab the first card
c = col.sched.getCard()
if is_2021():
passing_grade = 4
else:
passing_grade = 2
passing_grade = 4
assert col.sched.answerButtons(c) == passing_grade
assert col.sched.nextIvl(c, 1) == 600
assert col.sched.nextIvl(c, passing_grade) == 0
@ -914,35 +875,7 @@ def test_ordcycle():
col.sched.answerCard(c, 4)
def test_counts_idx():
if is_2021():
pytest.skip("old sched only")
col = getEmptyCol()
note = col.newNote()
note["Front"] = "one"
note["Back"] = "two"
col.addNote(note)
col.reset()
assert col.sched.counts() == (1, 0, 0)
c = col.sched.getCard()
# counter's been decremented but idx indicates 1
assert col.sched.counts() == (0, 0, 0)
assert col.sched.countIdx(c) == 0
# answer to move to learn queue
col.sched.answerCard(c, 1)
assert col.sched.counts() == (0, 1, 0)
# fetching again will decrement the count
c = col.sched.getCard()
assert col.sched.counts() == (0, 0, 0)
assert col.sched.countIdx(c) == 1
# answering should add it back again
col.sched.answerCard(c, 1)
assert col.sched.counts() == (0, 1, 0)
def test_counts_idx_new():
if not is_2021():
pytest.skip("new sched only")
col = getEmptyCol()
note = col.newNote()
note["Front"] = "one"

View file

@ -1,96 +0,0 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import time
from anki.consts import *
from tests.shared import getEmptyCol as getEmptyColOrig
def getEmptyCol():
col = getEmptyColOrig()
col.upgrade_to_v2_scheduler()
return col
def test_op():
col = getEmptyCol()
col.set_v3_scheduler(False)
# should have no undo by default
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.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.undo_status().undo
assert "abc" not in col.conf
# an (auto)save will clear the undo
col.save("foo")
assert col.undo_status().undo == "foo"
col.save()
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.undo_status().undo.lower()
c = col.sched.getCard()
col.sched.answerCard(c, 2)
assert col.undo_status().undo == "Review"
def test_review():
col = getEmptyCol()
col.set_v3_scheduler(False)
col.conf["counts"] = COUNT_REMAINING
note = col.newNote()
note["Front"] = "one"
col.addNote(note)
note = col.newNote()
note["Front"] = "two"
col.addNote(note)
col.reset()
# answer
assert col.sched.counts() == (2, 0, 0)
c = col.sched.getCard()
assert c.queue == QUEUE_TYPE_NEW
col.sched.answerCard(c, 3)
assert c.left % 1000 == 1
assert col.sched.counts() == (1, 1, 0)
assert c.queue == QUEUE_TYPE_LRN
# undo
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.undo_status().undo
# we should be able to undo multiple answers too
c = col.sched.getCard()
col.sched.answerCard(c, 3)
c = col.sched.getCard()
col.sched.answerCard(c, 3)
assert col.sched.counts() == (0, 2, 0)
col.undo_legacy()
col.reset()
assert col.sched.counts() == (1, 1, 0)
col.undo_legacy()
col.reset()
assert col.sched.counts() == (2, 0, 0)
# performing a normal op will clear the review queue
c = col.sched.getCard()
col.sched.answerCard(c, 3)
assert col.undo_status().undo == "Review"
col.save("foo")
assert col.undo_status().undo == "foo"
col.undo_legacy()
assert not col.undo_status().undo

View file

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>604</width>
<width>606</width>
<height>638</height>
</rect>
</property>
@ -252,64 +252,6 @@
<string>preferences_scheduler</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_17">
<item>
<widget class="QCheckBox" name="sched2021">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string notr="true"/>
</property>
<property name="text">
<string>preferences_v3_scheduler</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="dayLearnFirst">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>preferences_show_learning_cards_with_larger_steps</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="legacy_timezone">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>preferences_legacy_timezone_handling</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_4">
<property name="spacing">
@ -392,9 +334,6 @@
</item>
</layout>
</item>
<item>
<widget class="QComboBox" name="newSpread"/>
</item>
</layout>
</widget>
</item>
@ -472,17 +411,17 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="stop_timer_on_answer">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>preferences_stop_timer_on_answer</string>
</property>
</widget>
<widget class="QCheckBox" name="stop_timer_on_answer">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>preferences_stop_timer_on_answer</string>
</property>
</widget>
</item>
</layout>
</widget>
@ -1152,13 +1091,9 @@
<tabstop>bottomBarComboBox</tabstop>
<tabstop>reduce_motion</tabstop>
<tabstop>minimalist_mode</tabstop>
<tabstop>sched2021</tabstop>
<tabstop>dayLearnFirst</tabstop>
<tabstop>legacy_timezone</tabstop>
<tabstop>dayOffset</tabstop>
<tabstop>lrnCutoff</tabstop>
<tabstop>timeLimit</tabstop>
<tabstop>newSpread</tabstop>
<tabstop>showPlayButtons</tabstop>
<tabstop>interrupt_audio</tabstop>
<tabstop>showProgress</tabstop>

View file

@ -3,15 +3,13 @@
import functools
import re
from typing import Any, cast
import anki.lang
import aqt
import aqt.forms
import aqt.operations
from anki.collection import OpChanges
from anki.consts import new_card_scheduling_labels
from aqt import AnkiQt, gui_hooks
from aqt import AnkiQt
from aqt.operations.collection import set_preferences
from aqt.profiles import VideoDriver
from aqt.qt import *
@ -106,19 +104,8 @@ class Preferences(QDialog):
scheduling = self.prefs.scheduling
version = scheduling.scheduler_version
form.dayLearnFirst.setVisible(version == 2)
form.legacy_timezone.setVisible(version >= 2)
form.newSpread.setVisible(version < 3)
form.sched2021.setVisible(version >= 2)
form.lrnCutoff.setValue(int(scheduling.learn_ahead_secs / 60.0))
form.newSpread.addItems(list(new_card_scheduling_labels(self.mw.col).values()))
form.newSpread.setCurrentIndex(scheduling.new_review_mix)
form.dayLearnFirst.setChecked(scheduling.day_learn_first)
form.dayOffset.setValue(scheduling.rollover)
form.legacy_timezone.setChecked(not scheduling.new_timezone)
form.sched2021.setChecked(version == 3)
reviewing = self.prefs.reviewing
form.timeLimit.setValue(int(reviewing.time_limit_secs / 60.0))
@ -149,11 +136,8 @@ class Preferences(QDialog):
form = self.form
scheduling = self.prefs.scheduling
scheduling.new_review_mix = cast(Any, form.newSpread.currentIndex())
scheduling.learn_ahead_secs = form.lrnCutoff.value() * 60
scheduling.day_learn_first = form.dayLearnFirst.isChecked()
scheduling.rollover = form.dayOffset.value()
scheduling.new_timezone = not form.legacy_timezone.isChecked()
reviewing = self.prefs.reviewing
reviewing.show_remaining_due_counts = form.showProgress.isChecked()
@ -179,12 +163,6 @@ class Preferences(QDialog):
def after_prefs_update(changes: OpChanges) -> None:
self.mw.apply_collection_options()
if scheduling.scheduler_version > 1:
want_v3 = form.sched2021.isChecked()
if self.mw.col.v3_scheduler() != want_v3:
self.mw.col.set_v3_scheduler(want_v3)
gui_hooks.operation_did_execute(OpChanges(study_queues=True), None)
on_done()
set_preferences(parent=self, preferences=self.prefs).success(

View file

@ -444,8 +444,6 @@ class Reviewer:
return
if self.state != "answer":
return
if self.mw.col.sched.answerButtons(self.card) < ease:
return
proceed, ease = gui_hooks.reviewer_will_answer_card(
(True, ease), self, self.card
)
@ -753,18 +751,8 @@ timerStopped = false;
return ""
counts: list[Union[int, str]]
if v3 := self._v3:
idx, counts_ = v3.counts()
counts = cast(list[Union[int, str]], counts_)
else:
# v1/v2 scheduler
if self.hadCardQueue:
# if it's come from the undo queue, don't count it separately
counts = list(self.mw.col.sched.counts())
else:
counts = list(self.mw.col.sched.counts(self.card))
idx = self.mw.col.sched.countIdx(self.card)
idx, counts_ = self._v3.counts()
counts = cast(list[Union[int, str]], counts_)
counts[idx] = f"<u>{counts[idx]}</u>"
return f"""
@ -774,10 +762,7 @@ timerStopped = false;
"""
def _defaultEase(self) -> Literal[2, 3]:
if self.mw.col.sched.answerButtons(self.card) == 4:
return 3
else:
return 2
return 3
def _answerButtonList(self) -> tuple[tuple[int, str], ...]:
button_count = self.mw.col.sched.answerButtons(self.card)
@ -841,12 +826,9 @@ timerStopped = false;
buf += "</tr></table>"
return buf
def _buttonTime(self, i: int, v3_labels: Sequence[str] | None = None) -> str:
def _buttonTime(self, i: int, v3_labels: Sequence[str]) -> str:
if self.mw.col.conf["estTimes"]:
if v3_labels:
txt = v3_labels[i - 1]
else:
txt = self.mw.col.sched.nextIvlStr(self.card, i, True) or ""
txt = v3_labels[i - 1]
return f"""<span class="nobold">{txt}</span>"""
else:
return ""