NF: CardID type

This commit is contained in:
Arthur Milchior 2021-03-23 10:36:52 +01:00 committed by Damien Elmes
parent 6ac540927a
commit 986efeed19
15 changed files with 80 additions and 64 deletions

View File

@ -5,7 +5,7 @@ from __future__ import annotations
import pprint import pprint
import time import time
from typing import List, Optional from typing import List, NewType, Optional
import anki # pylint: disable=unused-import import anki # pylint: disable=unused-import
import anki._backend.backend_pb2 as _pb import anki._backend.backend_pb2 as _pb
@ -26,6 +26,9 @@ from anki.sound import AVTag
# - rev queue: integer day # - rev queue: integer day
# - lrn queue: integer timestamp # - lrn queue: integer timestamp
# types
CardID = NewType("CardID", int)
class Card: class Card:
_note: Optional[Note] _note: Optional[Note]
@ -33,9 +36,10 @@ class Card:
lastIvl: int lastIvl: int
ord: int ord: int
nid: anki.notes.NoteID nid: anki.notes.NoteID
id: CardID
def __init__( def __init__(
self, col: anki.collection.Collection, id: Optional[int] = None self, col: anki.collection.Collection, id: Optional[CardID] = None
) -> None: ) -> None:
self.col = col.weakref() self.col = col.weakref()
self.timerStarted = None self.timerStarted = None
@ -56,7 +60,7 @@ class Card:
def _load_from_backend_card(self, c: _pb.Card) -> None: def _load_from_backend_card(self, c: _pb.Card) -> None:
self._render_output = None self._render_output = None
self._note = None self._note = None
self.id = c.id self.id = CardID(c.id)
self.nid = anki.notes.NoteID(c.note_id) self.nid = anki.notes.NoteID(c.note_id)
self.did = c.deck_id self.did = c.deck_id
self.ord = c.template_idx self.ord = c.template_idx

View File

