From 8e43b298169361b53880529e3f760f7e83f915de Mon Sep 17 00:00:00 2001 From: RumovZ Date: Wed, 24 Feb 2021 13:57:44 +0100 Subject: [PATCH 1/4] Localise RenameDeckError --- ftl/core/errors.ftl | 2 ++ qt/aqt/deckbrowser.py | 6 +++--- qt/aqt/dyndeckconf.py | 3 ++- qt/aqt/sidebar.py | 6 +++--- qt/aqt/utils.py | 10 +++++++++- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/ftl/core/errors.ftl b/ftl/core/errors.ftl index 5f5ea6eb5..8e549ecb1 100644 --- a/ftl/core/errors.ftl +++ b/ftl/core/errors.ftl @@ -1,3 +1,5 @@ +errors-invalid-deck-name = Invalid deck name: { $reason } errors-invalid-input-empty = Invalid input. errors-invalid-input-details = Invalid input: { $details } errors-parse-number-fail = A number was invalid or out of range. +errors-reason-filtered-parent = Filtered decks cannot be parent decks. diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py index cd446fec9..05836f8dd 100644 --- a/qt/aqt/deckbrowser.py +++ b/qt/aqt/deckbrowser.py @@ -21,8 +21,8 @@ from aqt.utils import ( getOnlyText, openLink, shortcut, + show_rename_deck_error, showInfo, - showWarning, tr, ) @@ -272,8 +272,8 @@ class DeckBrowser: try: self.mw.col.decks.rename(deck, newName) gui_hooks.sidebar_should_refresh_decks() - except DeckRenameError as e: - showWarning(e.description) + except DeckRenameError as err: + show_rename_deck_error(err) return self.show() diff --git a/qt/aqt/dyndeckconf.py b/qt/aqt/dyndeckconf.py index 8c88df964..6f47480b7 100644 --- a/qt/aqt/dyndeckconf.py +++ b/qt/aqt/dyndeckconf.py @@ -19,6 +19,7 @@ from aqt.utils import ( restoreGeom, saveGeom, show_invalid_search_error, + show_rename_deck_error, showWarning, tr, ) @@ -244,7 +245,7 @@ class DeckConf(QDialog): except InvalidInput as err: show_invalid_search_error(err) except DeckRenameError as err: - showWarning(err.description) + show_rename_deck_error(err) else: if not self.mw.col.sched.rebuild_filtered_deck(self.deck["id"]): if askUser(tr(TR.DECKS_THE_PROVIDED_SEARCH_DID_NOT_MATCH)): diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index 41856e3c7..db90c0846 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -23,8 +23,8 @@ from aqt.utils import ( askUser, getOnlyText, show_invalid_search_error, + show_rename_deck_error, showInfo, - showWarning, tr, ) @@ -993,8 +993,8 @@ class SidebarTreeView(QTreeView): self.mw.checkpoint(tr(TR.ACTIONS_RENAME_DECK)) try: self.mw.col.decks.rename(deck, new_name) - except DeckRenameError as e: - showWarning(e.description) + except DeckRenameError as err: + show_rename_deck_error(err) return self.refresh() self.mw.deckBrowser.refresh() diff --git a/qt/aqt/utils.py b/qt/aqt/utils.py index 8d94aa5c7..5d57bbf0a 100644 --- a/qt/aqt/utils.py +++ b/qt/aqt/utils.py @@ -36,7 +36,7 @@ from PyQt5.QtWidgets import ( import anki import aqt from anki import Collection -from anki.errors import InvalidInput +from anki.errors import DeckRenameError, InvalidInput from anki.lang import TR # pylint: disable=unused-import from anki.utils import invalidFilename, isMac, isWin, noBundledLibs, versionWithBuild from aqt.qt import * @@ -146,6 +146,14 @@ def show_invalid_search_error(err: Exception) -> None: showWarning(text) +def show_rename_deck_error(err: DeckRenameError) -> None: + if err.description == "deck was filtered": + reason = tr(TR.ERRORS_REASON_FILTERED_PARENT) + else: + reason = "unknown reason." + showWarning(tr(TR.ERRORS_INVALID_DECK_NAME, reason=reason)) + + def showInfo( text: str, parent: Union[Literal[False], QDialog] = False, From 1dca43f40905cc2e27d9665a6f7d3e5765a5becc Mon Sep 17 00:00:00 2001 From: RumovZ Date: Wed, 24 Feb 2021 13:59:38 +0100 Subject: [PATCH 2/4] =?UTF-8?q?Fix=20#1024=20=E2=80=93=20catch=20deck=20re?= =?UTF-8?q?name=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- qt/aqt/deckbrowser.py | 17 ++++++++++++----- qt/aqt/studydeck.py | 8 +++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py index 05836f8dd..36e5029a5 100644 --- a/qt/aqt/deckbrowser.py +++ b/qt/aqt/deckbrowser.py @@ -88,11 +88,7 @@ class DeckBrowser: elif cmd == "import": self.mw.onImport() elif cmd == "create": - deck = getOnlyText(tr(TR.DECKS_NAME_FOR_DECK)) - if deck: - self.mw.col.decks.id(deck) - gui_hooks.sidebar_should_refresh_decks() - self.refresh() + self._on_create() elif cmd == "drag": source, target = arg.split(",") self._handle_drag_and_drop(int(source), int(target or 0)) @@ -352,6 +348,17 @@ class DeckBrowser: def _onShared(self) -> None: openLink(f"{aqt.appShared}decks/") + def _on_create(self) -> None: + deck = getOnlyText(tr(TR.DECKS_NAME_FOR_DECK)) + if deck: + try: + self.mw.col.decks.id(deck) + except DeckRenameError as err: + show_rename_deck_error(err) + return + gui_hooks.sidebar_should_refresh_decks() + self.refresh() + ###################################################################### def _v1_upgrade_message(self) -> str: diff --git a/qt/aqt/studydeck.py b/qt/aqt/studydeck.py index d44ff1d26..9db4d7184 100644 --- a/qt/aqt/studydeck.py +++ b/qt/aqt/studydeck.py @@ -4,6 +4,7 @@ from typing import List, Optional import aqt +from anki.decks import DeckRenameError from aqt import gui_hooks from aqt.qt import * from aqt.utils import ( @@ -16,6 +17,7 @@ from aqt.utils import ( restoreGeom, saveGeom, shortcut, + show_rename_deck_error, showInfo, tr, ) @@ -164,7 +166,11 @@ class StudyDeck(QDialog): n = getOnlyText(tr(TR.DECKS_NEW_DECK_NAME), default=default) n = n.strip() if n: - did = self.mw.col.decks.id(n) + try: + did = self.mw.col.decks.id(n) + except DeckRenameError as err: + show_rename_deck_error(err) + return # deck name may not be the same as user input. ex: ", :: self.name = self.mw.col.decks.name(did) # make sure we clean up reset hook when manually exiting From ef925a88d6325bdddf91d4bad33f68ff9cb3e78d Mon Sep 17 00:00:00 2001 From: RumovZ Date: Fri, 26 Feb 2021 11:32:26 +0100 Subject: [PATCH 3/4] Add filtered deck error localisation on backend --- ftl/core/errors.ftl | 3 +-- pylib/anki/errors.py | 21 ++++++++++----------- rslib/src/err.rs | 1 + 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/ftl/core/errors.ftl b/ftl/core/errors.ftl index 8e549ecb1..23a8cc7a3 100644 --- a/ftl/core/errors.ftl +++ b/ftl/core/errors.ftl @@ -1,5 +1,4 @@ -errors-invalid-deck-name = Invalid deck name: { $reason } errors-invalid-input-empty = Invalid input. errors-invalid-input-details = Invalid input: { $details } errors-parse-number-fail = A number was invalid or out of range. -errors-reason-filtered-parent = Filtered decks cannot be parent decks. +errors-filtered-parent-deck = Invalid deck name: Filtered decks cannot be parent decks. diff --git a/pylib/anki/errors.py b/pylib/anki/errors.py index 0fd0a5abb..7ca87996d 100644 --- a/pylib/anki/errors.py +++ b/pylib/anki/errors.py @@ -47,7 +47,15 @@ class ExistsError(Exception): pass -class DeckIsFilteredError(Exception): +class DeckRenameError(Exception): + """Legacy error, use DeckIsFilteredError instead.""" + + def __init__(self, description: str, *args: object) -> None: + super().__init__(description, *args) + self.description = description + + +class DeckIsFilteredError(StringError, DeckRenameError): pass @@ -78,7 +86,7 @@ def backend_exception_to_pylib(err: _pb.BackendError) -> Exception: elif val == "exists": return ExistsError() elif val == "deck_is_filtered": - return DeckIsFilteredError() + return DeckIsFilteredError(err.localized) elif val == "proto_error": return StringError(err.localized) else: @@ -95,12 +103,3 @@ class AnkiError(Exception): def __str__(self) -> str: return self.type - - -class DeckRenameError(Exception): - def __init__(self, description: str) -> None: - super().__init__() - self.description = description - - def __str__(self) -> str: - return f"Couldn't rename deck: {self.description}" diff --git a/rslib/src/err.rs b/rslib/src/err.rs index 6a93df75b..77f714599 100644 --- a/rslib/src/err.rs +++ b/rslib/src/err.rs @@ -208,6 +208,7 @@ impl AnkiError { } } AnkiError::ParseNumError => i18n.tr(TR::ErrorsParseNumberFail).into(), + AnkiError::DeckIsFiltered => i18n.tr(TR::ErrorsFilteredParentDeck).into(), _ => format!("{:?}", self), } } From 92cbf168f6ec26c8e60550dd8089c3e9cd3cddcb Mon Sep 17 00:00:00 2001 From: RumovZ Date: Fri, 26 Feb 2021 11:32:40 +0100 Subject: [PATCH 4/4] Catch DeckIsFilteredError directly on frontend --- pylib/anki/decks.py | 11 ++++------- qt/aqt/deckbrowser.py | 12 ++++++------ qt/aqt/dyndeckconf.py | 9 ++++----- qt/aqt/sidebar.py | 8 ++++---- qt/aqt/studydeck.py | 8 ++++---- qt/aqt/utils.py | 10 +--------- 6 files changed, 23 insertions(+), 35 deletions(-) diff --git a/pylib/anki/decks.py b/pylib/anki/decks.py index 17efb366e..8e7b7c755 100644 --- a/pylib/anki/decks.py +++ b/pylib/anki/decks.py @@ -12,7 +12,7 @@ from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union import anki # pylint: disable=unused-import import anki._backend.backend_pb2 as _pb from anki.consts import * -from anki.errors import DeckIsFilteredError, DeckRenameError, NotFoundError +from anki.errors import NotFoundError from anki.utils import from_json_bytes, ids2str, intTime, to_json_bytes # public exports @@ -246,12 +246,9 @@ class DeckManager: def update(self, g: Deck, preserve_usn: bool = True) -> None: "Add or update an existing deck. Used for syncing and merging." - try: - g["id"] = self.col._backend.add_or_update_deck_legacy( - deck=to_json_bytes(g), preserve_usn_and_mtime=preserve_usn - ) - except DeckIsFilteredError as exc: - raise DeckRenameError("deck was filtered") from exc + g["id"] = self.col._backend.add_or_update_deck_legacy( + deck=to_json_bytes(g), preserve_usn_and_mtime=preserve_usn + ) def rename(self, g: Deck, newName: str) -> None: "Rename deck prefix to NAME if not exists. Updates children." diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py index 36e5029a5..9b788bafb 100644 --- a/qt/aqt/deckbrowser.py +++ b/qt/aqt/deckbrowser.py @@ -9,7 +9,7 @@ from typing import Any import aqt from anki.decks import DeckTreeNode -from anki.errors import DeckRenameError +from anki.errors import DeckIsFilteredError from anki.utils import intTime from aqt import AnkiQt, gui_hooks from aqt.qt import * @@ -21,8 +21,8 @@ from aqt.utils import ( getOnlyText, openLink, shortcut, - show_rename_deck_error, showInfo, + showWarning, tr, ) @@ -268,8 +268,8 @@ class DeckBrowser: try: self.mw.col.decks.rename(deck, newName) gui_hooks.sidebar_should_refresh_decks() - except DeckRenameError as err: - show_rename_deck_error(err) + except DeckIsFilteredError as err: + showWarning(str(err)) return self.show() @@ -353,8 +353,8 @@ class DeckBrowser: if deck: try: self.mw.col.decks.id(deck) - except DeckRenameError as err: - show_rename_deck_error(err) + except DeckIsFilteredError as err: + showWarning(str(err)) return gui_hooks.sidebar_should_refresh_decks() self.refresh() diff --git a/qt/aqt/dyndeckconf.py b/qt/aqt/dyndeckconf.py index 6f47480b7..3f2e5ce35 100644 --- a/qt/aqt/dyndeckconf.py +++ b/qt/aqt/dyndeckconf.py @@ -4,8 +4,8 @@ from typing import Callable, List, Optional import aqt from anki.collection import SearchNode -from anki.decks import Deck, DeckRenameError -from anki.errors import InvalidInput +from anki.decks import Deck +from anki.errors import DeckIsFilteredError, InvalidInput from anki.lang import without_unicode_isolation from aqt import AnkiQt, colors, gui_hooks from aqt.qt import * @@ -19,7 +19,6 @@ from aqt.utils import ( restoreGeom, saveGeom, show_invalid_search_error, - show_rename_deck_error, showWarning, tr, ) @@ -244,8 +243,8 @@ class DeckConf(QDialog): self.saveConf() except InvalidInput as err: show_invalid_search_error(err) - except DeckRenameError as err: - show_rename_deck_error(err) + except DeckIsFilteredError as err: + showWarning(str(err)) else: if not self.mw.col.sched.rebuild_filtered_deck(self.deck["id"]): if askUser(tr(TR.DECKS_THE_PROVIDED_SEARCH_DID_NOT_MATCH)): diff --git a/qt/aqt/sidebar.py b/qt/aqt/sidebar.py index db90c0846..0821c4134 100644 --- a/qt/aqt/sidebar.py +++ b/qt/aqt/sidebar.py @@ -10,7 +10,7 @@ from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, cast import aqt from anki.collection import Config, SearchNode from anki.decks import DeckTreeNode -from anki.errors import DeckRenameError, InvalidInput +from anki.errors import DeckIsFilteredError, InvalidInput from anki.tags import TagTreeNode from anki.types import assert_exhaustive from aqt import colors, gui_hooks @@ -23,8 +23,8 @@ from aqt.utils import ( askUser, getOnlyText, show_invalid_search_error, - show_rename_deck_error, showInfo, + showWarning, tr, ) @@ -993,8 +993,8 @@ class SidebarTreeView(QTreeView): self.mw.checkpoint(tr(TR.ACTIONS_RENAME_DECK)) try: self.mw.col.decks.rename(deck, new_name) - except DeckRenameError as err: - show_rename_deck_error(err) + except DeckIsFilteredError as err: + showWarning(str(err)) return self.refresh() self.mw.deckBrowser.refresh() diff --git a/qt/aqt/studydeck.py b/qt/aqt/studydeck.py index 9db4d7184..6dc62451c 100644 --- a/qt/aqt/studydeck.py +++ b/qt/aqt/studydeck.py @@ -4,7 +4,7 @@ from typing import List, Optional import aqt -from anki.decks import DeckRenameError +from anki.errors import DeckIsFilteredError from aqt import gui_hooks from aqt.qt import * from aqt.utils import ( @@ -17,8 +17,8 @@ from aqt.utils import ( restoreGeom, saveGeom, shortcut, - show_rename_deck_error, showInfo, + showWarning, tr, ) @@ -168,8 +168,8 @@ class StudyDeck(QDialog): if n: try: did = self.mw.col.decks.id(n) - except DeckRenameError as err: - show_rename_deck_error(err) + except DeckIsFilteredError as err: + showWarning(str(err)) return # deck name may not be the same as user input. ex: ", :: self.name = self.mw.col.decks.name(did) diff --git a/qt/aqt/utils.py b/qt/aqt/utils.py index 5d57bbf0a..8d94aa5c7 100644 --- a/qt/aqt/utils.py +++ b/qt/aqt/utils.py @@ -36,7 +36,7 @@ from PyQt5.QtWidgets import ( import anki import aqt from anki import Collection -from anki.errors import DeckRenameError, InvalidInput +from anki.errors import InvalidInput from anki.lang import TR # pylint: disable=unused-import from anki.utils import invalidFilename, isMac, isWin, noBundledLibs, versionWithBuild from aqt.qt import * @@ -146,14 +146,6 @@ def show_invalid_search_error(err: Exception) -> None: showWarning(text) -def show_rename_deck_error(err: DeckRenameError) -> None: - if err.description == "deck was filtered": - reason = tr(TR.ERRORS_REASON_FILTERED_PARENT) - else: - reason = "unknown reason." - showWarning(tr(TR.ERRORS_INVALID_DECK_NAME, reason=reason)) - - def showInfo( text: str, parent: Union[Literal[False], QDialog] = False,