From c23b01978dd4f966085c2f1f7617995a30a5d7a6 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 8 Feb 2021 16:40:27 +1000 Subject: [PATCH] nest progress messages and remove Python wrapper class The progress messages are only really intended to be consumed by Anki. If consumption by add-ons was expected, we'd be better off keeping the wrapper, as the API for oneofs in Python is quite awkward to use. --- pylib/anki/collection.py | 46 ++----------------------------- qt/aqt/dbcheck.py | 12 ++++----- qt/aqt/mediacheck.py | 10 +++---- qt/aqt/mediasync.py | 15 +++++------ qt/aqt/sync.py | 19 +++++++------ rslib/backend.proto | 58 ++++++++++++++++++---------------------- rslib/src/backend/mod.rs | 10 +++---- 7 files changed, 58 insertions(+), 112 deletions(-) diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index b8c0cd51f..39c5efceb 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -4,7 +4,6 @@ from __future__ import annotations import copy -import enum import os import pprint import re @@ -12,7 +11,6 @@ import sys import time import traceback import weakref -from dataclasses import dataclass from typing import Any, List, Optional, Sequence, Tuple, Union import anki._backend.backend_pb2 as _pb @@ -46,10 +44,7 @@ from anki.utils import ( # public exports SearchTerm = _pb.SearchTerm -MediaSyncProgress = _pb.MediaSyncProgress -FullSyncProgress = _pb.FullSyncProgress -NormalSyncProgress = _pb.NormalSyncProgress -DatabaseCheckProgress = _pb.DatabaseCheckProgress +Progress = _pb.Progress Config = _pb.Config EmptyCardsReport = _pb.EmptyCardsReport NoteWithEmptyCards = _pb.NoteWithEmptyCards @@ -125,7 +120,7 @@ class Collection: ########################################################################## def latest_progress(self) -> Progress: - return Progress.from_proto(self._backend.latest_progress()) + return self._backend.latest_progress() # Scheduler ########################################################################## @@ -874,42 +869,5 @@ table.review-log {{ {revlog_style} }} self._backend.set_preferences(prefs) -class ProgressKind(enum.Enum): - NoProgress = 0 - MediaSync = 1 - MediaCheck = 2 - FullSync = 3 - NormalSync = 4 - DatabaseCheck = 5 - - -@dataclass -class Progress: - kind: ProgressKind - val: Union[ - MediaSyncProgress, - FullSyncProgress, - NormalSyncProgress, - DatabaseCheckProgress, - str, - ] - - @staticmethod - def from_proto(proto: _pb.Progress) -> Progress: - kind = proto.WhichOneof("value") - if kind == "media_sync": - return Progress(kind=ProgressKind.MediaSync, val=proto.media_sync) - elif kind == "media_check": - return Progress(kind=ProgressKind.MediaCheck, val=proto.media_check) - elif kind == "full_sync": - return Progress(kind=ProgressKind.FullSync, val=proto.full_sync) - elif kind == "normal_sync": - return Progress(kind=ProgressKind.NormalSync, val=proto.normal_sync) - elif kind == "database_check": - return Progress(kind=ProgressKind.DatabaseCheck, val=proto.database_check) - else: - return Progress(kind=ProgressKind.NoProgress, val="") - - # legacy name _Collection = Collection diff --git a/qt/aqt/dbcheck.py b/qt/aqt/dbcheck.py index c8cec9b86..44d43a9a7 100644 --- a/qt/aqt/dbcheck.py +++ b/qt/aqt/dbcheck.py @@ -6,22 +6,20 @@ from __future__ import annotations from concurrent.futures import Future import aqt -from anki.collection import DatabaseCheckProgress, ProgressKind from aqt.qt import * from aqt.utils import showText, tooltip def on_progress(mw: aqt.main.AnkiQt) -> None: progress = mw.col.latest_progress() - if progress.kind != ProgressKind.DatabaseCheck: + if not progress.HasField("database_check"): return - - assert isinstance(progress.val, DatabaseCheckProgress) + dbprogress = progress.database_check mw.progress.update( process=False, - label=progress.val.stage, - value=progress.val.stage_current, - max=progress.val.stage_total, + label=dbprogress.stage, + value=dbprogress.stage_current, + max=dbprogress.stage_total, ) diff --git a/qt/aqt/mediacheck.py b/qt/aqt/mediacheck.py index 3da4f87db..64f85e32d 100644 --- a/qt/aqt/mediacheck.py +++ b/qt/aqt/mediacheck.py @@ -9,7 +9,7 @@ from concurrent.futures import Future from typing import Iterable, List, Optional, Sequence, TypeVar import aqt -from anki.collection import ProgressKind, SearchTerm +from anki.collection import SearchTerm from anki.errors import Interrupted from anki.lang import TR from anki.media import CheckMediaOut @@ -62,11 +62,9 @@ class MediaChecker: def _on_progress(self) -> None: progress = self.mw.col.latest_progress() - if progress.kind != ProgressKind.MediaCheck: + if not progress.HasField("media_check"): return - - assert isinstance(progress.val, str) - val = progress.val + label = progress.media_check try: if self.progress_dialog.wantCancel: @@ -75,7 +73,7 @@ class MediaChecker: # dialog may not be active pass - self.mw.taskman.run_on_main(lambda: self.mw.progress.update(val)) + self.mw.taskman.run_on_main(lambda: self.mw.progress.update(label=label)) def _check(self) -> CheckMediaOut: "Run the check on a background thread." diff --git a/qt/aqt/mediasync.py b/qt/aqt/mediasync.py index 1c52c70a9..ef573561d 100644 --- a/qt/aqt/mediasync.py +++ b/qt/aqt/mediasync.py @@ -9,7 +9,7 @@ from dataclasses import dataclass from typing import Any, Callable, List, Optional, Union import aqt -from anki.collection import MediaSyncProgress, ProgressKind +from anki.collection import Progress from anki.errors import Interrupted, NetworkError from anki.lang import TR from anki.types import assert_exhaustive @@ -18,7 +18,7 @@ from aqt import gui_hooks from aqt.qt import QDialog, QDialogButtonBox, QPushButton, QTextCursor, QTimer, qconnect from aqt.utils import disable_help_button, showWarning, tr -LogEntry = Union[MediaSyncProgress, str] +LogEntry = Union[Progress.MediaSync, str] @dataclass @@ -37,11 +37,10 @@ class MediaSyncer: def _on_progress(self) -> None: progress = self.mw.col.latest_progress() - if progress.kind != ProgressKind.MediaSync: + if not progress.HasField("media_sync"): return - - assert isinstance(progress.val, MediaSyncProgress) - self._log_and_notify(progress.val) + sync_progress = progress.media_sync + self._log_and_notify(sync_progress) def start(self) -> None: "Start media syncing in the background, if it's not already running." @@ -202,13 +201,13 @@ class MediaSyncDialog(QDialog): def _entry_to_text(self, entry: LogEntryWithTime) -> str: if isinstance(entry.entry, str): txt = entry.entry - elif isinstance(entry.entry, MediaSyncProgress): + elif isinstance(entry.entry, Progress.MediaSync): txt = self._logentry_to_text(entry.entry) else: assert_exhaustive(entry.entry) return self._time_and_text(entry.time, txt) - def _logentry_to_text(self, e: MediaSyncProgress) -> str: + def _logentry_to_text(self, e: Progress.MediaSync) -> str: return f"{e.added}, {e.removed}, {e.checked}" def _on_log_entry(self, entry: LogEntryWithTime) -> None: diff --git a/qt/aqt/sync.py b/qt/aqt/sync.py index 939348786..9e6a10f5a 100644 --- a/qt/aqt/sync.py +++ b/qt/aqt/sync.py @@ -9,7 +9,6 @@ from concurrent.futures import Future from typing import Callable, Tuple import aqt -from anki.collection import FullSyncProgress, NormalSyncProgress, ProgressKind from anki.errors import Interrupted, SyncError from anki.lang import TR, without_unicode_isolation from anki.sync import SyncOutput, SyncStatus @@ -73,15 +72,15 @@ def handle_sync_error(mw: aqt.main.AnkiQt, err: Exception) -> None: def on_normal_sync_timer(mw: aqt.main.AnkiQt) -> None: progress = mw.col.latest_progress() - if progress.kind != ProgressKind.NormalSync: + if not progress.HasField("normal_sync"): return + sync_progress = progress.normal_sync - assert isinstance(progress.val, NormalSyncProgress) mw.progress.update( - label=f"{progress.val.added}\n{progress.val.removed}", + label=f"{sync_progress.added}\n{sync_progress.removed}", process=False, ) - mw.progress.set_title(progress.val.stage) + mw.progress.set_title(sync_progress.stage) if mw.progress.want_cancel(): mw.col.abort_sync() @@ -153,17 +152,17 @@ def confirm_full_download(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> N def on_full_sync_timer(mw: aqt.main.AnkiQt) -> None: progress = mw.col.latest_progress() - if progress.kind != ProgressKind.FullSync: + if not progress.HasField("full_sync"): return + sync_progress = progress.full_sync - assert isinstance(progress.val, FullSyncProgress) - if progress.val.transferred == progress.val.total: + if sync_progress.transferred == sync_progress.total: label = tr(TR.SYNC_CHECKING) else: label = None mw.progress.update( - value=progress.val.transferred, - max=progress.val.total, + value=sync_progress.transferred, + max=sync_progress.total, process=False, label=label, ) diff --git a/rslib/backend.proto b/rslib/backend.proto index 9c72f8997..eff0abee2 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -535,44 +535,38 @@ message SyncError { /////////////////////////////////////////////////////////// message Progress { + message MediaSync { + string checked = 1; + string added = 2; + string removed = 3; + } + + message FullSync { + uint32 transferred = 1; + uint32 total = 2; + } + + message NormalSync { + string stage = 1; + string added = 2; + string removed = 3; + } + + message DatabaseCheck { + string stage = 1; + uint32 stage_total = 2; + uint32 stage_current = 3; + } oneof value { Empty none = 1; - MediaSyncProgress media_sync = 2; + MediaSync media_sync = 2; string media_check = 3; - FullSyncProgress full_sync = 4; - NormalSyncProgress normal_sync = 5; - DatabaseCheckProgress database_check = 6; + FullSync full_sync = 4; + NormalSync normal_sync = 5; + DatabaseCheck database_check = 6; } } -message MediaSyncProgress { - string checked = 1; - string added = 2; - string removed = 3; -} - -message FullSyncProgress { - uint32 transferred = 1; - uint32 total = 2; -} - -message MediaSyncUploadProgress { - uint32 files = 1; - uint32 deletions = 2; -} - -message NormalSyncProgress { - string stage = 1; - string added = 2; - string removed = 3; -} - -message DatabaseCheckProgress { - string stage = 1; - uint32 stage_total = 2; - uint32 stage_current = 3; -} - // Messages /////////////////////////////////////////////////////////// diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index 4ceee747a..2ac7b2400 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -1898,7 +1898,7 @@ fn progress_to_proto(progress: Option, i18n: &I18n) -> pb::Progress { let s = i18n.trn(TR::MediaCheckChecked, tr_args!["count"=>n]); pb::progress::Value::MediaCheck(s) } - Progress::FullSync(p) => pb::progress::Value::FullSync(pb::FullSyncProgress { + Progress::FullSync(p) => pb::progress::Value::FullSync(pb::progress::FullSync { transferred: p.transferred_bytes as u32, total: p.total_bytes as u32, }), @@ -1919,7 +1919,7 @@ fn progress_to_proto(progress: Option, i18n: &I18n) -> pb::Progress { tr_args![ "up"=>p.local_remove, "down"=>p.remote_remove], ); - pb::progress::Value::NormalSync(pb::NormalSyncProgress { + pb::progress::Value::NormalSync(pb::progress::NormalSync { stage, added, removed, @@ -1940,7 +1940,7 @@ fn progress_to_proto(progress: Option, i18n: &I18n) -> pb::Progress { DatabaseCheckProgress::History => i18n.tr(TR::DatabaseCheckCheckingHistory), } .to_string(); - pb::progress::Value::DatabaseCheck(pb::DatabaseCheckProgress { + pb::progress::Value::DatabaseCheck(pb::progress::DatabaseCheck { stage, stage_current, stage_total, @@ -1955,8 +1955,8 @@ fn progress_to_proto(progress: Option, i18n: &I18n) -> pb::Progress { } } -fn media_sync_progress(p: MediaSyncProgress, i18n: &I18n) -> pb::MediaSyncProgress { - pb::MediaSyncProgress { +fn media_sync_progress(p: MediaSyncProgress, i18n: &I18n) -> pb::progress::MediaSync { + pb::progress::MediaSync { checked: i18n.trn(TR::SyncMediaCheckedCount, tr_args!["count"=>p.checked]), added: i18n.trn( TR::SyncMediaAddedCount,