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.
This commit is contained in:
Damien Elmes 2021-02-08 16:40:27 +10:00
parent f434cff36f
commit c23b01978d
7 changed files with 58 additions and 112 deletions

View file

@ -4,7 +4,6 @@
from __future__ import annotations from __future__ import annotations
import copy import copy
import enum
import os import os
import pprint import pprint
import re import re
@ -12,7 +11,6 @@ import sys
import time import time
import traceback import traceback
import weakref import weakref
from dataclasses import dataclass
from typing import Any, List, Optional, Sequence, Tuple, Union from typing import Any, List, Optional, Sequence, Tuple, Union
import anki._backend.backend_pb2 as _pb import anki._backend.backend_pb2 as _pb
@ -46,10 +44,7 @@ from anki.utils import (
# public exports # public exports
SearchTerm = _pb.SearchTerm SearchTerm = _pb.SearchTerm
MediaSyncProgress = _pb.MediaSyncProgress Progress = _pb.Progress
FullSyncProgress = _pb.FullSyncProgress
NormalSyncProgress = _pb.NormalSyncProgress
DatabaseCheckProgress = _pb.DatabaseCheckProgress
Config = _pb.Config Config = _pb.Config
EmptyCardsReport = _pb.EmptyCardsReport EmptyCardsReport = _pb.EmptyCardsReport
NoteWithEmptyCards = _pb.NoteWithEmptyCards NoteWithEmptyCards = _pb.NoteWithEmptyCards
@ -125,7 +120,7 @@ class Collection:
########################################################################## ##########################################################################
def latest_progress(self) -> Progress: def latest_progress(self) -> Progress:
return Progress.from_proto(self._backend.latest_progress()) return self._backend.latest_progress()
# Scheduler # Scheduler
########################################################################## ##########################################################################
@ -874,42 +869,5 @@ table.review-log {{ {revlog_style} }}
self._backend.set_preferences(prefs) 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 # legacy name
_Collection = Collection _Collection = Collection

View file

@ -6,22 +6,20 @@ from __future__ import annotations
from concurrent.futures import Future from concurrent.futures import Future
import aqt import aqt
from anki.collection import DatabaseCheckProgress, ProgressKind
from aqt.qt import * from aqt.qt import *
from aqt.utils import showText, tooltip from aqt.utils import showText, tooltip
def on_progress(mw: aqt.main.AnkiQt) -> None: def on_progress(mw: aqt.main.AnkiQt) -> None:
progress = mw.col.latest_progress() progress = mw.col.latest_progress()
if progress.kind != ProgressKind.DatabaseCheck: if not progress.HasField("database_check"):
return return
dbprogress = progress.database_check
assert isinstance(progress.val, DatabaseCheckProgress)
mw.progress.update( mw.progress.update(
process=False, process=False,
label=progress.val.stage, label=dbprogress.stage,
value=progress.val.stage_current, value=dbprogress.stage_current,
max=progress.val.stage_total, max=dbprogress.stage_total,
) )

View file

@ -9,7 +9,7 @@ from concurrent.futures import Future
from typing import Iterable, List, Optional, Sequence, TypeVar from typing import Iterable, List, Optional, Sequence, TypeVar
import aqt import aqt
from anki.collection import ProgressKind, SearchTerm from anki.collection import SearchTerm
from anki.errors import Interrupted from anki.errors import Interrupted
from anki.lang import TR from anki.lang import TR
from anki.media import CheckMediaOut from anki.media import CheckMediaOut
@ -62,11 +62,9 @@ class MediaChecker:
def _on_progress(self) -> None: def _on_progress(self) -> None:
progress = self.mw.col.latest_progress() progress = self.mw.col.latest_progress()
if progress.kind != ProgressKind.MediaCheck: if not progress.HasField("media_check"):
return return
label = progress.media_check
assert isinstance(progress.val, str)
val = progress.val
try: try:
if self.progress_dialog.wantCancel: if self.progress_dialog.wantCancel:
@ -75,7 +73,7 @@ class MediaChecker:
# dialog may not be active # dialog may not be active
pass 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: def _check(self) -> CheckMediaOut:
"Run the check on a background thread." "Run the check on a background thread."

View file

@ -9,7 +9,7 @@ from dataclasses import dataclass
from typing import Any, Callable, List, Optional, Union from typing import Any, Callable, List, Optional, Union
import aqt import aqt
from anki.collection import MediaSyncProgress, ProgressKind from anki.collection import Progress
from anki.errors import Interrupted, NetworkError from anki.errors import Interrupted, NetworkError
from anki.lang import TR from anki.lang import TR
from anki.types import assert_exhaustive 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.qt import QDialog, QDialogButtonBox, QPushButton, QTextCursor, QTimer, qconnect
from aqt.utils import disable_help_button, showWarning, tr from aqt.utils import disable_help_button, showWarning, tr
LogEntry = Union[MediaSyncProgress, str] LogEntry = Union[Progress.MediaSync, str]
@dataclass @dataclass
@ -37,11 +37,10 @@ class MediaSyncer:
def _on_progress(self) -> None: def _on_progress(self) -> None:
progress = self.mw.col.latest_progress() progress = self.mw.col.latest_progress()
if progress.kind != ProgressKind.MediaSync: if not progress.HasField("media_sync"):
return return
sync_progress = progress.media_sync
assert isinstance(progress.val, MediaSyncProgress) self._log_and_notify(sync_progress)
self._log_and_notify(progress.val)
def start(self) -> None: def start(self) -> None:
"Start media syncing in the background, if it's not already running." "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: def _entry_to_text(self, entry: LogEntryWithTime) -> str:
if isinstance(entry.entry, str): if isinstance(entry.entry, str):
txt = entry.entry txt = entry.entry
elif isinstance(entry.entry, MediaSyncProgress): elif isinstance(entry.entry, Progress.MediaSync):
txt = self._logentry_to_text(entry.entry) txt = self._logentry_to_text(entry.entry)
else: else:
assert_exhaustive(entry.entry) assert_exhaustive(entry.entry)
return self._time_and_text(entry.time, txt) 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}" return f"{e.added}, {e.removed}, {e.checked}"
def _on_log_entry(self, entry: LogEntryWithTime) -> None: def _on_log_entry(self, entry: LogEntryWithTime) -> None:

