diff --git a/pylib/anki/_legacy.py b/pylib/anki/_legacy.py index 3284f81c0..3d6e73358 100644 --- a/pylib/anki/_legacy.py +++ b/pylib/anki/_legacy.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Any, Callable, Dict, Tuple, Union +from typing import Any, Callable, Dict, Optional, Tuple, Union import stringcase @@ -41,3 +41,23 @@ class DeprecatedNamesMixin: are valid symbols, and we can't get a variable's name easily. """ cls._deprecated_aliases = {k: _target_to_string(v) for k, v in kwargs.items()} + + +def deprecated(replaced_by: Optional[Callable] = None, info: str = "") -> Callable: + """Print a deprecation warning, telling users to use `replaced_by`, or show `doc`.""" + + def decorator(func: Callable) -> Callable: + def decorated_func(*args: Any, **kwargs: Any) -> Any: + if replaced_by: + doc = f"please use {replaced_by.__name__} instead." + else: + doc = info + print( + f"'{func.__name__}' is deprecated, and will be removed in the future: ", + doc, + ) + return func(*args, **kwargs) + + return decorated_func + + return decorator diff --git a/pylib/anki/decks.py b/pylib/anki/decks.py index 34c839e28..af5217de8 100644 --- a/pylib/anki/decks.py +++ b/pylib/anki/decks.py @@ -11,11 +11,12 @@ from typing import Any, Dict, Iterable, List, NewType, Optional, Sequence, Tuple import anki # pylint: disable=unused-import import anki._backend.backend_pb2 as _pb +from anki._legacy import deprecated from anki.cards import CardId from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId from anki.consts import * from anki.errors import NotFoundError -from anki.utils import from_json_bytes, ids2str, intTime, legacy_func, to_json_bytes +from anki.utils import from_json_bytes, ids2str, intTime, to_json_bytes # public exports DeckTreeNode = _pb.DeckTreeNode @@ -142,7 +143,10 @@ class DeckManager: out = self.add_deck_legacy(deck) return DeckId(out.id) - @legacy_func(sub="remove") + 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): @@ -150,9 +154,6 @@ class DeckManager: assert cardsToo and childrenToo self.remove([did]) - def remove(self, dids: Sequence[DeckId]) -> OpChangesWithCount: - return self.col._backend.remove_decks(dids) - def all_names_and_ids( self, skip_empty_default: bool = False, include_filtered: bool = True ) -> Sequence[DeckNameId]: diff --git a/pylib/anki/utils.py b/pylib/anki/utils.py index 73da72688..330797c0f 100644 --- a/pylib/anki/utils.py +++ b/pylib/anki/utils.py @@ -18,7 +18,7 @@ import traceback from contextlib import contextmanager from hashlib import sha1 from html.entities import name2codepoint -from typing import Any, Callable, Iterable, Iterator, List, Match, Optional, Union +from typing import Any, Iterable, Iterator, List, Match, Optional, Union from anki.dbproxy import DBProxy @@ -372,26 +372,3 @@ def pointVersion() -> int: from anki.buildinfo import version return int(version.split(".")[-1]) - - -# Legacy support -############################################################################## - - -def legacy_func(sub: Optional[str] = None) -> Callable: - """Print a deprecation warning for the decorated callable recommending the use of - 'sub' instead, if provided. - """ - if sub: - hint = f", use '{sub}' instead" - else: - hint = "" - - def decorator(func: Callable) -> Callable: - def decorated_func(*args: Any, **kwargs: Any) -> Any: - print(f"'{func.__name__}' is deprecated{hint}.") - return func(*args, **kwargs) - - return decorated_func - - return decorator