From 62c23c6816adf912776b9378c008a52bb50b2e8d Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 27 Jun 2021 14:02:48 +1000 Subject: [PATCH] PEP8 decks.py --- pylib/anki/_legacy.py | 14 +- pylib/anki/cards.py | 10 +- pylib/anki/decks.py | 290 +++++++++++++++----------------- pylib/anki/exporting.py | 2 +- pylib/anki/importing/anki2.py | 2 +- pylib/anki/importing/noteimp.py | 2 +- pylib/anki/scheduler/base.py | 4 +- pylib/anki/scheduler/legacy.py | 2 +- pylib/anki/scheduler/v1.py | 4 +- pylib/anki/scheduler/v2.py | 12 +- pylib/tests/test_decks.py | 53 ------ pylib/tests/test_exporting.py | 6 +- pylib/tests/test_schedv1.py | 8 +- pylib/tests/test_schedv2.py | 18 +- qt/aqt/customstudy.py | 2 +- qt/aqt/deckchooser.py | 2 +- qt/aqt/deckconf.py | 10 +- 17 files changed, 188 insertions(+), 253 deletions(-) diff --git a/pylib/anki/_legacy.py b/pylib/anki/_legacy.py index b0b7d2293..d20ea3dc4 100644 --- a/pylib/anki/_legacy.py +++ b/pylib/anki/_legacy.py @@ -27,10 +27,14 @@ def partial_path(full_path: str, components: int) -> str: return os.path.join(*path.parts[-components:]) -def _print_deprecation_warning(old: str, doc: str) -> None: - path, linenum, fn, y = traceback.extract_stack(limit=5)[2] +def print_deprecation_warning(msg: str, frame: int = 2) -> None: + path, linenum, fn, y = traceback.extract_stack(limit=5)[frame] path = partial_path(path, components=3) - print(f"{path}:{linenum}:{old} is deprecated: {doc}") + print(f"{path}:{linenum}:{msg}") + + +def _print_warning(old: str, doc: str) -> None: + return print_deprecation_warning(f"{old} is deprecated: {doc}", frame=1) class DeprecatedNamesMixin: @@ -48,7 +52,7 @@ class DeprecatedNamesMixin: raise AttributeError out = getattr(self, remapped) - _print_deprecation_warning(f"'{name}'", f"please use '{remapped}'") + _print_warning(f"'{name}'", f"please use '{remapped}'") return out @@ -75,7 +79,7 @@ def deprecated(replaced_by: Optional[Callable] = None, info: str = "") -> Callab else: doc = info - _print_deprecation_warning(f"{func.__name__}()", doc) + _print_warning(f"{func.__name__}()", doc) return func(*args, **kwargs) diff --git a/pylib/anki/cards.py b/pylib/anki/cards.py index bd227bdcf..60f15c42b 100644 --- a/pylib/anki/cards.py +++ b/pylib/anki/cards.py @@ -170,19 +170,21 @@ class Card(DeprecatedNamesMixin): def time_limit(self) -> int: "Time limit for answering in milliseconds." - conf = self.col.decks.confForDid(self.current_deck_id()) + conf = self.col.decks.config_dict_for_deck_id(self.current_deck_id()) return conf["maxTaken"] * 1000 def should_show_timer(self) -> bool: - conf = self.col.decks.confForDid(self.current_deck_id()) + conf = self.col.decks.config_dict_for_deck_id(self.current_deck_id()) return conf["timer"] def replay_question_audio_on_answer_side(self) -> bool: - conf = self.col.decks.confForDid(self.current_deck_id()) + conf = self.col.decks.config_dict_for_deck_id(self.current_deck_id()) return conf.get("replayq", True) def autoplay(self) -> bool: - return self.col.decks.confForDid(self.current_deck_id())["autoplay"] + return self.col.decks.config_dict_for_deck_id(self.current_deck_id())[ + "autoplay" + ] def time_taken(self) -> int: "Time taken to answer card, in integer MS." diff --git a/pylib/anki/decks.py b/pylib/anki/decks.py index af5217de8..4bcbd8aaf 100644 --- a/pylib/anki/decks.py +++ b/pylib/anki/decks.py @@ -1,17 +1,30 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +# pylint: enable=invalid-name + from __future__ import annotations import copy -import pprint -import sys -import traceback -from typing import Any, Dict, Iterable, List, NewType, Optional, Sequence, Tuple, Union +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Iterable, + List, + NewType, + Optional, + Sequence, + Tuple, + Union, + no_type_check, +) + +if TYPE_CHECKING: + import anki -import anki # pylint: disable=unused-import import anki._backend.backend_pb2 as _pb -from anki._legacy import deprecated +from anki._legacy import DeprecatedNamesMixin, deprecated, print_deprecation_warning from anki.cards import CardId from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId from anki.consts import * @@ -26,10 +39,6 @@ DeckCollapseScope = _pb.SetDeckCollapsedRequest.Scope DeckConfigsForUpdate = _pb.DeckConfigsForUpdate UpdateDeckConfigs = _pb.UpdateDeckConfigsRequest -# legacy code may pass this in as the type argument to .id() -defaultDeck = 0 -defaultDynamicDeck = 1 - # type aliases until we can move away from dicts DeckDict = Dict[str, Any] DeckConfigDict = Dict[str, Any] @@ -46,8 +55,9 @@ class DecksDictProxy: self._col = col.weakref() def _warn(self) -> None: - traceback.print_stack(file=sys.stdout) - print("add-on should use methods on col.decks, not col.decks.decks dict") + print_deprecation_warning( + "add-on should use methods on col.decks, not col.decks.decks dict" + ) def __getitem__(self, item: Any) -> Any: self._warn() @@ -78,7 +88,7 @@ class DecksDictProxy: return self._col.decks.have(item) -class DeckManager: +class DeckManager(DeprecatedNamesMixin): # Registry save/load ############################################################# @@ -86,27 +96,18 @@ class DeckManager: self.col = col.weakref() self.decks = DecksDictProxy(col) - def save(self, g: Union[DeckDict, DeckConfigDict] = None) -> None: + def save(self, deck_or_config: Union[DeckDict, DeckConfigDict] = None) -> None: "Can be called with either a deck or a deck configuration." - if not g: + if not deck_or_config: print("col.decks.save() should be passed the changed deck") return # deck conf? - if "maxTaken" in g: - self.update_config(g) + if "maxTaken" in deck_or_config: + self.update_config(deck_or_config) return else: - self.update(g, preserve_usn=False) - - # legacy - def flush(self) -> None: - pass - - def __repr__(self) -> str: - d = dict(self.__dict__) - del d["col"] - return f"{super().__repr__()} {pprint.pformat(d, width=300)}" + self.update(deck_or_config, preserve_usn=False) # Deck save/load ############################################################# @@ -146,14 +147,6 @@ class DeckManager: def remove(self, dids: Sequence[DeckId]) -> OpChangesWithCount: return self.col._backend.remove_decks(dids) - @deprecated(replaced_by=remove) - def rem(self, did: DeckId, cardsToo: bool = True, childrenToo: bool = True) -> None: - "Remove the deck. If cardsToo, delete any cards inside." - if isinstance(did, str): - did = int(did) - assert cardsToo and childrenToo - self.remove([did]) - def all_names_and_ids( self, skip_empty_default: bool = False, include_filtered: bool = True ) -> Sequence[DeckNameId]: @@ -211,19 +204,6 @@ class DeckManager: "All decks. Expensive; prefer all_names_and_ids()" return self.get_all_legacy() - def allIds(self) -> List[str]: - print("decks.allIds() is deprecated, use .all_names_and_ids()") - return [str(x.id) for x in self.all_names_and_ids()] - - def allNames(self, dyn: bool = True, force_default: bool = True) -> List[str]: - print("decks.allNames() is deprecated, use .all_names_and_ids()") - return [ - x.name - for x in self.all_names_and_ids( - skip_empty_default=not force_default, include_filtered=dyn - ) - ] - def set_collapsed( self, deck_id: DeckId, collapsed: bool, scope: DeckCollapseScope.V ) -> OpChanges: @@ -236,7 +216,7 @@ class DeckManager: deck["collapsed"] = not deck["collapsed"] self.save(deck) - def collapseBrowser(self, did: DeckId) -> None: + def collapse_browser(self, did: DeckId) -> None: deck = self.get(did) collapsed = deck.get("browserCollapsed", False) deck["browserCollapsed"] = not collapsed @@ -275,17 +255,17 @@ class DeckManager: else: return None - def byName(self, name: str) -> Optional[DeckDict]: + def by_name(self, name: str) -> Optional[DeckDict]: """Get deck with NAME, ignoring case.""" id = self.id_for_name(name) if id: return self.get_legacy(id) return None - def update(self, g: DeckDict, preserve_usn: bool = True) -> None: + def update(self, deck: DeckDict, preserve_usn: bool = True) -> None: "Add or update an existing deck. Used for syncing and merging." - g["id"] = self.col._backend.add_or_update_deck_legacy( - deck=to_json_bytes(g), preserve_usn_and_mtime=preserve_usn + deck["id"] = self.col._backend.add_or_update_deck_legacy( + deck=to_json_bytes(deck), preserve_usn_and_mtime=preserve_usn ) def update_dict(self, deck: DeckDict) -> OpChanges: @@ -311,18 +291,6 @@ class DeckManager: deck_ids=deck_ids, new_parent=new_parent ) - # legacy - def renameForDragAndDrop( - self, - draggedDeckDid: Union[DeckId, str], - ontoDeckDid: Optional[Union[DeckId, str]], - ) -> None: - if not ontoDeckDid: - onto = 0 - else: - onto = int(ontoDeckDid) - self.reparent([DeckId(int(draggedDeckDid))], DeckId(onto)) - # Deck configurations ############################################################# @@ -336,7 +304,7 @@ class DeckManager: "A list of all deck config." return list(from_json_bytes(self.col._backend.all_deck_config_legacy())) - def confForDid(self, did: DeckId) -> DeckConfigDict: + def config_dict_for_deck_id(self, did: DeckId) -> DeckConfigDict: deck = self.get(did, default=False) assert deck if "conf" in deck: @@ -382,43 +350,36 @@ class DeckManager: def remove_config(self, id: DeckConfigId) -> None: "Remove a configuration and update all decks using it." self.col.modSchema(check=True) - for g in self.all(): + for deck in self.all(): # ignore cram decks - if "conf" not in g: + if "conf" not in deck: continue - if str(g["conf"]) == str(id): - g["conf"] = 1 - self.save(g) + if str(deck["conf"]) == str(id): + deck["conf"] = 1 + self.save(deck) self.col._backend.remove_deck_config(id) - def setConf(self, grp: DeckConfigDict, id: DeckConfigId) -> None: - grp["conf"] = id - self.save(grp) + def set_config_id_for_deck_dict(self, deck: DeckDict, id: DeckConfigId) -> None: + deck["conf"] = id + self.save(deck) - def didsForConf(self, conf: DeckConfigDict) -> List[DeckId]: + def decks_using_config(self, conf: DeckConfigDict) -> List[DeckId]: dids = [] for deck in self.all(): if "conf" in deck and deck["conf"] == conf["id"]: dids.append(deck["id"]) return dids - def restoreToDefault(self, conf: DeckConfigDict) -> None: - oldOrder = conf["new"]["order"] + def restore_to_default(self, conf: DeckConfigDict) -> None: + old_order = conf["new"]["order"] new = from_json_bytes(self.col._backend.new_deck_config_legacy()) new["id"] = conf["id"] new["name"] = conf["name"] self.update_config(new) # if it was previously randomized, re-sort - if not oldOrder: + if not old_order: self.col.sched.resortConf(new) - # legacy - allConf = all_config - getConf = get_config - updateConf = update_config - remConf = remove_config - confId = add_config_returning_id - # Deck utils ############################################################# @@ -434,14 +395,6 @@ class DeckManager: return deck["name"] return None - def setDeck(self, cids: List[CardId], did: DeckId) -> None: - self.col.db.execute( - f"update cards set did=?,usn=?,mod=? where id in {ids2str(cids)}", - did, - self.col.usn(), - intTime(), - ) - def cids(self, did: DeckId, children: bool = False) -> List[CardId]: if not children: return self.col.db.list("select id from cards where did=?", did) @@ -463,21 +416,19 @@ class DeckManager: "The currently selected deck ID." return DeckId(self.col._backend.get_current_deck().id) - # legacy - def current(self) -> DeckDict: return self.get(self.selected()) + def active(self) -> List[DeckId]: + # some add-ons assume this will always be non-empty + return self.col.sched.active_decks or [DeckId(1)] + def select(self, did: DeckId) -> None: # make sure arg is an int; legacy callers may be passing in a string did = DeckId(did) self.set_current(did) self.col.reset() - def active(self) -> List[DeckId]: - # some add-ons assume this will always be non-empty - return self.col.sched.active_decks or [DeckId(1)] - selected = get_current_id # Parents/children @@ -487,23 +438,19 @@ class DeckManager: def path(name: str) -> List[str]: return name.split("::") - _path = path - @classmethod def basename(cls, name: str) -> str: return cls.path(name)[-1] - _basename = basename - @classmethod def immediate_parent_path(cls, name: str) -> List[str]: - return cls._path(name)[:-1] + return cls.path(name)[:-1] @classmethod def immediate_parent(cls, name: str) -> Optional[str]: - pp = cls.immediate_parent_path(name) - if pp: - return "::".join(pp) + parent_path = cls.immediate_parent_path(name) + if parent_path: + return "::".join(parent_path) return None @classmethod @@ -514,9 +461,9 @@ class DeckManager: "All children of did, as (name, id)." name = self.get(did)["name"] actv = [] - for g in self.all_names_and_ids(): - if g.name.startswith(f"{name}::"): - actv.append((g.name, DeckId(g.id))) + for entry in self.all_names_and_ids(): + if entry.name.startswith(f"{name}::"): + actv.append((entry.name, DeckId(entry.id))) return actv def child_ids(self, parent_name: str) -> Iterable[DeckId]: @@ -531,38 +478,8 @@ class DeckManager: out.extend(self.child_ids(parent_name)) return out - childMapNode = Dict[DeckId, Any] - # Change to Dict[int, "DeckManager.childMapNode"] when MyPy allow recursive type - - def childDids(self, did: DeckId, childMap: DeckManager.childMapNode) -> List: - def gather(node: DeckManager.childMapNode, arr: List) -> None: - for did, child in node.items(): - arr.append(did) - gather(child, arr) - - arr: List[int] = [] - gather(childMap[did], arr) - return arr - - def childMap(self) -> DeckManager.childMapNode: - nameMap = self.nameMap() - childMap: DeckManager.childMapNode = {} - - # go through all decks, sorted by name - for deck in sorted(self.all(), key=self.key): - node: Dict[int, Any] = {} - childMap[deck["id"]] = node - - # add note to immediate parent - immediateParent = self.immediate_parent(deck["name"]) - if immediateParent is not None: - pid = nameMap[immediateParent]["id"] - childMap[pid][deck["id"]] = node - - return childMap - def parents( - self, did: DeckId, nameMap: Optional[Dict[str, DeckDict]] = None + self, did: DeckId, name_map: Optional[Dict[str, DeckDict]] = None ) -> List[DeckDict]: "All parents of did." # get parent and grandparent names @@ -575,14 +492,14 @@ class DeckManager: parents: List[DeckDict] = [] # convert to objects for parent_name in parents_names: - if nameMap: - deck = nameMap[parent_name] + if name_map: + deck = name_map[parent_name] else: deck = self.get(self.id(parent_name)) parents.append(deck) return parents - def parentsByName(self, name: str) -> List[DeckDict]: + def parents_by_name(self, name: str) -> List[DeckDict]: "All existing parents of name" if "::" not in name: return [] @@ -592,15 +509,12 @@ class DeckManager: while names: head.append(names.pop(0)) - deck = self.byName("::".join(head)) + deck = self.by_name("::".join(head)) if deck: parents.append(deck) return parents - def nameMap(self) -> Dict[str, DeckDict]: - return {d["name"]: d for d in self.all()} - # Filtered decks ########################################################################## @@ -610,11 +524,79 @@ class DeckManager: self.select(did) return did - # 1 for dyn, 0 for standard - def isDyn(self, did: Union[DeckId, str]) -> int: - return self.get(did)["dyn"] + def is_filtered(self, did: Union[DeckId, str]) -> bool: + return bool(self.get(did)["dyn"]) - # legacy + # Legacy + ############# - newDyn = new_filtered - nameOrNone = name_if_exists + @deprecated(info="no longer required") + def flush(self) -> None: + pass + + @deprecated(replaced_by=remove) + def rem( + self, + did: DeckId, + **legacy_args: bool, + ) -> None: + "Remove the deck. If cardsToo, delete any cards inside." + if isinstance(did, str): + did = int(did) + self.remove([did]) + + @deprecated(replaced_by=all_names_and_ids) + def name_map(self) -> Dict[str, DeckDict]: + return {d["name"]: d for d in self.all()} + + @deprecated(info="use col.set_deck() instead") + def set_deck(self, cids: List[CardId], did: DeckId) -> None: + self.col.set_deck(card_ids=cids, deck_id=did) + self.col.db.execute( + f"update cards set did=?,usn=?,mod=? where id in {ids2str(cids)}", + did, + self.col.usn(), + intTime(), + ) + + @deprecated(replaced_by=all_names_and_ids) + def all_ids(self) -> List[str]: + return [str(x.id) for x in self.all_names_and_ids()] + + @deprecated(replaced_by=all_names_and_ids) + def all_names(self, dyn: bool = True, force_default: bool = True) -> List[str]: + return [ + x.name + for x in self.all_names_and_ids( + skip_empty_default=not force_default, include_filtered=dyn + ) + ] + + +DeckManager.register_deprecated_aliases( + confForDid=DeckManager.config_dict_for_deck_id, + setConf=DeckManager.set_config_id_for_deck_dict, + didsForConf=DeckManager.decks_using_config, + allConf=DeckManager.all_config, + getConf=DeckManager.get_config, + updateConf=DeckManager.update_config, + remConf=DeckManager.remove_config, + confId=DeckManager.add_config_returning_id, + newDyn=DeckManager.new_filtered, + isDyn=DeckManager.is_filtered, + nameOrNone=DeckManager.name_if_exists, +) + + +@no_type_check +def __getattr__(name): + if name == "defaultDeck": + print_deprecation_warning( + "defaultDeck is deprecated; call decks.id() without it" + ) + return 0 + elif name == "defaultDynamicDeck": + print_deprecation_warning("defaultDynamicDeck is replaced with new_filtered()") + return 1 + else: + raise AttributeError(f"module {__name__} has no attribute {name}") diff --git a/pylib/anki/exporting.py b/pylib/anki/exporting.py index c06363e7b..102dc3e74 100644 --- a/pylib/anki/exporting.py +++ b/pylib/anki/exporting.py @@ -266,7 +266,7 @@ class AnkiExporter(Exporter): d["conf"] = 1 self.dst.decks.update(d) # copy used deck confs - for dc in self.src.decks.allConf(): + for dc in self.src.decks.all_config(): if dc["id"] in dconfs: self.dst.decks.update_config(dc) # find used media diff --git a/pylib/anki/importing/anki2.py b/pylib/anki/importing/anki2.py index d2ad32772..c017bc690 100644 --- a/pylib/anki/importing/anki2.py +++ b/pylib/anki/importing/anki2.py @@ -274,7 +274,7 @@ class Anki2Importer(Importer): idInSrc = self.src.decks.id(head) self._did(idInSrc) # if target is a filtered deck, we'll need a new deck name - deck = self.dst.decks.byName(name) + deck = self.dst.decks.by_name(name) if deck and deck["dyn"]: name = "%s %d" % (name, intTime()) # create in local diff --git a/pylib/anki/importing/noteimp.py b/pylib/anki/importing/noteimp.py index 1cabf47f6..bc73ef644 100644 --- a/pylib/anki/importing/noteimp.py +++ b/pylib/anki/importing/noteimp.py @@ -210,7 +210,7 @@ class NoteImporter(Importer): # we randomize or order here, to ensure that siblings # have the same due# did = self.col.decks.selected() - conf = self.col.decks.confForDid(did) + conf = self.col.decks.config_dict_for_deck_id(did) # in order due? if conf["new"]["order"] == NEW_CARDS_RANDOM: self.col.sched.randomizeCards(did) diff --git a/pylib/anki/scheduler/base.py b/pylib/anki/scheduler/base.py index de3c72b78..a4b082623 100644 --- a/pylib/anki/scheduler/base.py +++ b/pylib/anki/scheduler/base.py @@ -222,7 +222,7 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l self.col._backend.sort_deck(deck_id=did, randomize=False) def resortConf(self, conf: DeckConfigDict) -> None: - for did in self.col.decks.didsForConf(conf): + for did in self.col.decks.decks_using_config(conf): if conf["new"]["order"] == 0: self.randomizeCards(did) else: @@ -232,7 +232,7 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l def maybeRandomizeDeck(self, did: Optional[DeckId] = None) -> None: if not did: did = self.col.decks.selected() - conf = self.col.decks.confForDid(did) + conf = self.col.decks.config_dict_for_deck_id(did) # in order due? if conf["new"]["order"] == NEW_CARDS_RANDOM: self.randomizeCards(did) diff --git a/pylib/anki/scheduler/legacy.py b/pylib/anki/scheduler/legacy.py index ac3a33533..12368e789 100644 --- a/pylib/anki/scheduler/legacy.py +++ b/pylib/anki/scheduler/legacy.py @@ -113,7 +113,7 @@ due = (case when odue>0 then odue else due end), odue = 0, odid = 0, usn = ? whe # legacy in v3 but used by unit tests; redefined in v2/v1 def _cardConf(self, card: Card) -> DeckConfigDict: - return self.col.decks.confForDid(card.did) + return self.col.decks.config_dict_for_deck_id(card.did) def _fuzzIvlRange(self, ivl: int) -> Tuple[int, int]: return (ivl, ivl) diff --git a/pylib/anki/scheduler/v1.py b/pylib/anki/scheduler/v1.py index d84054387..e9a3ef353 100644 --- a/pylib/anki/scheduler/v1.py +++ b/pylib/anki/scheduler/v1.py @@ -636,7 +636,7 @@ did = ? and queue = {QUEUE_TYPE_REV} and due <= ? limit ?""", if not card.odid: return conf["new"] # dynamic deck; override some attributes, use original deck for others - oconf = self.col.decks.confForDid(card.odid) + oconf = self.col.decks.config_dict_for_deck_id(card.odid) delays = conf["delays"] or oconf["new"]["delays"] return dict( # original deck @@ -655,7 +655,7 @@ did = ? and queue = {QUEUE_TYPE_REV} and due <= ? limit ?""", if not card.odid: return conf["lapse"] # dynamic deck; override some attributes, use original deck for others - oconf = self.col.decks.confForDid(card.odid) + oconf = self.col.decks.config_dict_for_deck_id(card.odid) delays = conf["delays"] or oconf["lapse"]["delays"] return dict( # original deck diff --git a/pylib/anki/scheduler/v2.py b/pylib/anki/scheduler/v2.py index 8b358e394..0ee10194d 100644 --- a/pylib/anki/scheduler/v2.py +++ b/pylib/anki/scheduler/v2.py @@ -251,7 +251,7 @@ select count() from "Limit for deck without parent limits." if g["dyn"]: return self.dynReportLimit - c = self.col.decks.confForDid(g["id"]) + c = self.col.decks.config_dict_for_deck_id(g["id"]) limit = max(0, c["new"]["perDay"] - self.counts_for_deck_today(g["id"]).new) return hooks.scheduler_new_limit_for_single_deck(limit, g) @@ -400,7 +400,7 @@ did = ? and queue = {QUEUE_TYPE_DAY_LEARN_RELEARN} and due <= ? limit ?""", if d["dyn"]: return self.dynReportLimit - c = self.col.decks.confForDid(d["id"]) + c = self.col.decks.config_dict_for_deck_id(d["id"]) lim = max(0, c["rev"]["perDay"] - self.counts_for_deck_today(d["id"]).review) return hooks.scheduler_review_limit_for_single_deck(lim, d) @@ -503,7 +503,7 @@ limit ?""" card.odue = 0 def _cardConf(self, card: Card) -> DeckConfigDict: - return self.col.decks.confForDid(card.did) + return self.col.decks.config_dict_for_deck_id(card.did) def _deckLimit(self) -> str: return ids2str(self.col.decks.active()) @@ -517,7 +517,7 @@ limit ?""" if not card.odid: return conf["new"] # dynamic deck; override some attributes, use original deck for others - oconf = self.col.decks.confForDid(card.odid) + oconf = self.col.decks.config_dict_for_deck_id(card.odid) return dict( # original deck ints=oconf["new"]["ints"], @@ -535,7 +535,7 @@ limit ?""" if not card.odid: return conf["lapse"] # dynamic deck; override some attributes, use original deck for others - oconf = self.col.decks.confForDid(card.odid) + oconf = self.col.decks.config_dict_for_deck_id(card.odid) return dict( # original deck minInt=oconf["lapse"]["minInt"], @@ -824,7 +824,7 @@ limit ?""" if not card.odid: return conf["rev"] # dynamic deck - return self.col.decks.confForDid(card.odid)["rev"] + return self.col.decks.config_dict_for_deck_id(card.odid)["rev"] def _answerRevCard(self, card: Card, ease: int) -> None: delay = 0 diff --git a/pylib/tests/test_decks.py b/pylib/tests/test_decks.py index 03ad466e4..6b49646ea 100644 --- a/pylib/tests/test_decks.py +++ b/pylib/tests/test_decks.py @@ -94,56 +94,3 @@ def test_rename(): child = col.decks.get(childId) assertException(DeckRenameError, lambda: col.decks.rename(child, "filtered::child")) assertException(DeckRenameError, lambda: col.decks.rename(child, "FILTERED::child")) - - -def test_renameForDragAndDrop(): - col = getEmptyCol() - - def deckNames(): - return [n.name for n in col.decks.all_names_and_ids(skip_empty_default=True)] - - languages_did = col.decks.id("Languages") - chinese_did = col.decks.id("Chinese") - hsk_did = col.decks.id("Chinese::HSK") - - # Renaming also renames children - col.decks.renameForDragAndDrop(chinese_did, languages_did) - assert deckNames() == ["Languages", "Languages::Chinese", "Languages::Chinese::HSK"] - - # Dragging a deck onto itself is a no-op - col.decks.renameForDragAndDrop(languages_did, languages_did) - assert deckNames() == ["Languages", "Languages::Chinese", "Languages::Chinese::HSK"] - - # Dragging a deck onto its parent is a no-op - col.decks.renameForDragAndDrop(hsk_did, chinese_did) - assert deckNames() == ["Languages", "Languages::Chinese", "Languages::Chinese::HSK"] - - # Dragging a deck onto a descendant is a no-op - col.decks.renameForDragAndDrop(languages_did, hsk_did) - assert deckNames() == ["Languages", "Languages::Chinese", "Languages::Chinese::HSK"] - - # Can drag a grandchild onto its grandparent. It becomes a child - col.decks.renameForDragAndDrop(hsk_did, languages_did) - assert deckNames() == ["Languages", "Languages::Chinese", "Languages::HSK"] - - # Can drag a deck onto its sibling - col.decks.renameForDragAndDrop(hsk_did, chinese_did) - assert deckNames() == ["Languages", "Languages::Chinese", "Languages::Chinese::HSK"] - - # Can drag a deck back to the top level - col.decks.renameForDragAndDrop(chinese_did, None) - assert deckNames() == ["Chinese", "Chinese::HSK", "Languages"] - - # Dragging a top level col to the top level is a no-op - col.decks.renameForDragAndDrop(chinese_did, None) - assert deckNames() == ["Chinese", "Chinese::HSK", "Languages"] - - # decks are renamed if necessary - new_hsk_did = col.decks.id("hsk") - col.decks.renameForDragAndDrop(new_hsk_did, chinese_did) - assert deckNames() == ["Chinese", "Chinese::HSK", "Chinese::hsk+", "Languages"] - col.decks.remove([new_hsk_did]) - - # '' is a convenient alias for the top level DID - col.decks.renameForDragAndDrop(hsk_did, "") - assert deckNames() == ["Chinese", "HSK", "Languages"] diff --git a/pylib/tests/test_exporting.py b/pylib/tests/test_exporting.py index fe3691896..3d84fbd25 100644 --- a/pylib/tests/test_exporting.py +++ b/pylib/tests/test_exporting.py @@ -52,7 +52,7 @@ def test_export_anki(): conf = col.decks.get_config(confId) conf["new"]["perDay"] = 5 col.decks.save(conf) - col.decks.setConf(dobj, confId) + col.decks.set_config_id_for_deck_dict(dobj, confId) # export e = AnkiExporter(col) fd, newname = tempfile.mkstemp(prefix="ankitest", suffix=".anki2") @@ -61,7 +61,7 @@ def test_export_anki(): os.unlink(newname) e.exportInto(newname) # exporting should not have changed conf for original deck - conf = col.decks.confForDid(did) + conf = col.decks.config_dict_for_deck_id(did) assert conf["id"] != 1 # connect to new deck col2 = aopen(newname) @@ -69,7 +69,7 @@ def test_export_anki(): # as scheduling was reset, should also revert decks to default conf did = col2.decks.id("test", create=False) assert did - conf2 = col2.decks.confForDid(did) + conf2 = col2.decks.config_dict_for_deck_id(did) assert conf2["new"]["perDay"] == 20 dobj = col2.decks.get(did) # conf should be 1 diff --git a/pylib/tests/test_schedv1.py b/pylib/tests/test_schedv1.py index d73ba8861..d75622290 100644 --- a/pylib/tests/test_schedv1.py +++ b/pylib/tests/test_schedv1.py @@ -94,7 +94,7 @@ def test_newLimits(): col.addNote(note) # give the child deck a different configuration c2 = col.decks.add_config_returning_id("new conf") - col.decks.setConf(col.decks.get(deck2), c2) + col.decks.set_config_id_for_deck_dict(col.decks.get(deck2), c2) col.reset() # both confs have defaulted to a limit of 20 assert col.sched.newCount == 20 @@ -102,13 +102,13 @@ def test_newLimits(): c = col.sched.getCard() assert c.did == 1 # limit the parent to 10 cards, meaning we get 10 in total - conf1 = col.decks.confForDid(1) + conf1 = col.decks.config_dict_for_deck_id(1) conf1["new"]["perDay"] = 10 col.decks.save(conf1) col.reset() assert col.sched.newCount == 10 # if we limit child to 4, we should get 9 - conf2 = col.decks.confForDid(deck2) + conf2 = col.decks.config_dict_for_deck_id(deck2) conf2["new"]["perDay"] = 4 col.decks.save(conf2) col.reset() @@ -444,7 +444,7 @@ def test_nextIvl(): note["Back"] = "two" col.addNote(note) col.reset() - conf = col.decks.confForDid(1) + conf = col.decks.config_dict_for_deck_id(1) conf["new"]["delays"] = [0.5, 3, 10] conf["lapse"]["delays"] = [1, 5, 9] col.decks.save(conf) diff --git a/pylib/tests/test_schedv2.py b/pylib/tests/test_schedv2.py index b53fb6a17..ccbfd81c4 100644 --- a/pylib/tests/test_schedv2.py +++ b/pylib/tests/test_schedv2.py @@ -106,7 +106,7 @@ def test_newLimits(): col.addNote(note) # give the child deck a different configuration c2 = col.decks.add_config_returning_id("new conf") - col.decks.setConf(col.decks.get(deck2), c2) + col.decks.set_config_id_for_deck_dict(col.decks.get(deck2), c2) col.reset() # both confs have defaulted to a limit of 20 assert col.sched.newCount == 20 @@ -114,13 +114,13 @@ def test_newLimits(): c = col.sched.getCard() assert c.did == 1 # limit the parent to 10 cards, meaning we get 10 in total - conf1 = col.decks.confForDid(1) + conf1 = col.decks.config_dict_for_deck_id(1) conf1["new"]["perDay"] = 10 col.decks.save(conf1) col.reset() assert col.sched.newCount == 10 # if we limit child to 4, we should get 9 - conf2 = col.decks.confForDid(deck2) + conf2 = col.decks.config_dict_for_deck_id(deck2) conf2["new"]["perDay"] = 4 col.decks.save(conf2) col.reset() @@ -245,7 +245,7 @@ def test_relearn_no_steps(): c.type = QUEUE_TYPE_REV c.flush() - conf = col.decks.confForDid(1) + conf = col.decks.config_dict_for_deck_id(1) conf["lapse"]["delays"] = [] col.decks.save(conf) @@ -415,7 +415,7 @@ def test_reviews(): assert c.factor == 2650 # leech handling ################################################## - conf = col.decks.getConf(1) + conf = col.decks.get_config(1) conf["lapse"]["leechAction"] = LEECH_SUSPEND col.decks.save(conf) c = copy.copy(cardcopy) @@ -448,10 +448,10 @@ def review_limits_setup() -> Tuple[anki.collection.Collection, Dict]: pconf["rev"]["perDay"] = 5 col.decks.update_config(pconf) - col.decks.setConf(parent, pconf["id"]) + col.decks.set_config_id_for_deck_dict(parent, pconf["id"]) cconf["rev"]["perDay"] = 10 col.decks.update_config(cconf) - col.decks.setConf(child, cconf["id"]) + col.decks.set_config_id_for_deck_dict(child, cconf["id"]) m = col.models.current() m["did"] = child["id"] @@ -519,7 +519,7 @@ def test_button_spacing(): assert wo(ni(c, 4)) == "4d" # if hard factor is <= 1, then hard may not increase - conf = col.decks.confForDid(1) + conf = col.decks.config_dict_for_deck_id(1) conf["rev"]["hardFactor"] = 1 col.decks.save(conf) assert wo(ni(c, 2)) == "1d" @@ -566,7 +566,7 @@ def test_nextIvl(): note["Back"] = "two" col.addNote(note) col.reset() - conf = col.decks.confForDid(1) + conf = col.decks.config_dict_for_deck_id(1) conf["new"]["delays"] = [0.5, 3, 10] conf["lapse"]["delays"] = [1, 5, 9] col.decks.save(conf) diff --git a/qt/aqt/customstudy.py b/qt/aqt/customstudy.py index 931571257..92b71b57a 100644 --- a/qt/aqt/customstudy.py +++ b/qt/aqt/customstudy.py @@ -140,7 +140,7 @@ class CustomStudy(QDialog): elif i == RADIO_CRAM: tags = self._getTags() # the rest create a filtered deck - cur = self.mw.col.decks.byName(tr.custom_study_custom_study_session()) + cur = self.mw.col.decks.by_name(tr.custom_study_custom_study_session()) if cur: if not cur["dyn"]: showInfo(tr.custom_study_must_rename_deck()) diff --git a/qt/aqt/deckchooser.py b/qt/aqt/deckchooser.py index 59c8f7461..c1661dd6c 100644 --- a/qt/aqt/deckchooser.py +++ b/qt/aqt/deckchooser.py @@ -97,7 +97,7 @@ class DeckChooser(QHBoxLayout): geomKey="selectDeck", ) if ret.name: - self.selected_deck_id = self.mw.col.decks.byName(ret.name)["id"] + self.selected_deck_id = self.mw.col.decks.by_name(ret.name)["id"] # legacy diff --git a/qt/aqt/deckconf.py b/qt/aqt/deckconf.py index 6a5b93329..592f7e298 100644 --- a/qt/aqt/deckconf.py +++ b/qt/aqt/deckconf.py @@ -79,7 +79,7 @@ class DeckConf(QDialog): def loadConfs(self) -> None: current = self.deck["conf"] - self.confList = self.mw.col.decks.allConf() + self.confList = self.mw.col.decks.all_config() self.confList.sort(key=itemgetter("name")) startOn = 0 self.ignoreConfChange = True @@ -117,7 +117,7 @@ class DeckConf(QDialog): self.deck["conf"] = conf["id"] self.mw.col.decks.save(self.deck) self.loadConf() - cnt = len(self.mw.col.decks.didsForConf(conf)) + cnt = len(self.mw.col.decks.decks_using_config(conf)) if cnt > 1: txt = tr.scheduling_your_changes_will_affect_multiple_decks() else: @@ -190,7 +190,7 @@ class DeckConf(QDialog): return "" lim = -1 for d in self.mw.col.decks.parents(self.deck["id"]): - c = self.mw.col.decks.confForDid(d["id"]) + c = self.mw.col.decks.config_dict_for_deck_id(d["id"]) x = c[type]["perDay"] if lim == -1: lim = x @@ -199,7 +199,7 @@ class DeckConf(QDialog): return tr.scheduling_parent_limit(val=lim) def loadConf(self) -> None: - self.conf = self.mw.col.decks.confForDid(self.deck["id"]) + self.conf = self.mw.col.decks.config_dict_for_deck_id(self.deck["id"]) # new c = self.conf["new"] f = self.form @@ -240,7 +240,7 @@ class DeckConf(QDialog): def onRestore(self) -> None: self.mw.progress.start() - self.mw.col.decks.restoreToDefault(self.conf) + self.mw.col.decks.restore_to_default(self.conf) self.mw.progress.finish() self.loadConf()