diff --git a/pylib/anki/cards.py b/pylib/anki/cards.py index 480986ebc..9c35b0c4e 100644 --- a/pylib/anki/cards.py +++ b/pylib/anki/cards.py @@ -36,7 +36,7 @@ class Card: def __init__( self, col: anki.collection._Collection, id: Optional[int] = None ) -> None: - self.col = col + self.col = col.weakref() self.timerStarted = None self._render_output: Optional[anki.template.TemplateRenderOutput] = None self._note = None diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index a7d159c73..01f96fa8c 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -1,6 +1,8 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +from __future__ import annotations + import copy import datetime import json @@ -12,6 +14,7 @@ import stat import time import traceback import unicodedata +import weakref from typing import Any, Dict, Iterable, List, Optional, Tuple, Union import anki.find @@ -114,6 +117,10 @@ 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: + "Shortcut to create a weak reference that doesn't break code completion." + return weakref.proxy(self) + # Scheduler ########################################################################## diff --git a/pylib/anki/decks.py b/pylib/anki/decks.py index e19999cea..bf1927823 100644 --- a/pylib/anki/decks.py +++ b/pylib/anki/decks.py @@ -7,7 +7,6 @@ import copy import json import operator import unicodedata -import weakref from typing import Any, Dict, List, Optional, Set, Tuple, Union import anki # pylint: disable=unused-import @@ -102,7 +101,7 @@ class DeckManager: ############################################################# def __init__(self, col: anki.storage._Collection) -> None: - self.col = weakref.proxy(col) + self.col = col.weakref() self.decks = {} self.dconf = {} diff --git a/pylib/anki/exporting.py b/pylib/anki/exporting.py index 448ada9ed..67fd5faa6 100644 --- a/pylib/anki/exporting.py +++ b/pylib/anki/exporting.py @@ -27,7 +27,7 @@ class Exporter: did: Optional[int] = None, cids: Optional[List[int]] = None, ) -> None: - self.col = col + self.col = col.weakref() self.did = did self.cids = cids diff --git a/pylib/anki/find.py b/pylib/anki/find.py index 3faa6fe2a..2067c3df6 100644 --- a/pylib/anki/find.py +++ b/pylib/anki/find.py @@ -1,5 +1,6 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + from __future__ import annotations import re @@ -28,7 +29,7 @@ if TYPE_CHECKING: class Finder: def __init__(self, col: Optional[_Collection]) -> None: - self.col = col + self.col = col.weakref() self.search = dict( added=self._findAdded, card=self._findTemplate, diff --git a/pylib/anki/importing/base.py b/pylib/anki/importing/base.py index ccde5929c..1eee9e7c8 100644 --- a/pylib/anki/importing/base.py +++ b/pylib/anki/importing/base.py @@ -19,7 +19,7 @@ class Importer: def __init__(self, col: _Collection, file: str) -> None: self.file = file self.log: List[str] = [] - self.col = col + self.col = col.weakref() self.total = 0 self.dst = None diff --git a/pylib/anki/media.py b/pylib/anki/media.py index 96ef0e846..5d100a6a8 100644 --- a/pylib/anki/media.py +++ b/pylib/anki/media.py @@ -10,7 +10,6 @@ import time import urllib.error import urllib.parse import urllib.request -import weakref from typing import Any, Callable, List, Optional, Tuple, Union import anki @@ -43,7 +42,7 @@ class MediaManager: regexps = soundRegexps + imgRegexps def __init__(self, col: anki.storage._Collection, server: bool) -> None: - self.col = weakref.proxy(col) + self.col = col.weakref() if server: self._dir = None return diff --git a/pylib/anki/models.py b/pylib/anki/models.py index d74973142..21f27b649 100644 --- a/pylib/anki/models.py +++ b/pylib/anki/models.py @@ -7,7 +7,6 @@ import copy import json import re import time -import weakref from typing import Any, Callable, Dict, List, Optional, Tuple, Union import anki # pylint: disable=unused-import @@ -92,7 +91,7 @@ class ModelManager: ############################################################# def __init__(self, col: anki.storage._Collection) -> None: - self.col = weakref.proxy(col) + self.col = col.weakref() self.models = {} self.changed = False diff --git a/pylib/anki/notes.py b/pylib/anki/notes.py index aed366aee..5d8a3ddee 100644 --- a/pylib/anki/notes.py +++ b/pylib/anki/notes.py @@ -40,7 +40,7 @@ class Note: id: Optional[int] = None, ) -> None: assert not (model and id) - self.col = col + self.col = col.weakref() self.newlyAdded = False if id: self.id = id diff --git a/pylib/anki/sched.py b/pylib/anki/sched.py index 258c48994..91d531bb8 100644 --- a/pylib/anki/sched.py +++ b/pylib/anki/sched.py @@ -6,7 +6,6 @@ from __future__ import annotations import itertools import random import time -import weakref from heapq import * from operator import itemgetter from typing import Any, Dict, List, Optional, Tuple, Union @@ -32,7 +31,7 @@ class Scheduler(V2): def __init__( # pylint: disable=super-init-not-called self, col: anki.storage._Collection ) -> None: - self.col = weakref.proxy(col) + self.col = col.weakref() self.queueLimit = 50 self.reportLimit = 1000 self.dynReportLimit = 99999 diff --git a/pylib/anki/schedv2.py b/pylib/anki/schedv2.py index 6a7a3c4cb..68275a892 100644 --- a/pylib/anki/schedv2.py +++ b/pylib/anki/schedv2.py @@ -7,7 +7,6 @@ import datetime import itertools import random import time -import weakref from heapq import * from operator import itemgetter @@ -38,7 +37,7 @@ class Scheduler: revCount: int def __init__(self, col: anki.storage._Collection) -> None: - self.col = weakref.proxy(col) + self.col = col.weakref() self.queueLimit = 50 self.reportLimit = 1000 self.dynReportLimit = 99999 diff --git a/pylib/anki/stats.py b/pylib/anki/stats.py index cd21d7018..cbbf4f20d 100644 --- a/pylib/anki/stats.py +++ b/pylib/anki/stats.py @@ -25,7 +25,7 @@ PERIOD_LIFE = 2 class CardStats: def __init__(self, col: anki.storage._Collection, card: anki.cards.Card) -> None: - self.col = col + self.col = col.weakref() self.card = card self.txt = "" @@ -107,7 +107,7 @@ colSusp = "#ff0" class CollectionStats: def __init__(self, col: anki.storage._Collection) -> None: - self.col = col + self.col = col.weakref() self._stats = None self.type = PERIOD_MONTH self.width = 600 diff --git a/pylib/anki/sync.py b/pylib/anki/sync.py index 41d138961..10faaa66d 100644 --- a/pylib/anki/sync.py +++ b/pylib/anki/sync.py @@ -35,7 +35,7 @@ class Syncer: cursor: Optional[sqlite3.Cursor] def __init__(self, col: anki.storage._Collection, server=None) -> None: - self.col = col + self.col = col.weakref() self.server = server # these are set later; provide dummy values for type checking @@ -638,7 +638,7 @@ class FullSyncer(HttpSyncer): self.postVars = dict( k=self.hkey, v="ankidesktop,%s,%s" % (anki.version, platDesc()), ) - self.col = col + self.col = col.weakref() def download(self) -> Optional[str]: hooks.sync_stage_did_change("download") diff --git a/pylib/anki/tags.py b/pylib/anki/tags.py index 6085fa7b5..9f643a1e3 100644 --- a/pylib/anki/tags.py +++ b/pylib/anki/tags.py @@ -13,7 +13,6 @@ from __future__ import annotations import json import re -import weakref from typing import Callable, Collection, Dict, List, Optional, Tuple import anki # pylint: disable=unused-import @@ -27,7 +26,7 @@ class TagManager: ############################################################# def __init__(self, col: anki.storage._Collection) -> None: - self.col = weakref.proxy(col) + self.col = col.weakref() self.tags: Dict[str, int] = {} def load(self, json_: str) -> None: diff --git a/pylib/tests/test_find.py b/pylib/tests/test_find.py index 98ccc20a4..3ad041e6b 100644 --- a/pylib/tests/test_find.py +++ b/pylib/tests/test_find.py @@ -6,8 +6,13 @@ from anki.find import Finder from tests.shared import getEmptyCol +class DummyCollection: + def weakref(self): + return None + + def test_parse(): - f = Finder(None) + f = Finder(DummyCollection()) assert f._tokenize("hello world") == ["hello", "world"] assert f._tokenize("hello world") == ["hello", "world"] assert f._tokenize("one -two") == ["one", "-", "two"]