storage->collection

This commit is contained in:
Damien Elmes 2020-05-20 17:56:52 +10:00
parent c49c378296
commit 50fdf9b03d
29 changed files with 82 additions and 92 deletions

View file

@ -4,7 +4,7 @@
import sys
from anki.buildinfo import version
from anki.storage import Collection
from anki.collection import Collection
if sys.version_info[0] < 3 or sys.version_info[1] < 7:
raise Exception("Anki requires Python 3.7+")

View file

@ -33,7 +33,9 @@ class Card:
lastIvl: int
ord: int
def __init__(self, col: anki.storage._Collection, id: Optional[int] = None) -> None:
def __init__(
self, col: anki.collection.Collection, id: Optional[int] = None
) -> None:
self.col = col.weakref()
self.timerStarted = None
self._render_output: Optional[anki.template.TemplateRenderOutput] = None

View file

@ -33,21 +33,19 @@ from anki.tags import TagManager
from anki.utils import devMode, ids2str, intTime
# this is initialized by storage.Collection
class _Collection:
db: Optional[DBProxy]
class Collection:
sched: Union[V1Scheduler, V2Scheduler]
_undo: List[Any]
def __init__(
self,
path: str,
backend: Optional[RustBackend],
backend: Optional[RustBackend] = None,
server: bool = False,
log: bool = False,
) -> None:
self.backend = backend or RustBackend(server=server)
self.db = None
self.db: Optional[DBProxy] = None
self._should_log = log
self.server = server
self.path = os.path.abspath(path)
@ -70,7 +68,7 @@ class _Collection:
def tr(self, key: TR, **kwargs: Union[str, int, float]) -> str:
return self.backend.translate(key, **kwargs)
def weakref(self) -> anki.storage._Collection:
def weakref(self) -> Collection:
"Shortcut to create a weak reference that doesn't break code completion."
return weakref.proxy(self)
@ -654,3 +652,7 @@ select id from notes where mid = ?) limit 1"""
self.usn(),
intTime(),
)
# legacy name
_Collection = Collection

View file

@ -26,7 +26,7 @@ import anki
class ConfigManager:
def __init__(self, col: anki.storage._Collection):
def __init__(self, col: anki.collection.Collection):
self.col = col.weakref()
def get_immutable(self, key: str) -> Any:

View file

@ -21,7 +21,7 @@ defaultDynamicDeck = 1
class DecksDictProxy:
def __init__(self, col: anki.storage._Collection):
def __init__(self, col: anki.collection.Collection):
self._col = col.weakref()
def _warn(self):
@ -60,7 +60,7 @@ class DeckManager:
# Registry save/load
#############################################################
def __init__(self, col: anki.storage._Collection) -> None:
def __init__(self, col: anki.collection.Collection) -> None:
self.col = col.weakref()
self.decks = DecksDictProxy(col)

View file

@ -12,9 +12,8 @@ from typing import Any, Dict, List, Optional, Tuple, Union
from zipfile import ZipFile
from anki import hooks
from anki.collection import _Collection
from anki.collection import Collection
from anki.lang import _
from anki.storage import Collection
from anki.utils import ids2str, namedtmp, splitFields, stripHTML
@ -23,7 +22,7 @@ class Exporter:
def __init__(
self,
col: _Collection,
col: Collection,
did: Optional[int] = None,
cids: Optional[List[int]] = None,
) -> None:
@ -122,7 +121,7 @@ class TextNoteExporter(Exporter):
includeTags = True
includeHTML = True
def __init__(self, col: _Collection) -> None:
def __init__(self, col: Collection) -> None:
Exporter.__init__(self, col)
self.includeID = False
@ -164,7 +163,7 @@ class AnkiExporter(Exporter):
includeSched: Union[bool, None] = False
includeMedia = True
def __init__(self, col: _Collection) -> None:
def __init__(self, col: Collection) -> None:
Exporter.__init__(self, col)
def deckIds(self) -> List[int]:
@ -311,7 +310,7 @@ class AnkiPackageExporter(AnkiExporter):
key = _("Anki Deck Package")
ext = ".apkg"
def __init__(self, col: _Collection) -> None:
def __init__(self, col: Collection) -> None:
AnkiExporter.__init__(self, col)
def exportInto(self, path: str) -> None:

View file

@ -9,11 +9,11 @@ from anki.hooks import *
from anki.utils import ids2str, splitFields, stripHTMLMedia
if TYPE_CHECKING:
from anki.collection import _Collection
from anki.collection import Collection
class Finder:
def __init__(self, col: Optional[_Collection]) -> None:
def __init__(self, col: Optional[Collection]) -> None:
self.col = col.weakref()
print("Finder() is deprecated, please use col.find_cards() or .find_notes()")
@ -29,7 +29,7 @@ class Finder:
def findReplace(
col: _Collection,
col: Collection,
nids: List[int],
src: str,
dst: str,
@ -41,7 +41,7 @@ def findReplace(
return col.backend.find_and_replace(nids, src, dst, regex, fold, field)
def fieldNamesForNotes(col: _Collection, nids: List[int]) -> List[str]:
def fieldNamesForNotes(col: Collection, nids: List[int]) -> List[str]:
return list(col.backend.field_names_for_note_ids(nids))
@ -61,7 +61,7 @@ def fieldNames(col, downcase=True) -> List:
# returns array of ("dupestr", [nids])
def findDupes(
col: _Collection, fieldName: str, search: str = ""
col: Collection, fieldName: str, search: str = ""
) -> List[Tuple[Any, List]]:
# limit search to notes with applicable field name
if search:

View file

@ -358,21 +358,21 @@ note_will_flush = _NoteWillFlushHook()
class _NotesWillBeDeletedHook:
_hooks: List[Callable[["anki.storage._Collection", List[int]], None]] = []
_hooks: List[Callable[["anki.collection.Collection", List[int]], None]] = []
def append(
self, cb: Callable[["anki.storage._Collection", List[int]], None]
self, cb: Callable[["anki.collection.Collection", List[int]], None]
) -> None:
"""(col: anki.storage._Collection, ids: List[int])"""
self._hooks.append(cb)
def remove(
self, cb: Callable[["anki.storage._Collection", List[int]], None]
self, cb: Callable[["anki.collection.Collection", List[int]], None]
) -> None:
if cb in self._hooks:
self._hooks.remove(cb)
def __call__(self, col: anki.storage._Collection, ids: List[int]) -> None:
def __call__(self, col: anki.collection.Collection, ids: List[int]) -> None:
for hook in self._hooks:
try:
hook(col, ids)

View file

@ -5,12 +5,11 @@ import os
import unicodedata
from typing import Any, Dict, List, Optional, Tuple
from anki.collection import _Collection
from anki.collection import Collection
from anki.consts import *
from anki.decks import DeckManager
from anki.importing.base import Importer
from anki.lang import _
from anki.storage import Collection
from anki.utils import intTime, joinFields, splitFields
GUID = 1
@ -23,10 +22,10 @@ class Anki2Importer(Importer):
needMapper = False
deckPrefix: Optional[str] = None
allowUpdate = True
src: _Collection
dst: _Collection
src: Collection
dst: Collection
def __init__(self, col: _Collection, file: str) -> None:
def __init__(self, col: Collection, file: str) -> None:
super().__init__(col, file)
# set later, defined here for typechecking

View file

@ -3,7 +3,7 @@
from typing import Any, List, Optional
from anki.collection import _Collection
from anki.collection import Collection
from anki.utils import maxID
# Base importer
@ -14,9 +14,9 @@ class Importer:
needMapper = False
needDelimiter = False
dst: Optional[_Collection]
dst: Optional[Collection]
def __init__(self, col: _Collection, file: str) -> None:
def __init__(self, col: Collection, file: str) -> None:
self.file = file
self.log: List[str] = []
self.col = col.weakref()

View file

@ -5,7 +5,7 @@ import csv
import re
from typing import Any, List, Optional, TextIO, Union
from anki.collection import _Collection
from anki.collection import Collection
from anki.importing.noteimp import ForeignNote, NoteImporter
from anki.lang import _
@ -15,7 +15,7 @@ class TextImporter(NoteImporter):
needDelimiter = True
patterns = "\t|,;:"
def __init__(self, col: _Collection, file: str) -> None:
def __init__(self, col: Collection, file: str) -> None:
NoteImporter.__init__(self, col, file)
self.lines = None
self.fileobj: Optional[TextIO] = None

View file

@ -4,7 +4,7 @@
import html
from typing import Dict, List, Optional, Tuple, Union
from anki.collection import _Collection
from anki.collection import Collection
from anki.consts import NEW_CARDS_RANDOM, STARTING_FACTOR
from anki.importing.base import Importer
from anki.lang import _, ngettext
@ -68,7 +68,7 @@ class NoteImporter(Importer):
mapping: Optional[List[str]]
tagModified: Optional[str]
def __init__(self, col: _Collection, file: str) -> None:
def __init__(self, col: Collection, file: str) -> None:
Importer.__init__(self, col, file)
self.model = col.models.current()
self.mapping = None

View file

@ -12,7 +12,7 @@ from typing import List, Optional, Union
from xml.dom import minidom
from xml.dom.minidom import Element, Text
from anki.collection import _Collection
from anki.collection import Collection
from anki.importing.noteimp import ForeignCard, ForeignNote, NoteImporter
from anki.lang import _, ngettext
from anki.stdmodels import addBasicModel
@ -83,7 +83,7 @@ class SupermemoXmlImporter(NoteImporter):
Code should be upgrade to support importing of SM2006 exports.
"""
def __init__(self, col: _Collection, file: str) -> None:
def __init__(self, col: Collection, file: str) -> None:
"""Initialize internal varables.
Pameters to be exposed to GUI are stored in self.META"""
NoteImporter.__init__(self, col, file)

