From 644670d0d60fb899b63fa2c688bc5258c1f6c477 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 27 Feb 2020 10:46:24 +1000 Subject: [PATCH] return a localized error for all error kinds some errors are not yet localized, but now the Python code doesn't need to think about which property to use --- proto/backend.proto | 21 +++++++++------------ pylib/anki/rsbackend.py | 40 +++++++++++++++------------------------- qt/aqt/mediasync.py | 10 +--------- rslib/src/backend.rs | 9 +++++---- rslib/src/err.rs | 17 ++++++++++------- 5 files changed, 40 insertions(+), 57 deletions(-) diff --git a/proto/backend.proto b/proto/backend.proto index e1eb3b4f0..27c7d5b19 100644 --- a/proto/backend.proto +++ b/proto/backend.proto @@ -73,13 +73,16 @@ message BackendOutput { } message BackendError { + // localized error description suitable for displaying to the user + string localized = 1; + // error specifics oneof value { - StringError invalid_input = 1; - TemplateParseError template_parse = 2; - StringError io_error = 3; - StringError db_error = 4; - NetworkError network_error = 5; - SyncError sync_error = 6; + StringError invalid_input = 2; + StringError template_parse = 3; + StringError io_error = 4; + StringError db_error = 5; + NetworkError network_error = 6; + SyncError sync_error = 7; // user interrupted operation Empty interrupted = 8; } @@ -96,10 +99,6 @@ message StringError { string info = 1; } -message TemplateParseError { - string info = 1; -} - message NetworkError { string info = 1; enum NetworkErrorKind { @@ -109,7 +108,6 @@ message NetworkError { PROXY_AUTH = 3; } NetworkErrorKind kind = 2; - string localized = 3; } message SyncError { @@ -125,7 +123,6 @@ message SyncError { RESYNC_REQUIRED = 7; } SyncErrorKind kind = 2; - string localized = 3; } message MediaSyncProgress { diff --git a/pylib/anki/rsbackend.py b/pylib/anki/rsbackend.py index 6395a184f..eccfabfab 100644 --- a/pylib/anki/rsbackend.py +++ b/pylib/anki/rsbackend.py @@ -32,14 +32,17 @@ class StringError(Exception): NetworkErrorKind = pb.NetworkError.NetworkErrorKind +SyncErrorKind = pb.SyncError.SyncErrorKind class NetworkError(StringError): def kind(self) -> NetworkErrorKind: return self.args[1] - def localized(self) -> str: - return self.args[2] + +class SyncError(StringError): + def kind(self) -> SyncErrorKind: + return self.args[1] class IOError(StringError): @@ -54,35 +57,22 @@ class TemplateError(StringError): pass -SyncErrorKind = pb.SyncError.SyncErrorKind - - -class SyncError(StringError): - def kind(self) -> SyncErrorKind: - return self.args[1] - - def localized(self) -> str: - return self.args[2] - - def proto_exception_to_native(err: pb.BackendError) -> Exception: val = err.WhichOneof("value") if val == "interrupted": return Interrupted() elif val == "network_error": - e = err.network_error - return NetworkError(e.info, e.kind, e.localized) - elif val == "io_error": - return IOError(err.io_error.info) - elif val == "db_error": - return DBError(err.db_error.info) - elif val == "template_parse": - return TemplateError(err.template_parse.info) - elif val == "invalid_input": - return StringError(err.invalid_input.info) + return NetworkError(err.localized, err.network_error.kind) elif val == "sync_error": - e2 = err.sync_error - return SyncError(e2.info, e2.kind, e2.localized) + return SyncError(err.localized, err.sync_error.kind) + elif val == "io_error": + return IOError(err.localized) + elif val == "db_error": + return DBError(err.localized) + elif val == "template_parse": + return TemplateError(err.localized) + elif val == "invalid_input": + return StringError(err.localized) else: assert_impossible_literal(val) diff --git a/qt/aqt/mediasync.py b/qt/aqt/mediasync.py index f0ec19bdd..6cd5a063e 100644 --- a/qt/aqt/mediasync.py +++ b/qt/aqt/mediasync.py @@ -14,10 +14,8 @@ from anki.rsbackend import ( FString, Interrupted, MediaSyncProgress, - NetworkError, Progress, ProgressKind, - SyncError, ) from anki.types import assert_impossible from anki.utils import intTime @@ -109,13 +107,7 @@ class MediaSyncer: return self._log_and_notify(tr(FString.SYNC_MEDIA_FAILED)) - if isinstance(exc, SyncError): - showWarning(exc.localized()) - elif isinstance(exc, NetworkError): - msg = exc.localized() - msg += "\n\n" + tr(FString.NETWORK_DETAILS, details=str(exc)) - else: - raise exc + showWarning(str(exc)) def entries(self) -> List[LogEntryWithTime]: return self._log diff --git a/rslib/src/backend.rs b/rslib/src/backend.rs index 6a7f8d033..7d0f10444 100644 --- a/rslib/src/backend.rs +++ b/rslib/src/backend.rs @@ -45,23 +45,24 @@ fn anki_error_to_proto_error(err: AnkiError, i18n: &I18n) -> pb::BackendError { let localized = err.localized_description(i18n); let value = match err { AnkiError::InvalidInput { info } => V::InvalidInput(pb::StringError { info }), - AnkiError::TemplateError { info } => V::TemplateParse(pb::TemplateParseError { info }), + AnkiError::TemplateError { info } => V::TemplateParse(pb::StringError { info }), AnkiError::IOError { info } => V::IoError(pb::StringError { info }), AnkiError::DBError { info } => V::DbError(pb::StringError { info }), AnkiError::NetworkError { info, kind } => V::NetworkError(pb::NetworkError { info, kind: kind.into(), - localized, }), AnkiError::SyncError { info, kind } => V::SyncError(pb::SyncError { info, kind: kind.into(), - localized, }), AnkiError::Interrupted => V::Interrupted(Empty {}), }; - pb::BackendError { value: Some(value) } + pb::BackendError { + value: Some(value), + localized, + } } // Convert an Anki error to a protobuf output. diff --git a/rslib/src/err.rs b/rslib/src/err.rs index 9a39babf0..9714f5925 100644 --- a/rslib/src/err.rs +++ b/rslib/src/err.rs @@ -1,7 +1,7 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -use crate::i18n::{FString, I18n}; +use crate::i18n::{tr_strs, FString, I18n}; pub use failure::{Error, Fail}; use reqwest::StatusCode; use std::io; @@ -67,13 +67,16 @@ impl AnkiError { SyncErrorKind::ResyncRequired => i18n.tr(FString::SyncResyncRequired), } .into(), - AnkiError::NetworkError { kind, .. } => match kind { - NetworkErrorKind::Offline => i18n.tr(FString::NetworkOffline), - NetworkErrorKind::Timeout => i18n.tr(FString::NetworkTimeout), - NetworkErrorKind::ProxyAuth => i18n.tr(FString::NetworkProxyAuth), - NetworkErrorKind::Other => i18n.tr(FString::NetworkOther), + AnkiError::NetworkError { kind, info } => { + let summary = match kind { + NetworkErrorKind::Offline => i18n.tr(FString::NetworkOffline), + NetworkErrorKind::Timeout => i18n.tr(FString::NetworkTimeout), + NetworkErrorKind::ProxyAuth => i18n.tr(FString::NetworkProxyAuth), + NetworkErrorKind::Other => i18n.tr(FString::NetworkOther), + }; + let details = i18n.trn(FString::NetworkDetails, tr_strs!["details"=>info]); + format!("{}\n{}", summary, details) } - .into(), _ => "".into(), } }