NF: NoteTypeID type
This commit is contained in:
parent
b54410200e
commit
7ea862931c
@ -42,7 +42,7 @@ from anki.decks import DeckID, DeckManager
|
||||
from anki.errors import AnkiError, DBError
|
||||
from anki.lang import TR, FormatTimeSpan
|
||||
from anki.media import MediaManager, media_paths_from_col_path
|
||||
from anki.models import ModelManager, NoteType
|
||||
from anki.models import ModelManager, NoteType, NoteTypeID
|
||||
from anki.notes import Note, NoteID
|
||||
from anki.scheduler.v1 import Scheduler as V1Scheduler
|
||||
from anki.scheduler.v2 import Scheduler as V2Scheduler
|
||||
@ -406,7 +406,7 @@ class Collection:
|
||||
home_deck_of_current_review_card=home_deck,
|
||||
)
|
||||
|
||||
def default_deck_for_notetype(self, notetype_id: NoteID) -> Optional[DeckID]:
|
||||
def default_deck_for_notetype(self, notetype_id: NoteTypeID) -> Optional[DeckID]:
|
||||
"""If 'change deck depending on notetype' is enabled in the preferences,
|
||||
return the last deck used with the provided notetype, if any.."""
|
||||
if self.get_config_bool(Config.Bool.ADDING_DEFAULTS_TO_CURRENT_DECK):
|
||||
@ -578,7 +578,7 @@ class Collection:
|
||||
dupes = []
|
||||
fields: Dict[int, int] = {}
|
||||
|
||||
def ordForMid(mid: int) -> int:
|
||||
def ordForMid(mid: NoteTypeID) -> int:
|
||||
if mid not in fields:
|
||||
model = self.models.get(mid)
|
||||
for c, f in enumerate(model["flds"]):
|
||||
|
@ -11,6 +11,7 @@ from anki.consts import *
|
||||
from anki.decks import DeckID, DeckManager
|
||||
from anki.importing.base import Importer
|
||||
from anki.lang import TR
|
||||
from anki.models import NoteTypeID
|
||||
from anki.notes import NoteID
|
||||
from anki.utils import intTime, joinFields, splitFields, stripHTMLMedia
|
||||
|
||||
@ -81,7 +82,7 @@ class Anki2Importer(Importer):
|
||||
|
||||
def _importNotes(self) -> None:
|
||||
# build guid -> (id,mod,mid) hash & map of existing note ids
|
||||
self._notes: Dict[str, Tuple[NoteID, int, int]] = {}
|
||||
self._notes: Dict[str, Tuple[NoteID, int, NoteTypeID]] = {}
|
||||
existing = {}
|
||||
for id, guid, mod, mid in self.dst.db.execute(
|
||||
"select id, guid, mod, mid from notes"
|
||||
@ -217,9 +218,9 @@ class Anki2Importer(Importer):
|
||||
|
||||
def _prepareModels(self) -> None:
|
||||
"Prepare index of schema hashes."
|
||||
self._modelMap: Dict[int, int] = {}
|
||||
self._modelMap: Dict[NoteTypeID, NoteTypeID] = {}
|
||||
|
||||
def _mid(self, srcMid: int) -> Any:
|
||||
def _mid(self, srcMid: NoteTypeID) -> Any:
|
||||
"Return local id for remote MID."
|
||||
# already processed this mid?
|
||||
if srcMid in self._modelMap:
|
||||
@ -248,7 +249,7 @@ class Anki2Importer(Importer):
|
||||
self.dst.models.update(model)
|
||||
break
|
||||
# as they don't match, try next id
|
||||
mid += 1
|
||||
mid = NoteTypeID(mid + 1)
|
||||
# save map and return new mid
|
||||
self._modelMap[srcMid] = mid
|
||||
return mid
|
||||
@ -432,7 +433,7 @@ insert or ignore into revlog values (?,?,?,?,?,?,?,?,?)""",
|
||||
# the user likely used subdirectories
|
||||
pass
|
||||
|
||||
def _mungeMedia(self, mid: int, fieldsStr: str) -> str:
|
||||
def _mungeMedia(self, mid: NoteTypeID, fieldsStr: str) -> str:
|
||||
fields = splitFields(fieldsStr)
|
||||
|
||||
def repl(match):
|
||||
|
@ -10,6 +10,7 @@ from anki.config import Config
|
||||
from anki.consts import NEW_CARDS_RANDOM, STARTING_FACTOR
|
||||
from anki.importing.base import Importer
|
||||
from anki.lang import TR
|
||||
from anki.models import NoteTypeID
|
||||
from anki.notes import NoteID
|
||||
from anki.utils import (
|
||||
fieldChecksum,
|
||||
@ -243,7 +244,7 @@ class NoteImporter(Importer):
|
||||
|
||||
def newData(
|
||||
self, n: ForeignNote
|
||||
) -> Tuple[NoteID, str, int, int, int, str, str, str, int, int, str]:
|
||||
) -> Tuple[NoteID, str, NoteTypeID, int, int, str, str, str, int, int, str]:
|
||||
id = self._nextID
|
||||
self._nextID = NoteID(self._nextID + 1)
|
||||
self._ids.append(id)
|
||||
@ -267,7 +268,9 @@ class NoteImporter(Importer):
|
||||
|
||||
def addNew(
|
||||
self,
|
||||
rows: List[Tuple[NoteID, str, int, int, int, str, str, str, int, int, str]],
|
||||
rows: List[
|
||||
Tuple[NoteID, str, NoteTypeID, int, int, str, str, str, int, int, str]
|
||||
],
|
||||
) -> None:
|
||||
self.col.db.executemany(
|
||||
"insert or replace into notes values (?,?,?,?,?,?,?,?,?,?,?)", rows
|
||||
|
@ -17,6 +17,7 @@ import anki
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki.consts import *
|
||||
from anki.latex import render_latex, render_latex_returning_errors
|
||||
from anki.models import NoteTypeID
|
||||
from anki.sound import SoundOrVideoTag
|
||||
from anki.template import av_tags_to_native
|
||||
from anki.utils import intTime
|
||||
@ -159,7 +160,7 @@ class MediaManager:
|
||||
##########################################################################
|
||||
|
||||
def filesInStr(
|
||||
self, mid: int, string: str, includeRemote: bool = False
|
||||
self, mid: NoteTypeID, string: str, includeRemote: bool = False
|
||||
) -> List[str]:
|
||||
l = []
|
||||
model = self.col.models.get(mid)
|
||||
|
@ -8,7 +8,7 @@ import pprint
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
|
||||
from typing import Any, Dict, List, NewType, Optional, Sequence, Tuple, Union
|
||||
|
||||
import anki # pylint: disable=unused-import
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
@ -35,6 +35,7 @@ NoteTypeNameIDUseCount = _pb.NoteTypeNameIDUseCount
|
||||
NoteType = Dict[str, Any]
|
||||
Field = Dict[str, Any]
|
||||
Template = Dict[str, Union[str, int, None]]
|
||||
NoteTypeID = NewType("NoteTypeID", int)
|
||||
|
||||
|
||||
class ModelsDictProxy:
|
||||
@ -47,7 +48,7 @@ class ModelsDictProxy:
|
||||
|
||||
def __getitem__(self, item: Any) -> Any:
|
||||
self._warn()
|
||||
return self._col.models.get(int(item))
|
||||
return self._col.models.get(NoteTypeID(int(item)))
|
||||
|
||||
def __setitem__(self, key: str, val: Any) -> None:
|
||||
self._warn()
|
||||
@ -114,16 +115,16 @@ class ModelManager:
|
||||
# need to cache responses from the backend. Please do not
|
||||
# access the cache directly!
|
||||
|
||||
_cache: Dict[int, NoteType] = {}
|
||||
_cache: Dict[NoteTypeID, NoteType] = {}
|
||||
|
||||
def _update_cache(self, nt: NoteType) -> None:
|
||||
self._cache[nt["id"]] = nt
|
||||
|
||||
def _remove_from_cache(self, ntid: int) -> None:
|
||||
def _remove_from_cache(self, ntid: NoteTypeID) -> None:
|
||||
if ntid in self._cache:
|
||||
del self._cache[ntid]
|
||||
|
||||
def _get_cached(self, ntid: int) -> Optional[NoteType]:
|
||||
def _get_cached(self, ntid: NoteTypeID) -> Optional[NoteType]:
|
||||
return self._cache.get(ntid)
|
||||
|
||||
def _clear_cache(self) -> None:
|
||||
@ -143,11 +144,11 @@ class ModelManager:
|
||||
def allNames(self) -> List[str]:
|
||||
return [n.name for n in self.all_names_and_ids()]
|
||||
|
||||
def ids(self) -> List[int]:
|
||||
return [n.id for n in self.all_names_and_ids()]
|
||||
def ids(self) -> List[NoteTypeID]:
|
||||
return [NoteTypeID(n.id) for n in self.all_names_and_ids()]
|
||||
|
||||
# only used by importing code
|
||||
def have(self, id: int) -> bool:
|
||||
def have(self, id: NoteTypeID) -> bool:
|
||||
if isinstance(id, str):
|
||||
id = int(id)
|
||||
return any(True for e in self.all_names_and_ids() if e.id == id)
|
||||
@ -162,7 +163,7 @@ class ModelManager:
|
||||
m = self.get(self.col.conf["curModel"])
|
||||
if m:
|
||||
return m
|
||||
return self.get(self.all_names_and_ids()[0].id)
|
||||
return self.get(NoteTypeID(self.all_names_and_ids()[0].id))
|
||||
|
||||
def setCurrent(self, m: NoteType) -> None:
|
||||
self.col.conf["curModel"] = m["id"]
|
||||
@ -170,13 +171,13 @@ class ModelManager:
|
||||
# Retrieving and creating models
|
||||
#############################################################
|
||||
|
||||
def id_for_name(self, name: str) -> Optional[int]:
|
||||
def id_for_name(self, name: str) -> Optional[NoteTypeID]:
|
||||
try:
|
||||
return self.col._backend.get_notetype_id_by_name(name)
|
||||
return NoteTypeID(self.col._backend.get_notetype_id_by_name(name))
|
||||
except NotFoundError:
|
||||
return None
|
||||
|
||||
def get(self, id: int) -> Optional[NoteType]:
|
||||
def get(self, id: NoteTypeID) -> Optional[NoteType]:
|
||||
"Get model with ID, or None."
|
||||
# deal with various legacy input types
|
||||
if id is None:
|
||||
@ -195,7 +196,7 @@ class ModelManager:
|
||||
|
||||
def all(self) -> List[NoteType]:
|
||||
"Get all models."
|
||||
return [self.get(nt.id) for nt in self.all_names_and_ids()]
|
||||
return [self.get(NoteTypeID(nt.id)) for nt in self.all_names_and_ids()]
|
||||
|
||||
def byName(self, name: str) -> Optional[NoteType]:
|
||||
"Get model with NAME."
|
||||
@ -222,10 +223,10 @@ class ModelManager:
|
||||
|
||||
def remove_all_notetypes(self) -> None:
|
||||
for nt in self.all_names_and_ids():
|
||||
self._remove_from_cache(nt.id)
|
||||
self._remove_from_cache(NoteTypeID(nt.id))
|
||||
self.col._backend.remove_notetype(nt.id)
|
||||
|
||||
def remove(self, id: int) -> None:
|
||||
def remove(self, id: NoteTypeID) -> None:
|
||||
"Modifies schema."
|
||||
self._remove_from_cache(id)
|
||||
self.col._backend.remove_notetype(id)
|
||||
@ -257,7 +258,7 @@ class ModelManager:
|
||||
# Tools
|
||||
##################################################
|
||||
|
||||
def nids(self, ntid: int) -> List[anki.notes.NoteID]:
|
||||
def nids(self, ntid: NoteTypeID) -> List[anki.notes.NoteID]:
|
||||
"Note ids for M."
|
||||
if isinstance(ntid, dict):
|
||||
# legacy callers passed in note type
|
||||
@ -403,7 +404,7 @@ class ModelManager:
|
||||
self.reposition_template(m, template, idx)
|
||||
self.save(m)
|
||||
|
||||
def template_use_count(self, ntid: int, ord: int) -> int:
|
||||
def template_use_count(self, ntid: NoteTypeID, ord: int) -> int:
|
||||
return self.col.db.scalar(
|
||||
"""
|
||||
select count() from cards, notes where cards.nid = notes.id
|
||||
|
@ -11,7 +11,7 @@ import anki # pylint: disable=unused-import
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki import hooks
|
||||
from anki.consts import MODEL_STD
|
||||
from anki.models import NoteType, Template
|
||||
from anki.models import NoteType, NoteTypeID, Template
|
||||
from anki.utils import joinFields
|
||||
|
||||
DuplicateOrEmptyResult = _pb.NoteIsDuplicateOrEmptyOut.State
|
||||
@ -25,6 +25,7 @@ class Note:
|
||||
flags = 0
|
||||
data = ""
|
||||
id: NoteID
|
||||
mid: NoteTypeID
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -52,7 +53,7 @@ class Note:
|
||||
def _load_from_backend_note(self, n: _pb.Note) -> None:
|
||||
self.id = NoteID(n.id)
|
||||
self.guid = n.guid
|
||||
self.mid = n.notetype_id
|
||||
self.mid = NoteTypeID(n.notetype_id)
|
||||
self.mod = n.mtime_secs
|
||||
self.usn = n.usn
|
||||
self.tags = list(n.tags)
|
||||
|
@ -9,6 +9,7 @@ import aqt.forms
|
||||
from anki.collection import OpChanges, SearchNode
|
||||
from anki.consts import MODEL_CLOZE
|
||||
from anki.decks import DeckID
|
||||
from anki.models import NoteTypeID
|
||||
from anki.notes import DuplicateOrEmptyResult, Note, NoteID
|
||||
from anki.utils import htmlToTextLine, isMac
|
||||
from aqt import AnkiQt, gui_hooks
|
||||
@ -65,7 +66,7 @@ class AddCards(QDialog):
|
||||
self.notetype_chooser = NoteTypeChooser(
|
||||
mw=self.mw,
|
||||
widget=self.form.modelArea,
|
||||
starting_notetype_id=defaults.notetype_id,
|
||||
starting_notetype_id=NoteTypeID(defaults.notetype_id),
|
||||
on_button_activated=self.show_notetype_selector,
|
||||
on_notetype_changed=self.on_notetype_change,
|
||||
)
|
||||
@ -110,7 +111,7 @@ class AddCards(QDialog):
|
||||
def show_notetype_selector(self) -> None:
|
||||
self.editor.call_after_note_saved(self.notetype_chooser.choose_notetype)
|
||||
|
||||
def on_notetype_change(self, notetype_id: NoteID) -> None:
|
||||
def on_notetype_change(self, notetype_id: NoteTypeID) -> None:
|
||||
# need to adjust current deck?
|
||||
if deck_id := self.mw.col.default_deck_for_notetype(notetype_id):
|
||||
self.deck_chooser.selected_deck_id = deck_id
|
||||
|
@ -8,7 +8,7 @@ from typing import Any, List, Optional, Sequence
|
||||
import aqt.clayout
|
||||
from anki import stdmodels
|
||||
from anki.lang import without_unicode_isolation
|
||||
from anki.models import NoteType, NoteTypeNameIDUseCount
|
||||
from anki.models import NoteType, NoteTypeID, NoteTypeNameIDUseCount
|
||||
from anki.notes import Note
|
||||
from aqt import AnkiQt, gui_hooks
|
||||
from aqt.qt import *
|
||||
@ -33,7 +33,7 @@ class Models(QDialog):
|
||||
mw: AnkiQt,
|
||||
parent: Optional[QWidget] = None,
|
||||
fromMain: bool = False,
|
||||
selected_notetype_id: Optional[int] = None,
|
||||
selected_notetype_id: Optional[NoteTypeID] = None,
|
||||
):
|
||||
self.mw = mw
|
||||
parent = parent or mw
|
||||
|
@ -2,7 +2,7 @@
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
from typing import List, Optional
|
||||
|
||||
from anki.notes import NoteID
|
||||
from anki.models import NoteTypeID
|
||||
from aqt import AnkiQt, gui_hooks
|
||||
from aqt.qt import *
|
||||
from aqt.utils import TR, HelpPage, shortcut, tr
|
||||
@ -23,14 +23,16 @@ class NoteTypeChooser(QHBoxLayout):
|
||||
deleted.
|
||||
"""
|
||||
|
||||
_selected_notetype_id: NoteTypeID
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
mw: AnkiQt,
|
||||
widget: QWidget,
|
||||
starting_notetype_id: int,
|
||||
starting_notetype_id: NoteTypeID,
|
||||
on_button_activated: Optional[Callable[[], None]] = None,
|
||||
on_notetype_changed: Optional[Callable[[NoteID], None]] = None,
|
||||
on_notetype_changed: Optional[Callable[[NoteTypeID], None]] = None,
|
||||
show_prefix_label: bool = True,
|
||||
) -> None:
|
||||
QHBoxLayout.__init__(self)
|
||||
@ -42,7 +44,7 @@ class NoteTypeChooser(QHBoxLayout):
|
||||
self.on_button_activated = self.choose_notetype
|
||||
self._setup_ui(show_label=show_prefix_label)
|
||||
gui_hooks.state_did_reset.append(self.reset_state)
|
||||
self._selected_notetype_id = 0
|
||||
self._selected_notetype_id = NoteTypeID(0)
|
||||
# triggers UI update; avoid firing changed hook on startup
|
||||
self.on_notetype_changed = None
|
||||
self.selected_notetype_id = starting_notetype_id
|
||||
@ -119,7 +121,7 @@ class NoteTypeChooser(QHBoxLayout):
|
||||
self.selected_notetype_id = id
|
||||
|
||||
@property
|
||||
def selected_notetype_id(self) -> int:
|
||||
def selected_notetype_id(self) -> NoteTypeID:
|
||||
# theoretically this should not be necessary, as we're listening to
|
||||
# resets
|
||||
self._ensure_selected_notetype_valid()
|
||||
@ -127,7 +129,7 @@ class NoteTypeChooser(QHBoxLayout):
|
||||
return self._selected_notetype_id
|
||||
|
||||
@selected_notetype_id.setter
|
||||
def selected_notetype_id(self, id: int) -> None:
|
||||
def selected_notetype_id(self, id: NoteTypeID) -> None:
|
||||
if id != self._selected_notetype_id:
|
||||
self._selected_notetype_id = id
|
||||
self._ensure_selected_notetype_valid()
|
||||
@ -140,7 +142,9 @@ class NoteTypeChooser(QHBoxLayout):
|
||||
|
||||
def _ensure_selected_notetype_valid(self) -> None:
|
||||
if not self.mw.col.models.get(self._selected_notetype_id):
|
||||
self.selected_notetype_id = self.mw.col.models.all_names_and_ids()[0].id
|
||||
self.selected_notetype_id = NoteTypeID(
|
||||
self.mw.col.models.all_names_and_ids()[0].id
|
||||
)
|
||||
|
||||
def _update_button_label(self) -> None:
|
||||
self.button.setText(self.selected_notetype_name().replace("&", "&&"))
|
||||
|
@ -9,6 +9,7 @@ from typing import Dict, Iterable, List, Optional, Tuple, cast
|
||||
import aqt
|
||||
from anki.collection import Config, OpChanges, SearchJoiner, SearchNode
|
||||
from anki.decks import DeckID, DeckTreeNode
|
||||
from anki.models import NoteTypeID
|
||||
from anki.notes import Note
|
||||
from anki.tags import TagTreeNode
|
||||
from anki.types import assert_exhaustive
|
||||
@ -1291,11 +1292,14 @@ class SidebarTreeView(QTreeView):
|
||||
|
||||
def manage_notetype(self, item: SidebarItem) -> None:
|
||||
Models(
|
||||
self.mw, parent=self.browser, fromMain=True, selected_notetype_id=item.id
|
||||
self.mw,
|
||||
parent=self.browser,
|
||||
fromMain=True,
|
||||
selected_notetype_id=NoteTypeID(item.id),
|
||||
)
|
||||
|
||||
def manage_template(self, item: SidebarItem) -> None:
|
||||
note = Note(self.col, self.col.models.get(item._parent_item.id))
|
||||
note = Note(self.col, self.col.models.get(NoteTypeID(item._parent_item.id)))
|
||||
CardLayout(self.mw, note, ord=item.id, parent=self, fill_empty=True)
|
||||
|
||||
# Helpers
|
||||
|
Loading…
Reference in New Issue
Block a user