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
This commit is contained in:
Damien Elmes 2020-02-27 10:46:24 +10:00
parent bec4699e27
commit 644670d0d6
5 changed files with 40 additions and 57 deletions

View file

@ -73,13 +73,16 @@ message BackendOutput {
} }
message BackendError { message BackendError {
// localized error description suitable for displaying to the user
string localized = 1;
// error specifics
oneof value { oneof value {
StringError invalid_input = 1; StringError invalid_input = 2;
TemplateParseError template_parse = 2; StringError template_parse = 3;
StringError io_error = 3; StringError io_error = 4;
StringError db_error = 4; StringError db_error = 5;
NetworkError network_error = 5; NetworkError network_error = 6;
SyncError sync_error = 6; SyncError sync_error = 7;
// user interrupted operation // user interrupted operation
Empty interrupted = 8; Empty interrupted = 8;
} }
@ -96,10 +99,6 @@ message StringError {
string info = 1; string info = 1;
} }
message TemplateParseError {
string info = 1;
}
message NetworkError { message NetworkError {
string info = 1; string info = 1;
enum NetworkErrorKind { enum NetworkErrorKind {
@ -109,7 +108,6 @@ message NetworkError {
PROXY_AUTH = 3; PROXY_AUTH = 3;
} }
NetworkErrorKind kind = 2; NetworkErrorKind kind = 2;
string localized = 3;
} }
message SyncError { message SyncError {
@ -125,7 +123,6 @@ message SyncError {
RESYNC_REQUIRED = 7; RESYNC_REQUIRED = 7;
} }
SyncErrorKind kind = 2; SyncErrorKind kind = 2;
string localized = 3;
} }
message MediaSyncProgress { message MediaSyncProgress {

View file

@ -32,14 +32,17 @@ class StringError(Exception):
NetworkErrorKind = pb.NetworkError.NetworkErrorKind NetworkErrorKind = pb.NetworkError.NetworkErrorKind
SyncErrorKind = pb.SyncError.SyncErrorKind
class NetworkError(StringError): class NetworkError(StringError):
def kind(self) -> NetworkErrorKind: def kind(self) -> NetworkErrorKind:
return self.args[1] 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): class IOError(StringError):
@ -54,35 +57,22 @@ class TemplateError(StringError):
pass 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: def proto_exception_to_native(err: pb.BackendError) -> Exception:
val = err.WhichOneof("value") val = err.WhichOneof("value")
if val == "interrupted": if val == "interrupted":
return Interrupted() return Interrupted()
elif val == "network_error": elif val == "network_error":
e = err.network_error return NetworkError(err.localized, err.network_error.kind)
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)
elif val == "sync_error": elif val == "sync_error":
e2 = err.sync_error return SyncError(err.localized, err.sync_error.kind)
return SyncError(e2.info, e2.kind, e2.localized) 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: else:
assert_impossible_literal(val) assert_impossible_literal(val)

View file

@ -14,10 +14,8 @@ from anki.rsbackend import (
FString, FString,
Interrupted, Interrupted,
MediaSyncProgress, MediaSyncProgress,
NetworkError,
Progress, Progress,
ProgressKind, ProgressKind,
SyncError,
) )
from anki.types import assert_impossible from anki.types import assert_impossible
from anki.utils import intTime from anki.utils import intTime
@ -109,13 +107,7 @@ class MediaSyncer:
return return
self._log_and_notify(tr(FString.SYNC_MEDIA_FAILED)) self._log_and_notify(tr(FString.SYNC_MEDIA_FAILED))
if isinstance(exc, SyncError): showWarning(str(exc))
showWarning(exc.localized())
elif isinstance(exc, NetworkError):
msg = exc.localized()
msg += "\n\n" + tr(FString.NETWORK_DETAILS, details=str(exc))
else:
raise exc
def entries(self) -> List[LogEntryWithTime]: def entries(self) -> List[LogEntryWithTime]:
return self._log return self._log

View file

@ -45,23 +45,24 @@ fn anki_error_to_proto_error(err: AnkiError, i18n: &I18n) -> pb::BackendError {
let localized = err.localized_description(i18n); let localized = err.localized_description(i18n);
let value = match err { let value = match err {
AnkiError::InvalidInput { info } => V::InvalidInput(pb::StringError { info }), 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::IOError { info } => V::IoError(pb::StringError { info }),
AnkiError::DBError { info } => V::DbError(pb::StringError { info }), AnkiError::DBError { info } => V::DbError(pb::StringError { info }),
AnkiError::NetworkError { info, kind } => V::NetworkError(pb::NetworkError { AnkiError::NetworkError { info, kind } => V::NetworkError(pb::NetworkError {
info, info,
kind: kind.into(), kind: kind.into(),
localized,
}), }),
AnkiError::SyncError { info, kind } => V::SyncError(pb::SyncError { AnkiError::SyncError { info, kind } => V::SyncError(pb::SyncError {
info, info,
kind: kind.into(), kind: kind.into(),
localized,
}), }),
AnkiError::Interrupted => V::Interrupted(Empty {}), AnkiError::Interrupted => V::Interrupted(Empty {}),
}; };
pb::BackendError { value: Some(value) } pb::BackendError {
value: Some(value),
localized,
}
} }
// Convert an Anki error to a protobuf output. // Convert an Anki error to a protobuf output.

View file

@ -1,7 +1,7 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // 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}; pub use failure::{Error, Fail};
use reqwest::StatusCode; use reqwest::StatusCode;
use std::io; use std::io;
@ -67,13 +67,16 @@ impl AnkiError {
SyncErrorKind::ResyncRequired => i18n.tr(FString::SyncResyncRequired), SyncErrorKind::ResyncRequired => i18n.tr(FString::SyncResyncRequired),
} }
.into(), .into(),
AnkiError::NetworkError { kind, .. } => match kind { AnkiError::NetworkError { kind, info } => {
NetworkErrorKind::Offline => i18n.tr(FString::NetworkOffline), let summary = match kind {
NetworkErrorKind::Timeout => i18n.tr(FString::NetworkTimeout), NetworkErrorKind::Offline => i18n.tr(FString::NetworkOffline),
NetworkErrorKind::ProxyAuth => i18n.tr(FString::NetworkProxyAuth), NetworkErrorKind::Timeout => i18n.tr(FString::NetworkTimeout),
NetworkErrorKind::Other => i18n.tr(FString::NetworkOther), 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(), _ => "".into(),
} }
} }