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 {
// 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 {

View file

@ -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)

View file

@ -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

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 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.

View file

@ -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(),
}
}