diff --git a/pylib/anki/rsbackend.py b/pylib/anki/rsbackend.py index edc770e6d..539b71d1d 100644 --- a/pylib/anki/rsbackend.py +++ b/pylib/anki/rsbackend.py @@ -233,7 +233,13 @@ class RustBackend(RustBackendGenerated): return self._db_command(dict(kind="rollback")) def _db_command(self, input: Dict[str, Any]) -> Any: - return from_json_bytes(self._backend.db_command(to_json_bytes(input))) + try: + return from_json_bytes(self._backend.db_command(to_json_bytes(input))) + except Exception as e: + err_bytes = bytes(e.args[0]) + err = pb.BackendError() + err.ParseFromString(err_bytes) + raise proto_exception_to_native(err) def translate(self, key: TRValue, **kwargs: Union[str, int, float]) -> str: return self.translate_string(translate_string_in(key, **kwargs)) @@ -254,7 +260,7 @@ class RustBackend(RustBackendGenerated): return self._backend.command(method, input_bytes) except Exception as e: err_bytes = bytes(e.args[0]) - err = pb.BackendError() + err = pb.BackendError() err.ParseFromString(err_bytes) raise proto_exception_to_native(err) diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index dbe6c6e1b..5cd7f4312 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -1528,6 +1528,15 @@ impl Backend { pub fn db_command(&self, input: &[u8]) -> Result> { self.with_col(|col| db_command_bytes(&col.storage, input)) } + + pub fn run_db_command_bytes(&self, input: &[u8]) -> std::result::Result, Vec> { + self.db_command(input).map_err(|err| { + let backend_err = anki_error_to_proto_error(err, &self.i18n); + let mut bytes = Vec::new(); + backend_err.encode(&mut bytes).unwrap(); + bytes + }) + } } fn to_nids(ids: Vec) -> Vec { diff --git a/rspy/src/lib.rs b/rspy/src/lib.rs index 8724d2133..11b53978f 100644 --- a/rspy/src/lib.rs +++ b/rspy/src/lib.rs @@ -16,7 +16,6 @@ struct Backend { backend: RustBackend, } -create_exception!(ankirspy, DBError, Exception); create_exception!(ankirspy, BackendError, Exception); #[pyfunction] @@ -140,12 +139,14 @@ impl Backend { .map_err(|err_bytes| BackendError::py_err(err_bytes)) } + /// This takes and returns JSON, due to Python's slow protobuf + /// encoding/decoding. fn db_command(&mut self, py: Python, input: &PyBytes) -> PyResult { let in_bytes = input.as_bytes(); let out_res = py.allow_threads(move || { self.backend - .db_command(in_bytes) - .map_err(|e| DBError::py_err(e.localized_description(&self.backend.i18n()))) + .run_db_command_bytes(in_bytes) + .map_err(|err_bytes| BackendError::py_err(err_bytes)) }); let out_bytes = out_res?; let out_obj = PyBytes::new(py, &out_bytes);