@ -34,7 +34,7 @@ from dataclasses import dataclass, field
import anki.latex import anki.latex
from anki import hooks from anki import hooks
from anki._backend import RustBackend from anki._backend import RustBackend
from anki.cards import Card from anki.cards import Card, CardID
from anki.config import Config, ConfigManager from anki.config import Config, ConfigManager
from anki.consts import * from anki.consts import *
from anki.dbproxy import DBProxy from anki.dbproxy import DBProxy
@ -319,7 +319,7 @@ class Collection:
# Object creation helpers # Object creation helpers
########################################################################## ##########################################################################
def get_card(self, id: int) -> Card: def get_card(self, id: CardID) -> Card:
return Card(self, id) return Card(self, id)
def update_card(self, card: Card) -> None: def update_card(self, card: Card) -> None:
@ -379,7 +379,7 @@ class Collection:
hooks.notes_will_be_deleted(self, note_ids) hooks.notes_will_be_deleted(self, note_ids)
return self._backend.remove_notes(note_ids=note_ids, card_ids=[]) return self._backend.remove_notes(note_ids=note_ids, card_ids=[])
def remove_notes_by_card(self, card_ids: List[int]) -> None: def remove_notes_by_card(self, card_ids: List[CardID]) -> None:
if hooks.notes_will_be_deleted.count(): if hooks.notes_will_be_deleted.count():
nids = self.db.list( nids = self.db.list(
f"select nid from cards where id in {ids2str(card_ids)}" f"select nid from cards where id in {ids2str(card_ids)}"
@ -387,8 +387,8 @@ class Collection:
hooks.notes_will_be_deleted(self, nids) hooks.notes_will_be_deleted(self, nids)
self._backend.remove_notes(note_ids=[], card_ids=card_ids) self._backend.remove_notes(note_ids=[], card_ids=card_ids)
def card_ids_of_note(self, note_id: NoteID) -> Sequence[int]: def card_ids_of_note(self, note_id: NoteID) -> Sequence[CardID]:
return self._backend.cards_of_note(note_id) return [CardID(id) for id in self._backend.cards_of_note(note_id)]
def defaults_for_adding( def defaults_for_adding(
self, *, current_review_card: Optional[Card] self, *, current_review_card: Optional[Card]
@ -447,11 +447,11 @@ class Collection:
def cardCount(self) -> Any: def cardCount(self) -> Any:
return self.db.scalar("select count() from cards") return self.db.scalar("select count() from cards")
def remove_cards_and_orphaned_notes(self, card_ids: Sequence[int]) -> None: def remove_cards_and_orphaned_notes(self, card_ids: Sequence[CardID]) -> None:
"You probably want .remove_notes_by_card() instead." "You probably want .remove_notes_by_card() instead."
self._backend.remove_cards(card_ids=card_ids) self._backend.remove_cards(card_ids=card_ids)
def set_deck(self, card_ids: Sequence[int], deck_id: int) -> OpChanges: def set_deck(self, card_ids: Sequence[CardID], deck_id: int) -> OpChanges:
return self._backend.set_deck(card_ids=card_ids, deck_id=deck_id) return self._backend.set_deck(card_ids=card_ids, deck_id=deck_id)
def get_empty_cards(self) -> EmptyCardsReport: def get_empty_cards(self) -> EmptyCardsReport:
@ -459,10 +459,10 @@ class Collection:
# legacy # legacy
def remCards(self, ids: List[int], notes: bool = True) -> None: def remCards(self, ids: List[CardID], notes: bool = True) -> None:
self.remove_cards_and_orphaned_notes(ids) self.remove_cards_and_orphaned_notes(ids)
def emptyCids(self) -> List[int]: def emptyCids(self) -> List[CardID]:
print("emptyCids() will go away") print("emptyCids() will go away")
return [] return []
@ -495,7 +495,7 @@ class Collection:
query: str, query: str,
order: Union[bool, str, BuiltinSort.Kind.V] = False, order: Union[bool, str, BuiltinSort.Kind.V] = False,
reverse: bool = False, reverse: bool = False,
) -> Sequence[int]: ) -> Sequence[CardID]:
"""Return card ids matching the provided search. """Return card ids matching the provided search.
To programmatically construct a search string, see .build_search_string(). To programmatically construct a search string, see .build_search_string().
@ -525,7 +525,9 @@ class Collection:
mode = _pb.SortOrder( mode = _pb.SortOrder(
builtin=_pb.SortOrder.Builtin(kind=order, reverse=reverse) builtin=_pb.SortOrder.Builtin(kind=order, reverse=reverse)
) )
return self._backend.search_cards(search=query, order=mode) return [
CardID(id) for id in self._backend.search_cards(search=query, order=mode)
]
def find_notes(self, *terms: Union[str, SearchNode]) -> Sequence[NoteID]: def find_notes(self, *terms: Union[str, SearchNode]) -> Sequence[NoteID]:
"""Return note ids matching the provided search or searches. """Return note ids matching the provided search or searches.
@ -740,7 +742,7 @@ class Collection:
return CollectionStats(self) return CollectionStats(self)
def card_stats(self, card_id: int, include_revlog: bool) -> str: def card_stats(self, card_id: CardID, include_revlog: bool) -> str:
import anki.stats as st import anki.stats as st
if include_revlog: if include_revlog:
@ -1033,7 +1035,7 @@ table.review-log {{ {revlog_style} }}
########################################################################## ##########################################################################
def set_user_flag_for_cards(self, flag: int, cids: Sequence[int]) -> OpChanges: def set_user_flag_for_cards(self, flag: int, cids: Sequence[CardID]) -> OpChanges:
return self._backend.set_flag(card_ids=cids, flag=flag) return self._backend.set_flag(card_ids=cids, flag=flag)
def set_wants_abort(self) -> None: def set_wants_abort(self) -> None:

View File

@ -11,6 +11,7 @@ from typing import Any, Dict, Iterable, List, NewType, Optional, Sequence, Tuple
import anki # pylint: disable=unused-import import anki # pylint: disable=unused-import
import anki._backend.backend_pb2 as _pb import anki._backend.backend_pb2 as _pb
from anki.cards import CardID
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithID from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithID
from anki.consts import * from anki.consts import *
from anki.errors import NotFoundError from anki.errors import NotFoundError
@ -406,7 +407,7 @@ class DeckManager:
return deck["name"] return deck["name"]
return None return None
def setDeck(self, cids: List[int], did: int) -> None: def setDeck(self, cids: List[CardID], did: int) -> None:
self.col.db.execute( self.col.db.execute(
f"update cards set did=?,usn=?,mod=? where id in {ids2str(cids)}", f"update cards set did=?,usn=?,mod=? where id in {ids2str(cids)}",
did, did,
@ -414,7 +415,7 @@ class DeckManager:
intTime(), intTime(),
) )
def cids(self, did: int, children: bool = False) -> List[int]: def cids(self, did: int, children: bool = False) -> List[CardID]:
if not children: if not children:
return self.col.db.list("select id from cards where did=?", did) return self.col.db.list("select id from cards where did=?", did)
dids = [did] dids = [did]
@ -422,7 +423,7 @@ class DeckManager:
dids.append(id) dids.append(id)
return self.col.db.list(f"select id from cards where did in {ids2str(dids)}") return self.col.db.list(f"select id from cards where did in {ids2str(dids)}")
def for_card_ids(self, cids: List[int]) -> List[int]: def for_card_ids(self, cids: List[CardID]) -> List[int]:
return self.col.db.list(f"select did from cards where id in {ids2str(cids)}") return self.col.db.list(f"select did from cards where id in {ids2str(cids)}")
# Deck selection # Deck selection

View File

@ -12,6 +12,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union
from zipfile import ZipFile from zipfile import ZipFile
from anki import hooks from anki import hooks
from anki.cards import CardID
from anki.collection import Collection from anki.collection import Collection
from anki.lang import TR from anki.lang import TR
from anki.utils import ids2str, namedtmp, splitFields, stripHTML from anki.utils import ids2str, namedtmp, splitFields, stripHTML
@ -28,7 +29,7 @@ class Exporter:
self, self,
col: Collection, col: Collection,
did: Optional[int] = None, did: Optional[int] = None,
cids: Optional[List[int]] = None, cids: Optional[List[CardID]] = None,
) -> None: ) -> None:
self.col = col.weakref() self.col = col.weakref()
self.did = did self.did = did