View file

@ -9,7 +9,6 @@ from concurrent.futures import Future
from typing import Callable, Tuple from typing import Callable, Tuple
import aqt import aqt
from anki.collection import FullSyncProgress, NormalSyncProgress, ProgressKind
from anki.errors import Interrupted, SyncError from anki.errors import Interrupted, SyncError
from anki.lang import TR, without_unicode_isolation from anki.lang import TR, without_unicode_isolation
from anki.sync import SyncOutput, SyncStatus 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: def on_normal_sync_timer(mw: aqt.main.AnkiQt) -> None:
progress = mw.col.latest_progress() progress = mw.col.latest_progress()
if progress.kind != ProgressKind.NormalSync: if not progress.HasField("normal_sync"):
return return
sync_progress = progress.normal_sync
assert isinstance(progress.val, NormalSyncProgress)
mw.progress.update( mw.progress.update(
label=f"{progress.val.added}\n{progress.val.removed}", label=f"{sync_progress.added}\n{sync_progress.removed}",
process=False, process=False,
) )
mw.progress.set_title(progress.val.stage) mw.progress.set_title(sync_progress.stage)
if mw.progress.want_cancel(): if mw.progress.want_cancel():
mw.col.abort_sync() 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: def on_full_sync_timer(mw: aqt.main.AnkiQt) -> None:
progress = mw.col.latest_progress() progress = mw.col.latest_progress()
if progress.kind != ProgressKind.FullSync: if not progress.HasField("full_sync"):
return return
sync_progress = progress.full_sync
assert isinstance(progress.val, FullSyncProgress) if sync_progress.transferred == sync_progress.total:
if progress.val.transferred == progress.val.total:
label = tr(TR.SYNC_CHECKING) label = tr(TR.SYNC_CHECKING)
else: else:
label = None label = None
mw.progress.update( mw.progress.update(
value=progress.val.transferred, value=sync_progress.transferred,
max=progress.val.total, max=sync_progress.total,
process=False, process=False,
label=label, label=label,
) )