View file

@ -42,7 +42,7 @@ def on_card_did_render(
output.answer_text = render_latex(output.answer_text, ctx.note_type(), ctx.col())
def render_latex(html: str, model: NoteType, col: anki.storage._Collection) -> str:
def render_latex(html: str, model: NoteType, col: anki.collection.Collection) -> str:
"Convert embedded latex tags in text to image links."
html, err = render_latex_returning_errors(html, model, col)
if err:
@ -53,7 +53,7 @@ def render_latex(html: str, model: NoteType, col: anki.storage._Collection) -> s
def render_latex_returning_errors(
html: str,
model: NoteType,
col: anki.storage._Collection,
col: anki.collection.Collection,
expand_clozes: bool = False,
) -> Tuple[str, List[str]]:
"""Returns (text, errors).
@ -80,7 +80,7 @@ def render_latex_returning_errors(
def _save_latex_image(
col: anki.storage._Collection,
col: anki.collection.Collection,
extracted: ExtractedLatex,
header: str,
footer: str,

View file

@ -41,7 +41,7 @@ class MediaManager:
]
regexps = soundRegexps + imgRegexps
def __init__(self, col: anki.storage._Collection, server: bool) -> None:
def __init__(self, col: anki.collection.Collection, server: bool) -> None:
self.col = col.weakref()
if server:
self._dir = None

View file

@ -22,7 +22,7 @@ Template = Dict[str, Union[str, int, None]]
class ModelsDictProxy:
def __init__(self, col: anki.storage._Collection):
def __init__(self, col: anki.collection.Collection):
self._col = col.weakref()
def _warn(self):
@ -61,7 +61,7 @@ class ModelManager:
# Saving/loading registry
#############################################################
def __init__(self, col: anki.storage._Collection) -> None:
def __init__(self, col: anki.collection.Collection) -> None:
self.col = col.weakref()
self.models = ModelsDictProxy(col)
# do not access this directly!

View file

@ -19,7 +19,7 @@ class Note:
def __init__(
self,
col: anki.storage._Collection,
col: anki.collection.Collection,
model: Optional[NoteType] = None,
id: Optional[int] = None,
) -> None:

View file

@ -27,7 +27,7 @@ class Scheduler(V2):
_burySiblingsOnAnswer = True
def __init__( # pylint: disable=super-init-not-called
self, col: anki.storage._Collection
self, col: anki.collection.Collection
) -> None:
self.col = col.weakref()
self.queueLimit = 50

View file

@ -6,8 +6,6 @@ from __future__ import annotations
import random
import time
from heapq import *
# from anki.collection import _Collection
from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, Union
import anki # pylint: disable=unused-import
@ -33,7 +31,7 @@ class Scheduler:
_burySiblingsOnAnswer = True
revCount: int
def __init__(self, col: anki.storage._Collection) -> None:
def __init__(self, col: anki.collection.Collection) -> None:
self.col = col.weakref()
self.queueLimit = 50
self.reportLimit = 1000

View file

@ -24,7 +24,7 @@ PERIOD_LIFE = 2
class CardStats:
def __init__(self, col: anki.storage._Collection, card: anki.cards.Card) -> None:
def __init__(self, col: anki.collection.Collection, card: anki.cards.Card) -> None:
if col:
self.col = col.weakref()
self.card = card
@ -108,7 +108,7 @@ colSusp = "#ff0"
class CollectionStats:
def __init__(self, col: anki.storage._Collection) -> None:
def __init__(self, col: anki.collection.Collection) -> None:
self.col = col.weakref()
self._stats = None
self.type = PERIOD_MONTH

View file

@ -3,7 +3,7 @@
from typing import Callable, List, Tuple
from anki.collection import _Collection
from anki.collection import Collection
from anki.models import NoteType
from anki.rsbackend import StockNoteType
@ -12,38 +12,38 @@ from anki.rsbackend import StockNoteType
models: List[Tuple] = []
def add_stock_notetype(col: _Collection, kind: StockNoteType) -> NoteType:
def add_stock_notetype(col: Collection, kind: StockNoteType) -> NoteType:
m = col.backend.get_stock_notetype_legacy(kind)
col.models.add(m)
return m
def addBasicModel(col: _Collection) -> NoteType:
def addBasicModel(col: Collection) -> NoteType:
return add_stock_notetype(col, StockNoteType.STOCK_NOTE_TYPE_BASIC)
def addBasicTypingModel(col: _Collection) -> NoteType:
def addBasicTypingModel(col: Collection) -> NoteType:
return add_stock_notetype(col, StockNoteType.STOCK_NOTE_TYPE_BASIC_TYPING)
def addForwardReverse(col: _Collection) -> NoteType:
def addForwardReverse(col: Collection) -> NoteType:
return add_stock_notetype(col, StockNoteType.STOCK_NOTE_TYPE_BASIC_AND_REVERSED)
def addForwardOptionalReverse(col: _Collection) -> NoteType:
def addForwardOptionalReverse(col: Collection) -> NoteType:
return add_stock_notetype(
col, StockNoteType.STOCK_NOTE_TYPE_BASIC_OPTIONAL_REVERSED
)
def addClozeModel(col: _Collection) -> NoteType:
def addClozeModel(col: Collection) -> NoteType:
return add_stock_notetype(col, StockNoteType.STOCK_NOTE_TYPE_CLOZE)
def get_stock_notetypes(
col: _Collection,
) -> List[Tuple[str, Callable[[_Collection], NoteType]]]:
out: List[Tuple[str, Callable[[_Collection], NoteType]]] = []
col: Collection,
) -> List[Tuple[str, Callable[[Collection], NoteType]]]:
out: List[Tuple[str, Callable[[Collection], NoteType]]] = []
# add standard
for (kind, func) in [
(StockNoteType.STOCK_NOTE_TYPE_BASIC, addBasicModel),

View file

@ -1,17 +1,8 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from typing import Optional
# Legacy code expects to find Collection in this module.
from anki.collection import _Collection
from anki.rsbackend import RustBackend
from anki.collection import Collection
def Collection(
path: str,
backend: Optional[RustBackend] = None,
server: bool = False,
log: bool = False,
) -> _Collection:
"Open a new or existing collection. Path must be unicode."
return _Collection(path, backend, server, log)
_Collection = Collection

View file

@ -33,7 +33,7 @@ class UnexpectedSchemaChange(Exception):
class Syncer:
chunkRows: Optional[List[Sequence]]
def __init__(self, col: anki.storage._Collection, server=None) -> None:
def __init__(self, col: anki.collection.Collection, server=None) -> None:
self.col = col.weakref()
self.server = server

View file

@ -19,7 +19,7 @@ from anki.utils import ids2str
class TagManager:
def __init__(self, col: anki.storage._Collection) -> None:
def __init__(self, col: anki.collection.Collection) -> None:
self.col = col.weakref()
# all tags

View file

@ -74,7 +74,7 @@ class TemplateRenderContext:
def __init__(
self,
col: anki.storage._Collection,
col: anki.collection.Collection,
card: Card,
note: Note,
browser: bool = False,
@ -97,7 +97,7 @@ class TemplateRenderContext:
# hooks, you can insert it into this dictionary
self.extra_state: Dict[str, Any] = {}
def col(self) -> anki.storage._Collection:
def col(self) -> anki.collection.Collection:
return self._col
# legacy

View file

@ -16,7 +16,7 @@ import aqt
import aqt.forms
from anki import hooks
from anki.cards import Card
from anki.collection import _Collection
from anki.collection import Collection
from anki.consts import *
from anki.lang import _, ngettext
from anki.models import NoteType
@ -569,7 +569,7 @@ class SidebarModel(QAbstractItemModel):
class Browser(QMainWindow):
model: DataModel
mw: AnkiQt
col: _Collection
col: Collection
editor: Optional[Editor]
def __init__(self, mw: AnkiQt) -> None:

View file

@ -702,17 +702,17 @@ card_will_show = _CardWillShowFilter()
class _CollectionDidLoadHook:
_hooks: List[Callable[["anki.storage._Collection"], None]] = []
_hooks: List[Callable[["anki.collection.Collection"], None]] = []
def append(self, cb: Callable[["anki.storage._Collection"], None]) -> None:
def append(self, cb: Callable[["anki.collection.Collection"], None]) -> None:
"""(col: anki.storage._Collection)"""
self._hooks.append(cb)
def remove(self, cb: Callable[["anki.storage._Collection"], None]) -> None:
def remove(self, cb: Callable[["anki.collection.Collection"], None]) -> None:
if cb in self._hooks:
self._hooks.remove(cb)
def __call__(self, col: anki.storage._Collection) -> None:
def __call__(self, col: anki.collection.Collection) -> None:
for hook in self._hooks:
try:
hook(col)

View file

@ -27,12 +27,11 @@ import aqt.stats
import aqt.toolbar
import aqt.webview
from anki import hooks
from anki.collection import _Collection
from anki.collection import Collection
from anki.hooks import runHook
from anki.lang import _, ngettext
from anki.rsbackend import RustBackend
from anki.sound import AVTag, SoundOrVideoTag
from anki.storage import Collection
from anki.utils import devMode, ids2str, intTime, isMac, isWin, splitFields
from aqt import gui_hooks
from aqt.addons import DownloadLogEntry, check_and_prompt_for_updates, show_log_to_user
@ -71,7 +70,7 @@ class ResetRequired:
class AnkiQt(QMainWindow):
col: _Collection
col: Collection
pm: ProfileManagerType
web: aqt.webview.AnkiWebView
bottomWeb: aqt.webview.AnkiWebView
@ -88,7 +87,7 @@ class AnkiQt(QMainWindow):
self.backend = backend
self.state = "startup"
self.opts = opts
self.col: Optional[_Collection] = None
self.col: Optional[Collection] = None
self.taskman = TaskManager(self)
self.media_syncer = MediaSyncer(self)
aqt.mw = self
@ -1265,7 +1264,7 @@ and if the problem comes up again, please ask on the support site."""
# Log note deletion
##########################################################################
def onRemNotes(self, col: _Collection, nids: List[int]) -> None:
def onRemNotes(self, col: Collection, nids: List[int]) -> None:
path = os.path.join(self.pm.profileFolder(), "deleted.txt")
existed = os.path.exists(path)
with open(path, "ab") as f:

View file

@ -9,7 +9,7 @@ import threading
from http import HTTPStatus
from typing import Optional
from anki.collection import _Collection
from anki.collection import Collection
from anki.utils import devMode
from aqt.qt import *
from aqt.utils import aqt_data_folder
@ -74,7 +74,7 @@ class MediaServer(threading.Thread):
class RequestHandler(http.server.SimpleHTTPRequestHandler):
timeout = 1
mw: Optional[_Collection] = None
mw: Optional[Collection] = None
def do_GET(self):
f = self.send_head()