View File

@ -5,6 +5,7 @@ import os
import unicodedata import unicodedata
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
from anki.cards import CardID
from anki.collection import Collection from anki.collection import Collection
from anki.consts import * from anki.consts import *
from anki.decks import DeckManager from anki.decks import DeckManager
@ -306,7 +307,7 @@ class Anki2Importer(Importer):
if self.source_needs_upgrade: if self.source_needs_upgrade:
self.src.upgrade_to_v2_scheduler() self.src.upgrade_to_v2_scheduler()
# build map of (guid, ord) -> cid and used id cache # build map of (guid, ord) -> cid and used id cache
self._cards: Dict[Tuple[str, int], int] = {} self._cards: Dict[Tuple[str, int], CardID] = {}
existing = {} existing = {}
for guid, ord, cid in self.dst.db.execute( for guid, ord, cid in self.dst.db.execute(
"select f.guid, c.ord, c.id from cards c, notes f " "where c.nid = f.id" "select f.guid, c.ord, c.id from cards c, notes f " "where c.nid = f.id"

View File

@ -24,6 +24,7 @@ class Note:
# not currently exposed # not currently exposed
flags = 0 flags = 0
data = "" data = ""
id: NoteID
def __init__( def __init__(
self, self,
@ -122,7 +123,7 @@ class Note:
def cards(self) -> List[anki.cards.Card]: def cards(self) -> List[anki.cards.Card]:
return [self.col.getCard(id) for id in self.card_ids()] return [self.col.getCard(id) for id in self.card_ids()]
def card_ids(self) -> Sequence[int]: def card_ids(self) -> Sequence[anki.cards.CardID]:
return self.col.card_ids_of_note(self.id) return self.col.card_ids_of_note(self.id)
def model(self) -> Optional[NoteType]: def model(self) -> Optional[NoteType]:

View File

@ -13,6 +13,7 @@ SchedTimingToday = _pb.SchedTimingTodayOut
from typing import List, Optional, Sequence from typing import List, Optional, Sequence
from anki.cards import CardID
from anki.consts import CARD_TYPE_NEW, NEW_CARDS_RANDOM, QUEUE_TYPE_NEW, QUEUE_TYPE_REV from anki.consts import CARD_TYPE_NEW, NEW_CARDS_RANDOM, QUEUE_TYPE_NEW, QUEUE_TYPE_REV
from anki.decks import DeckConfigDict, DeckID, DeckTreeNode from anki.decks import DeckConfigDict, DeckID, DeckTreeNode
from anki.notes import Note from anki.notes import Note
@ -107,10 +108,10 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
# Suspending & burying # Suspending & burying
########################################################################## ##########################################################################
def unsuspend_cards(self, ids: Sequence[int]) -> OpChanges: def unsuspend_cards(self, ids: Sequence[CardID]) -> OpChanges:
return self.col._backend.restore_buried_and_suspended_cards(ids) return self.col._backend.restore_buried_and_suspended_cards(ids)
def unbury_cards(self, ids: List[int]) -> OpChanges: def unbury_cards(self, ids: List[CardID]) -> OpChanges:
return self.col._backend.restore_buried_and_suspended_cards(ids) return self.col._backend.restore_buried_and_suspended_cards(ids)
def unbury_cards_in_current_deck( def unbury_cards_in_current_deck(
@ -119,12 +120,12 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
) -> None: ) -> None:
self.col._backend.unbury_cards_in_current_deck(mode) self.col._backend.unbury_cards_in_current_deck(mode)
def suspend_cards(self, ids: Sequence[int]) -> OpChanges: def suspend_cards(self, ids: Sequence[CardID]) -> OpChanges:
return self.col._backend.bury_or_suspend_cards( return self.col._backend.bury_or_suspend_cards(
card_ids=ids, mode=BuryOrSuspend.SUSPEND card_ids=ids, mode=BuryOrSuspend.SUSPEND
) )
def bury_cards(self, ids: Sequence[int], manual: bool = True) -> OpChanges: def bury_cards(self, ids: Sequence[CardID], manual: bool = True) -> OpChanges:
if manual: if manual:
mode = BuryOrSuspend.BURY_USER mode = BuryOrSuspend.BURY_USER
else: else:
@ -137,13 +138,13 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
# Resetting/rescheduling # Resetting/rescheduling
########################################################################## ##########################################################################
def schedule_cards_as_new(self, card_ids: List[int]) -> OpChanges: def schedule_cards_as_new(self, card_ids: List[CardID]) -> OpChanges:
"Put cards at the end of the new queue." "Put cards at the end of the new queue."
return self.col._backend.schedule_cards_as_new(card_ids=card_ids, log=True) return self.col._backend.schedule_cards_as_new(card_ids=card_ids, log=True)
def set_due_date( def set_due_date(
self, self,
card_ids: List[int], card_ids: List[CardID],
days: str, days: str,
config_key: Optional[Config.String.Key.V] = None, config_key: Optional[Config.String.Key.V] = None,
) -> OpChanges: ) -> OpChanges:
@ -162,7 +163,7 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
config_key=key, # type: ignore config_key=key, # type: ignore
) )
def resetCards(self, ids: List[int]) -> None: def resetCards(self, ids: List[CardID]) -> None:
"Completely reset cards for export." "Completely reset cards for export."
sids = ids2str(ids) sids = ids2str(ids)
assert self.col.db assert self.col.db
@ -184,7 +185,7 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
def reposition_new_cards( def reposition_new_cards(
self, self,
card_ids: Sequence[int], card_ids: Sequence[CardID],
starting_from: int, starting_from: int,
step_size: int, step_size: int,
randomize: bool, randomize: bool,
@ -223,7 +224,7 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
# legacy # legacy
def sortCards( def sortCards(
self, self,
cids: List[int], cids: List[CardID],
start: int = 1, start: int = 1,
step: int = 1, step: int = 1,
shuffle: bool = False, shuffle: bool = False,

View File

@ -3,7 +3,7 @@
from typing import List, Optional, Tuple from typing import List, Optional, Tuple
from anki.cards import Card from anki.cards import Card, CardID
from anki.consts import CARD_TYPE_RELEARNING, QUEUE_TYPE_DAY_LEARN_RELEARN from anki.consts import CARD_TYPE_RELEARNING, QUEUE_TYPE_DAY_LEARN_RELEARN
from anki.decks import DeckConfigDict from anki.decks import DeckConfigDict
from anki.notes import NoteID from anki.notes import NoteID
@ -15,7 +15,7 @@ class SchedulerBaseWithLegacy(SchedulerBase):
"Legacy aliases and helpers. These will go away in the future." "Legacy aliases and helpers. These will go away in the future."
def reschedCards( def reschedCards(
self, card_ids: List[int], min_interval: int, max_interval: int self, card_ids: List[CardID], min_interval: int, max_interval: int
) -> None: ) -> None:
self.set_due_date(card_ids, f"{min_interval}-{max_interval}!") self.set_due_date(card_ids, f"{min_interval}-{max_interval}!")
@ -80,7 +80,7 @@ due = (case when odue>0 then odue else due end), odue = 0, odid = 0, usn = ? whe
self.col.usn(), self.col.usn(),
) )
def remFromDyn(self, cids: List[int]) -> None: def remFromDyn(self, cids: List[CardID]) -> None:
self.emptyDyn(None, f"id in {ids2str(cids)} and odid") self.emptyDyn(None, f"id in {ids2str(cids)} and odid")
# used by v2 scheduler and some add-ons # used by v2 scheduler and some add-ons

View File

@ -11,7 +11,7 @@ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
import anki # pylint: disable=unused-import import anki # pylint: disable=unused-import
import anki._backend.backend_pb2 as _pb import anki._backend.backend_pb2 as _pb
from anki import hooks from anki import hooks
from anki.cards import Card from anki.cards import Card, CardID
from anki.consts import * from anki.consts import *
from anki.decks import DeckConfigDict, DeckDict from anki.decks import DeckConfigDict, DeckDict
from anki.lang import FormatTimeSpan from anki.lang import FormatTimeSpan
@ -144,7 +144,7 @@ class Scheduler(SchedulerBaseWithLegacy):
def _resetNew(self) -> None: def _resetNew(self) -> None:
self._newDids = self.col.decks.active()[:] self._newDids = self.col.decks.active()[:]
self._newQueue: List[int] = [] self._newQueue: List[CardID] = []
self._updateNewCardRatio() self._updateNewCardRatio()
def _fillNew(self, recursing: bool = False) -> bool: def _fillNew(self, recursing: bool = False) -> bool:
@ -301,8 +301,8 @@ select count() from cards where did in %s and queue = {QUEUE_TYPE_PREVIEW}
def _resetLrn(self) -> None: def _resetLrn(self) -> None:
self._updateLrnCutoff(force=True) self._updateLrnCutoff(force=True)
self._resetLrnCount() self._resetLrnCount()
self._lrnQueue: List[Tuple[int, int]] = [] self._lrnQueue: List[Tuple[int, CardID]] = []
self._lrnDayQueue: List[int] = [] self._lrnDayQueue: List[CardID] = []
self._lrnDids = self.col.decks.active()[:] self._lrnDids = self.col.decks.active()[:]
# sub-day learning # sub-day learning
@ -397,7 +397,7 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""",
return hooks.scheduler_review_limit_for_single_deck(lim, d) return hooks.scheduler_review_limit_for_single_deck(lim, d)
def _resetRev(self) -> None: def _resetRev(self) -> None:
self._revQueue: List[int] = [] self._revQueue: List[CardID] = []
def _fillRev(self, recursing: bool = False) -> bool: def _fillRev(self, recursing: bool = False) -> bool:
"True if a review card can be fetched." "True if a review card can be fetched."
@ -1072,7 +1072,7 @@ limit ?"""
########################################################################## ##########################################################################
def _burySiblings(self, card: Card) -> None: def _burySiblings(self, card: Card) -> None:
toBury: List[int] = [] toBury: List[CardID] = []
nconf = self._newConf(card) nconf = self._newConf(card)
buryNew = nconf.get("bury", True) buryNew = nconf.get("bury", True)
rconf = self._revConf(card) rconf = self._revConf(card)

View File

@ -22,7 +22,7 @@ from typing import (
import aqt import aqt
import aqt.forms import aqt.forms
from anki.cards import Card from anki.cards import Card, CardID
from anki.collection import BrowserRow, Collection, Config, OpChanges, SearchNode from anki.collection import BrowserRow, Collection, Config, OpChanges, SearchNode
from anki.consts import * from anki.consts import *
from anki.errors import NotFoundError from anki.errors import NotFoundError
@ -97,7 +97,7 @@ class SearchContext:
browser: Browser browser: Browser
order: Union[bool, str] = True order: Union[bool, str] = True
# if set, provided card ids will be used instead of the regular search # if set, provided card ids will be used instead of the regular search
card_ids: Optional[Sequence[int]] = None card_ids: Optional[Sequence[CardID]] = None
# Data model # Data model
@ -170,13 +170,13 @@ class DataModel(QAbstractTableModel):
self.activeCols: List[str] = self.col.get_config( self.activeCols: List[str] = self.col.get_config(
"activeCols", ["noteFld", "template", "cardDue", "deck"] "activeCols", ["noteFld", "template", "cardDue", "deck"]
) )
self.cards: Sequence[int] = [] self.cards: Sequence[CardID] = []
self._rows: Dict[int, CellRow] = {} self._rows: Dict[int, CellRow] = {}
self._last_refresh = 0.0 self._last_refresh = 0.0
# serve stale content to avoid hitting the DB? # serve stale content to avoid hitting the DB?
self.block_updates = False self.block_updates = False
def get_id(self, index: QModelIndex) -> int: def get_id(self, index: QModelIndex) -> CardID:
return self.cards[index.row()] return self.cards[index.row()]
def get_cell(self, index: QModelIndex) -> Cell: def get_cell(self, index: QModelIndex) -> Cell:
@ -198,7 +198,7 @@ class DataModel(QAbstractTableModel):
self._rows[cid] = self._fetch_row_from_backend(cid) self._rows[cid] = self._fetch_row_from_backend(cid)
return self._rows[cid] return self._rows[cid]
def _fetch_row_from_backend(self, cid: int) -> CellRow: def _fetch_row_from_backend(self, cid: CardID) -> CellRow:
try: try:
row = CellRow(*self.col.browser_row_for_card(cid)) row = CellRow(*self.col.browser_row_for_card(cid))
except NotFoundError: except NotFoundError:
@ -1049,7 +1049,7 @@ QTableView {{ gridline-color: {grid} }}
# Menu helpers # Menu helpers
###################################################################### ######################################################################
def selected_cards(self) -> List[int]: def selected_cards(self) -> List[CardID]:
return [ return [
self.model.cards[idx.row()] self.model.cards[idx.row()]
for idx in self.form.tableView.selectionModel().selectedRows() for idx in self.form.tableView.selectionModel().selectedRows()
@ -1068,7 +1068,7 @@ where id in %s"""
) )
) )
def selectedNotesAsCards(self) -> List[int]: def selectedNotesAsCards(self) -> List[CardID]:
return self.col.db.list( return self.col.db.list(
"select id from cards where nid in (%s)" "select id from cards where nid in (%s)"
% ",".join([str(s) for s in self.selected_notes()]) % ",".join([str(s) for s in self.selected_notes()])
@ -1590,7 +1590,7 @@ where id in %s"""
def onCardList(self) -> None: def onCardList(self) -> None:
self.form.tableView.setFocus() self.form.tableView.setFocus()
def focusCid(self, cid: int) -> None: def focusCid(self, cid: CardID) -> None:
try: try:
row = list(self.model.cards).index(cid) row = list(self.model.cards).index(cid)
except ValueError: except ValueError:

View File

@ -5,12 +5,14 @@ from __future__ import annotations
from typing import Sequence from typing import Sequence
from anki.cards import CardID
from anki.decks import DeckID
from aqt import AnkiQt from aqt import AnkiQt
def set_card_deck(*, mw: AnkiQt, card_ids: Sequence[int], deck_id: int) -> None: def set_card_deck(*, mw: AnkiQt, card_ids: Sequence[CardID], deck_id: DeckID) -> None:
mw.perform_op(lambda: mw.col.set_deck(card_ids, deck_id)) mw.perform_op(lambda: mw.col.set_deck(card_ids, deck_id))
def set_card_flag(*, mw: AnkiQt, card_ids: Sequence[int], flag: int) -> None: def set_card_flag(*, mw: AnkiQt, card_ids: Sequence[CardID], flag: int) -> None:
mw.perform_op(lambda: mw.col.set_user_flag_for_cards(flag, card_ids)) mw.perform_op(lambda: mw.col.set_user_flag_for_cards(flag, card_ids))

View File

@ -5,9 +5,10 @@ from __future__ import annotations
import re import re
from concurrent.futures import Future from concurrent.futures import Future
from typing import Any from typing import Any, List
import aqt import aqt
from anki.cards import CardID
from anki.collection import EmptyCardsReport from anki.collection import EmptyCardsReport
from aqt import gui_hooks from aqt import gui_hooks
from aqt.qt import QDialog, QDialogButtonBox, qconnect from aqt.qt import QDialog, QDialogButtonBox, qconnect
@ -88,14 +89,14 @@ class EmptyCardsDialog(QDialog):
self.mw.taskman.run_in_background(delete, on_done) self.mw.taskman.run_in_background(delete, on_done)
def _delete_cards(self, keep_notes: bool) -> int: def _delete_cards(self, keep_notes: bool) -> int:
to_delete = [] to_delete: List[CardID] = []
note: EmptyCardsReport.NoteWithEmptyCards note: EmptyCardsReport.NoteWithEmptyCards
for note in self.report.notes: for note in self.report.notes:
if keep_notes and note.will_delete_note: if keep_notes and note.will_delete_note:
# leave first card # leave first card
to_delete.extend(note.card_ids[1:]) to_delete.extend([CardID(id) for id in note.card_ids[1:]])
else: else:
to_delete.extend(note.card_ids) to_delete.extend([CardID(id) for id in note.card_ids])
self.mw.col.remove_cards_and_orphaned_notes(to_delete) self.mw.col.remove_cards_and_orphaned_notes(to_delete)
return len(to_delete) return len(to_delete)

View File

@ -11,6 +11,7 @@ from typing import List, Optional
import aqt import aqt
from anki import hooks from anki import hooks
from anki.cards import CardID
from anki.exporting import Exporter, exporters from anki.exporting import Exporter, exporters
from aqt.qt import * from aqt.qt import *
from aqt.utils import ( from aqt.utils import (
@ -29,7 +30,7 @@ class ExportDialog(QDialog):
self, self,
mw: aqt.main.AnkiQt, mw: aqt.main.AnkiQt,
did: Optional[int] = None, did: Optional[int] = None,
cids: Optional[List[int]] = None, cids: Optional[List[CardID]] = None,
): ):
QDialog.__init__(self, mw, Qt.Window) QDialog.__init__(self, mw, Qt.Window)
self.mw = mw self.mw = mw

View File

@ -13,7 +13,7 @@ from typing import Any, Callable, List, Match, Optional, Sequence, Tuple, Union
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from anki import hooks from anki import hooks
from anki.cards import Card from anki.cards import Card, CardID
from anki.collection import Config, OpChanges from anki.collection import Config, OpChanges
from anki.tags import MARKED_TAG from anki.tags import MARKED_TAG
from anki.utils import stripHTML from anki.utils import stripHTML
@ -74,7 +74,7 @@ class Reviewer:
self.card: Optional[Card] = None self.card: Optional[Card] = None
self.cardQueue: List[Card] = [] self.cardQueue: List[Card] = []
self.hadCardQueue = False self.hadCardQueue = False
self._answeredIds: List[int] = [] self._answeredIds: List[CardID] = []
self._recordedAudio: Optional[str] = None self._recordedAudio: Optional[str] = None
self.typeCorrect: str = None # web init happens before this is set self.typeCorrect: str = None # web init happens before this is set
self.state: Optional[str] = None self.state: Optional[str] = None

View File

@ -6,6 +6,7 @@ from __future__ import annotations
from typing import List, Optional, Sequence from typing import List, Optional, Sequence
import aqt import aqt
from anki.cards import CardID
from anki.collection import CARD_TYPE_NEW, Config from anki.collection import CARD_TYPE_NEW, Config
from anki.decks import DeckID from anki.decks import DeckID
from anki.lang import TR from anki.lang import TR
@ -21,7 +22,7 @@ def set_due_date_dialog(
*, *,
mw: aqt.AnkiQt, mw: aqt.AnkiQt,
parent: QWidget, parent: QWidget,
card_ids: List[int], card_ids: List[CardID],
config_key: Optional[Config.String.Key.V], config_key: Optional[Config.String.Key.V],
) -> None: ) -> None:
if not card_ids: if not card_ids:
@ -54,7 +55,7 @@ def set_due_date_dialog(
) )
def forget_cards(*, mw: aqt.AnkiQt, parent: QWidget, card_ids: List[int]) -> None: def forget_cards(*, mw: aqt.AnkiQt, parent: QWidget, card_ids: List[CardID]) -> None:
if not card_ids: if not card_ids:
return return
@ -67,7 +68,7 @@ def forget_cards(*, mw: aqt.AnkiQt, parent: QWidget, card_ids: List[int]) -> Non
def reposition_new_cards_dialog( def reposition_new_cards_dialog(
*, mw: AnkiQt, parent: QWidget, card_ids: Sequence[int] *, mw: AnkiQt, parent: QWidget, card_ids: Sequence[CardID]
) -> None: ) -> None:
assert mw.col.db assert mw.col.db
row = mw.col.db.first( row = mw.col.db.first(
@ -112,7 +113,7 @@ def reposition_new_cards(
*, *,
mw: AnkiQt, mw: AnkiQt,
parent: QWidget, parent: QWidget,
card_ids: Sequence[int], card_ids: Sequence[CardID],
starting_from: int, starting_from: int,
step_size: int, step_size: int,
randomize: bool, randomize: bool,
@ -135,7 +136,7 @@ def reposition_new_cards(
def suspend_cards( def suspend_cards(
*, *,
mw: AnkiQt, mw: AnkiQt,
card_ids: Sequence[int], card_ids: Sequence[CardID],
success: PerformOpOptionalSuccessCallback = None, success: PerformOpOptionalSuccessCallback = None,
) -> None: ) -> None:
mw.perform_op(lambda: mw.col.sched.suspend_cards(card_ids), success=success) mw.perform_op(lambda: mw.col.sched.suspend_cards(card_ids), success=success)
@ -153,14 +154,14 @@ def suspend_note(
) )
def unsuspend_cards(*, mw: AnkiQt, card_ids: Sequence[int]) -> None: def unsuspend_cards(*, mw: AnkiQt, card_ids: Sequence[CardID]) -> None:
mw.perform_op(lambda: mw.col.sched.unsuspend_cards(card_ids)) mw.perform_op(lambda: mw.col.sched.unsuspend_cards(card_ids))
def bury_cards( def bury_cards(
*, *,
mw: AnkiQt, mw: AnkiQt,
card_ids: Sequence[int], card_ids: Sequence[CardID],
success: PerformOpOptionalSuccessCallback = None, success: PerformOpOptionalSuccessCallback = None,
) -> None: ) -> None:
mw.perform_op(lambda: mw.col.sched.bury_cards(card_ids), success=success) mw.perform_op(lambda: mw.col.sched.bury_cards(card_ids), success=success)