View file

@ -535,42 +535,36 @@ message SyncError {
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
message Progress { message Progress {
oneof value { message MediaSync {
Empty none = 1;
MediaSyncProgress media_sync = 2;
string media_check = 3;
FullSyncProgress full_sync = 4;
NormalSyncProgress normal_sync = 5;
DatabaseCheckProgress database_check = 6;
}
}
message MediaSyncProgress {
string checked = 1; string checked = 1;
string added = 2; string added = 2;
string removed = 3; string removed = 3;
} }
message FullSyncProgress { message FullSync {
uint32 transferred = 1; uint32 transferred = 1;
uint32 total = 2; uint32 total = 2;
} }
message MediaSyncUploadProgress { message NormalSync {
uint32 files = 1;
uint32 deletions = 2;
}
message NormalSyncProgress {
string stage = 1; string stage = 1;
string added = 2; string added = 2;
string removed = 3; string removed = 3;
} }
message DatabaseCheckProgress { message DatabaseCheck {
string stage = 1; string stage = 1;
uint32 stage_total = 2; uint32 stage_total = 2;
uint32 stage_current = 3; uint32 stage_current = 3;
}
oneof value {
Empty none = 1;
MediaSync media_sync = 2;
string media_check = 3;
FullSync full_sync = 4;
NormalSync normal_sync = 5;
DatabaseCheck database_check = 6;
}
} }
// Messages // Messages

View file

@ -1898,7 +1898,7 @@ fn progress_to_proto(progress: Option<Progress>, i18n: &I18n) -> pb::Progress {
let s = i18n.trn(TR::MediaCheckChecked, tr_args!["count"=>n]); let s = i18n.trn(TR::MediaCheckChecked, tr_args!["count"=>n]);
pb::progress::Value::MediaCheck(s) 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, transferred: p.transferred_bytes as u32,
total: p.total_bytes as u32, total: p.total_bytes as u32,
}), }),
@ -1919,7 +1919,7 @@ fn progress_to_proto(progress: Option<Progress>, i18n: &I18n) -> pb::Progress {
tr_args![ tr_args![
"up"=>p.local_remove, "down"=>p.remote_remove], "up"=>p.local_remove, "down"=>p.remote_remove],
); );
pb::progress::Value::NormalSync(pb::NormalSyncProgress { pb::progress::Value::NormalSync(pb::progress::NormalSync {
stage, stage,
added, added,
removed, removed,
@ -1940,7 +1940,7 @@ fn progress_to_proto(progress: Option<Progress>, i18n: &I18n) -> pb::Progress {
DatabaseCheckProgress::History => i18n.tr(TR::DatabaseCheckCheckingHistory), DatabaseCheckProgress::History => i18n.tr(TR::DatabaseCheckCheckingHistory),
} }
.to_string(); .to_string();
pb::progress::Value::DatabaseCheck(pb::DatabaseCheckProgress { pb::progress::Value::DatabaseCheck(pb::progress::DatabaseCheck {
stage, stage,
stage_current, stage_current,
stage_total, stage_total,
@ -1955,8 +1955,8 @@ fn progress_to_proto(progress: Option<Progress>, i18n: &I18n) -> pb::Progress {
} }
} }
fn media_sync_progress(p: MediaSyncProgress, i18n: &I18n) -> pb::MediaSyncProgress { fn media_sync_progress(p: MediaSyncProgress, i18n: &I18n) -> pb::progress::MediaSync {
pb::MediaSyncProgress { pb::progress::MediaSync {
checked: i18n.trn(TR::SyncMediaCheckedCount, tr_args!["count"=>p.checked]), checked: i18n.trn(TR::SyncMediaCheckedCount, tr_args!["count"=>p.checked]),
added: i18n.trn( added: i18n.trn(
TR::SyncMediaAddedCount, TR::SyncMediaAddedCount,