mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
add a bunch of return types
This commit is contained in:
parent
f15715fb07
commit
a56b09b987
41 changed files with 359 additions and 338 deletions
|
@ -10,7 +10,7 @@ import os
|
|||
import sys
|
||||
import tempfile
|
||||
import traceback
|
||||
from typing import Any, Callable, Dict, Optional, Union
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
||||
|
||||
import anki.lang
|
||||
from anki import version as _version
|
||||
|
@ -102,10 +102,10 @@ class DialogManager:
|
|||
self._dialogs[name][1] = instance
|
||||
return instance
|
||||
|
||||
def markClosed(self, name: str):
|
||||
def markClosed(self, name: str) -> None:
|
||||
self._dialogs[name] = [self._dialogs[name][0], None]
|
||||
|
||||
def allClosed(self):
|
||||
def allClosed(self) -> bool:
|
||||
return not any(x[1] for x in self._dialogs.values())
|
||||
|
||||
def closeAll(self, onsuccess: Callable[[], None]) -> Optional[bool]:
|
||||
|
@ -119,7 +119,7 @@ class DialogManager:
|
|||
if not instance:
|
||||
continue
|
||||
|
||||
def callback():
|
||||
def callback() -> None:
|
||||
if self.allClosed():
|
||||
onsuccess()
|
||||
else:
|
||||
|
@ -189,12 +189,12 @@ def setupLangAndBackend(
|
|||
pass
|
||||
|
||||
# add _ and ngettext globals used by legacy code
|
||||
def fn__(arg):
|
||||
def fn__(arg) -> None:
|
||||
print("".join(traceback.format_stack()[-2]))
|
||||
print("_ global will break in the future; please see anki/lang.py")
|
||||
return arg
|
||||
|
||||
def fn_ngettext(a, b, c):
|
||||
def fn_ngettext(a, b, c) -> None:
|
||||
print("".join(traceback.format_stack()[-2]))
|
||||
print("ngettext global will break in the future; please see anki/lang.py")
|
||||
return b
|
||||
|
@ -244,11 +244,11 @@ class AnkiApp(QApplication):
|
|||
KEY = "anki" + checksum(getpass.getuser())
|
||||
TMOUT = 30000
|
||||
|
||||
def __init__(self, argv):
|
||||
def __init__(self, argv) -> None:
|
||||
QApplication.__init__(self, argv)
|
||||
self._argv = argv
|
||||
|
||||
def secondInstance(self):
|
||||
def secondInstance(self) -> bool:
|
||||
# we accept only one command line argument. if it's missing, send
|
||||
# a blank screen to just raise the existing window
|
||||
opts, args = parseArgs(self._argv)
|
||||
|
@ -267,7 +267,7 @@ class AnkiApp(QApplication):
|
|||
self._srv.listen(self.KEY)
|
||||
return False
|
||||
|
||||
def sendMsg(self, txt):
|
||||
def sendMsg(self, txt) -> bool:
|
||||
sock = QLocalSocket(self)
|
||||
sock.connectToServer(self.KEY, QIODevice.WriteOnly)
|
||||
if not sock.waitForConnected(self.TMOUT):
|
||||
|
@ -286,7 +286,7 @@ class AnkiApp(QApplication):
|
|||
sock.disconnectFromServer()
|
||||
return True
|
||||
|
||||
def onRecv(self):
|
||||
def onRecv(self) -> None:
|
||||
sock = self._srv.nextPendingConnection()
|
||||
if not sock.waitForReadyRead(self.TMOUT):
|
||||
sys.stderr.write(sock.errorString())
|
||||
|
@ -298,14 +298,14 @@ class AnkiApp(QApplication):
|
|||
# OS X file/url handler
|
||||
##################################################
|
||||
|
||||
def event(self, evt):
|
||||
def event(self, evt) -> bool:
|
||||
if evt.type() == QEvent.FileOpen:
|
||||
self.appMsg.emit(evt.file() or "raise") # type: ignore
|
||||
return True
|
||||
return QApplication.event(self, evt)
|
||||
|
||||
|
||||
def parseArgs(argv):
|
||||
def parseArgs(argv) -> Tuple[argparse.Namespace, List[str]]:
|
||||
"Returns (opts, args)."
|
||||
# py2app fails to strip this in some instances, then anki dies
|
||||
# as there's no such profile
|
||||
|
@ -330,7 +330,7 @@ def parseArgs(argv):
|
|||
return parser.parse_known_args(argv[1:])
|
||||
|
||||
|
||||
def setupGL(pm):
|
||||
def setupGL(pm) -> None:
|
||||
if isMac:
|
||||
return
|
||||
|
||||
|
@ -343,7 +343,7 @@ def setupGL(pm):
|
|||
ctypes.CDLL("libGL.so.1", ctypes.RTLD_GLOBAL)
|
||||
|
||||
# catch opengl errors
|
||||
def msgHandler(category, ctx, msg):
|
||||
def msgHandler(category, ctx, msg) -> None:
|
||||
if category == QtDebugMsg:
|
||||
category = "debug"
|
||||
elif category == QtInfoMsg:
|
||||
|
@ -400,7 +400,7 @@ def setupGL(pm):
|
|||
PROFILE_CODE = os.environ.get("ANKI_PROFILE_CODE")
|
||||
|
||||
|
||||
def write_profile_results():
|
||||
def write_profile_results() -> None:
|
||||
|
||||
profiler.disable()
|
||||
profiler.dump_stats("anki.prof")
|
||||
|
@ -408,7 +408,7 @@ def write_profile_results():
|
|||
print("use 'bazel run qt:profile' to explore")
|
||||
|
||||
|
||||
def run():
|
||||
def run() -> None:
|
||||
try:
|
||||
_run()
|
||||
except Exception as e:
|
||||
|
@ -420,7 +420,7 @@ def run():
|
|||
)
|
||||
|
||||
|
||||
def _run(argv=None, exec=True):
|
||||
def _run(argv=None, exec=True) -> Optional[AnkiApp]:
|
||||
"""Start AnkiQt application or reuse an existing instance if one exists.
|
||||
|
||||
If the function is invoked with exec=False, the AnkiQt will not enter
|
||||
|
@ -441,12 +441,12 @@ def _run(argv=None, exec=True):
|
|||
|
||||
if opts.version:
|
||||
print(f"Anki {appVersion}")
|
||||
return
|
||||
return None
|
||||
elif opts.syncserver:
|
||||
from anki.syncserver import serve
|
||||
|
||||
serve()
|
||||
return
|
||||
return None
|
||||
|
||||
if PROFILE_CODE:
|
||||
|
||||
|
@ -465,7 +465,7 @@ def _run(argv=None, exec=True):
|
|||
except AnkiRestart as error:
|
||||
if error.exitcode:
|
||||
sys.exit(error.exitcode)
|
||||
return
|
||||
return None
|
||||
except:
|
||||
# will handle below
|
||||
traceback.print_exc()
|
||||
|
@ -500,7 +500,7 @@ def _run(argv=None, exec=True):
|
|||
app = AnkiApp(argv)
|
||||
if app.secondInstance():
|
||||
# we've signaled the primary instance, so we should close
|
||||
return
|
||||
return None
|
||||
|
||||
if not pm:
|
||||
QMessageBox.critical(
|
||||
|
@ -508,7 +508,7 @@ def _run(argv=None, exec=True):
|
|||
tr(TR.QT_MISC_ERROR),
|
||||
tr(TR.PROFILES_COULD_NOT_CREATE_DATA_FOLDER),
|
||||
)
|
||||
return
|
||||
return None
|
||||
|
||||
# disable icons on mac; this must be done before window created
|
||||
if isMac:
|
||||
|
@ -548,7 +548,7 @@ def _run(argv=None, exec=True):
|
|||
tr(TR.QT_MISC_ERROR),
|
||||
tr(TR.QT_MISC_NO_TEMP_FOLDER),
|
||||
)
|
||||
return
|
||||
return None
|
||||
|
||||
if pmLoadResult.firstTime:
|
||||
pm.setDefaultLang(lang[0])
|
||||
|
@ -590,3 +590,5 @@ def _run(argv=None, exec=True):
|
|||
|
||||
if PROFILE_CODE:
|
||||
write_profile_results()
|
||||
|
||||
return None
|
||||
|
|
|
@ -13,20 +13,20 @@ from aqt.utils import TR, disable_help_button, supportText, tooltip, tr
|
|||
|
||||
|
||||
class ClosableQDialog(QDialog):
|
||||
def reject(self):
|
||||
def reject(self) -> None:
|
||||
aqt.dialogs.markClosed("About")
|
||||
QDialog.reject(self)
|
||||
|
||||
def accept(self):
|
||||
def accept(self) -> None:
|
||||
aqt.dialogs.markClosed("About")
|
||||
QDialog.accept(self)
|
||||
|
||||
def closeWithCallback(self, callback):
|
||||
def closeWithCallback(self, callback) -> None:
|
||||
self.reject()
|
||||
callback()
|
||||
|
||||
|
||||
def show(mw):
|
||||
def show(mw) -> QDialog:
|
||||
dialog = ClosableQDialog(mw)
|
||||
disable_help_button(dialog)
|
||||
mw.setupDialogGC(dialog)
|
||||
|
@ -55,7 +55,7 @@ def show(mw):
|
|||
modified = "mod"
|
||||
return f"{name} ['{addon.dir_name}', {installed}, '{addon.human_version}', {modified}]"
|
||||
|
||||
def onCopy():
|
||||
def onCopy() -> None:
|
||||
addmgr = mw.addonManager
|
||||
active = []
|
||||
activeids = []
|
||||
|
|
|
@ -65,7 +65,7 @@ class AddCards(QDialog):
|
|||
)
|
||||
self.deckChooser = aqt.deckchooser.DeckChooser(self.mw, self.form.deckArea)
|
||||
|
||||
def helpRequested(self):
|
||||
def helpRequested(self) -> None:
|
||||
openHelp(HelpPage.ADDING_CARD_AND_NOTE)
|
||||
|
||||
def setupButtons(self) -> None:
|
||||
|
@ -161,7 +161,7 @@ class AddCards(QDialog):
|
|||
gui_hooks.add_cards_will_show_history_menu(self, m)
|
||||
m.exec_(self.historyButton.mapToGlobal(QPoint(0, 0)))
|
||||
|
||||
def editHistory(self, nid):
|
||||
def editHistory(self, nid) -> None:
|
||||
self.mw.browser_search(SearchTerm(nid=nid))
|
||||
|
||||
def addNote(self, note) -> Optional[Note]:
|
||||
|
@ -225,7 +225,7 @@ class AddCards(QDialog):
|
|||
QDialog.reject(self)
|
||||
|
||||
def ifCanClose(self, onOk: Callable) -> None:
|
||||
def afterSave():
|
||||
def afterSave() -> None:
|
||||
ok = self.editor.fieldsAreBlank(self.previousNote) or askUser(
|
||||
tr(TR.ADDING_CLOSE_AND_LOSE_CURRENT_INPUT), defaultno=True
|
||||
)
|
||||
|
@ -234,8 +234,8 @@ class AddCards(QDialog):
|
|||
|
||||
self.editor.saveNow(afterSave)
|
||||
|
||||
def closeWithCallback(self, cb):
|
||||
def doClose():
|
||||
def closeWithCallback(self, cb) -> None:
|
||||
def doClose() -> None:
|
||||
self._reject()
|
||||
cb()
|
||||
|
||||
|
|
|
@ -605,7 +605,7 @@ class AddonManager:
|
|||
def _addon_schema_path(self, dir: str) -> str:
|
||||
return os.path.join(self.addonsFolder(dir), "config.schema.json")
|
||||
|
||||
def _addon_schema(self, dir: str):
|
||||
def _addon_schema(self, dir: str) -> Any:
|
||||
path = self._addon_schema_path(dir)
|
||||
try:
|
||||
if not os.path.exists(path):
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import copy
|
||||
import json
|
||||
import re
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict, List, Match, Optional
|
||||
|
||||
import aqt
|
||||
from anki.cards import Card
|
||||
|
@ -140,7 +140,7 @@ class CardLayout(QDialog):
|
|||
combo.setEnabled(not self._isCloze())
|
||||
self.ignore_change_signals = False
|
||||
|
||||
def _summarizedName(self, idx: int, tmpl: Dict):
|
||||
def _summarizedName(self, idx: int, tmpl: Dict) -> str:
|
||||
return "{}: {}: {} -> {}".format(
|
||||
idx + 1,
|
||||
tmpl["name"],
|
||||
|
@ -284,7 +284,7 @@ class CardLayout(QDialog):
|
|||
|
||||
self.fill_fields_from_template()
|
||||
|
||||
def on_search_changed(self, text: str):
|
||||
def on_search_changed(self, text: str) -> None:
|
||||
editor = self.tform.edit_area
|
||||
if not editor.find(text):
|
||||
# try again from top
|
||||
|
@ -294,7 +294,7 @@ class CardLayout(QDialog):
|
|||
if not editor.find(text):
|
||||
tooltip("No matches found.")
|
||||
|
||||
def on_search_next(self):
|
||||
def on_search_next(self) -> None:
|
||||
text = self.tform.search_edit.text()
|
||||
self.on_search_changed(text)
|
||||
|
||||
|
@ -341,7 +341,7 @@ class CardLayout(QDialog):
|
|||
self.fill_empty_action_toggled = not self.fill_empty_action_toggled
|
||||
self.on_preview_toggled()
|
||||
|
||||
def on_night_mode_action_toggled(self):
|
||||
def on_night_mode_action_toggled(self) -> None:
|
||||
self.night_mode_is_enabled = not self.night_mode_is_enabled
|
||||
self.on_preview_toggled()
|
||||
|
||||
|
@ -520,7 +520,7 @@ class CardLayout(QDialog):
|
|||
txt = txt.replace("<hr id=answer>", "")
|
||||
hadHR = origLen != len(txt)
|
||||
|
||||
def answerRepl(match):
|
||||
def answerRepl(match: Match) -> str:
|
||||
res = self.mw.reviewer.correct("exomple", "an example")
|
||||
if hadHR:
|
||||
res = "<hr id=answer>" + res
|
||||
|
@ -556,14 +556,15 @@ class CardLayout(QDialog):
|
|||
# Card operations
|
||||
######################################################################
|
||||
|
||||
def onRemove(self):
|
||||
def onRemove(self) -> None:
|
||||
if len(self.templates) < 2:
|
||||
return showInfo(tr(TR.CARD_TEMPLATES_AT_LEAST_ONE_CARD_TYPE_IS))
|
||||
showInfo(tr(TR.CARD_TEMPLATES_AT_LEAST_ONE_CARD_TYPE_IS))
|
||||
return
|
||||
|
||||
def get_count():
|
||||
def get_count() -> int:
|
||||
return self.mm.template_use_count(self.model["id"], self.ord)
|
||||
|
||||
def on_done(fut):
|
||||
def on_done(fut) -> None:
|
||||
card_cnt = fut.result()
|
||||
|
||||
template = self.current_template()
|
||||
|
@ -593,7 +594,7 @@ class CardLayout(QDialog):
|
|||
|
||||
self.redraw_everything()
|
||||
|
||||
def onRename(self):
|
||||
def onRename(self) -> None:
|
||||
template = self.current_template()
|
||||
name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=template["name"]).replace(
|
||||
'"', ""
|
||||
|
@ -604,7 +605,7 @@ class CardLayout(QDialog):
|
|||
template["name"] = name
|
||||
self.redraw_everything()
|
||||
|
||||
def onReorder(self):
|
||||
def onReorder(self) -> None:
|
||||
n = len(self.templates)
|
||||
template = self.current_template()
|
||||
current_pos = self.templates.index(template) + 1
|
||||
|
@ -629,7 +630,7 @@ class CardLayout(QDialog):
|
|||
self.ord = new_idx
|
||||
self.redraw_everything()
|
||||
|
||||
def _newCardName(self):
|
||||
def _newCardName(self) -> str:
|
||||
n = len(self.templates) + 1
|
||||
while 1:
|
||||
name = without_unicode_isolation(tr(TR.CARD_TEMPLATES_CARD, val=n))
|
||||
|
@ -638,7 +639,7 @@ class CardLayout(QDialog):
|
|||
n += 1
|
||||
return name
|
||||
|
||||
def onAddCard(self):
|
||||
def onAddCard(self) -> None:
|
||||
cnt = self.mw.col.models.useCount(self.model)
|
||||
txt = tr(TR.CARD_TEMPLATES_THIS_WILL_CREATE_CARD_PROCEED, count=cnt)
|
||||
if not askUser(txt):
|
||||
|
@ -654,12 +655,12 @@ class CardLayout(QDialog):
|
|||
self.ord = len(self.templates) - 1
|
||||
self.redraw_everything()
|
||||
|
||||
def onFlip(self):
|
||||
def onFlip(self) -> None:
|
||||
old = self.current_template()
|
||||
self._flipQA(old, old)
|
||||
self.redraw_everything()
|
||||
|
||||
def _flipQA(self, src, dst):
|
||||
def _flipQA(self, src, dst) -> None:
|
||||
m = re.match("(?s)(.+)<hr id=answer>(.+)", src["afmt"])
|
||||
if not m:
|
||||
showInfo(tr(TR.CARD_TEMPLATES_ANKI_COULDNT_FIND_THE_LINE_BETWEEN))
|
||||
|
@ -667,7 +668,6 @@ class CardLayout(QDialog):
|
|||
self.change_tracker.mark_basic()
|
||||
dst["afmt"] = "{{FrontSide}}\n\n<hr id=answer>\n\n%s" % src["qfmt"]
|
||||
dst["qfmt"] = m.group(2).strip()
|
||||
return True
|
||||
|
||||
def onMore(self) -> None:
|
||||
m = QMenu(self)
|
||||
|
@ -728,7 +728,7 @@ class CardLayout(QDialog):
|
|||
if key in t:
|
||||
del t[key]
|
||||
|
||||
def onTargetDeck(self):
|
||||
def onTargetDeck(self) -> None:
|
||||
from aqt.tagedit import TagEdit
|
||||
|
||||
t = self.current_template()
|
||||
|
@ -760,7 +760,7 @@ class CardLayout(QDialog):
|
|||
else:
|
||||
t["did"] = self.col.decks.id(te.text())
|
||||
|
||||
def onAddField(self):
|
||||
def onAddField(self) -> None:
|
||||
diag = QDialog(self)
|
||||
form = aqt.forms.addfield.Ui_Dialog()
|
||||
form.setupUi(diag)
|
||||
|
@ -780,7 +780,7 @@ class CardLayout(QDialog):
|
|||
form.size.value(),
|
||||
)
|
||||
|
||||
def _addField(self, field, font, size):
|
||||
def _addField(self, field, font, size) -> None:
|
||||
text = self.tform.edit_area.toPlainText()
|
||||
text += "\n<div style='font-family: %s; font-size: %spx;'>{{%s}}</div>\n" % (
|
||||
font,
|
||||
|
@ -795,10 +795,10 @@ class CardLayout(QDialog):
|
|||
######################################################################
|
||||
|
||||
def accept(self) -> None:
|
||||
def save():
|
||||
def save() -> None:
|
||||
self.mm.save(self.model)
|
||||
|
||||
def on_done(fut):
|
||||
def on_done(fut) -> None:
|
||||
try:
|
||||
fut.result()
|
||||
except TemplateError as e:
|
||||
|
@ -829,5 +829,5 @@ class CardLayout(QDialog):
|
|||
self.rendered_card = None
|
||||
self.mw = None
|
||||
|
||||
def onHelp(self):
|
||||
def onHelp(self) -> None:
|
||||
openHelp(HelpPage.TEMPLATES)
|
||||
|
|
|
@ -57,7 +57,7 @@ class CustomStudy(QDialog):
|
|||
typeShow = False
|
||||
ok = tr(TR.CUSTOM_STUDY_OK)
|
||||
|
||||
def plus(num):
|
||||
def plus(num) -> str:
|
||||
if num == 1000:
|
||||
num = "1000+"
|
||||
return "<b>" + str(num) + "</b>"
|
||||
|
|
|
@ -9,7 +9,7 @@ from aqt.qt import *
|
|||
from aqt.utils import showText, tooltip
|
||||
|
||||
|
||||
def on_progress(mw: aqt.main.AnkiQt):
|
||||
def on_progress(mw: aqt.main.AnkiQt) -> None:
|
||||
progress = mw.col.latest_progress()
|
||||
if progress.kind != ProgressKind.DatabaseCheck:
|
||||
return
|
||||
|
@ -24,14 +24,14 @@ def on_progress(mw: aqt.main.AnkiQt):
|
|||
|
||||
|
||||
def check_db(mw: aqt.AnkiQt) -> None:
|
||||
def on_timer():
|
||||
def on_timer() -> None:
|
||||
on_progress(mw)
|
||||
|
||||
timer = QTimer(mw)
|
||||
qconnect(timer.timeout, on_timer)
|
||||
timer.start(100)
|
||||
|
||||
def on_future_done(fut):
|
||||
def on_future_done(fut) -> None:
|
||||
timer.stop()
|
||||
ret, ok = fut.result()
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ from aqt.utils import TR, askUser, getOnlyText, openLink, shortcut, showWarning,
|
|||
|
||||
|
||||
class DeckBrowserBottomBar:
|
||||
def __init__(self, deck_browser: DeckBrowser):
|
||||
def __init__(self, deck_browser: DeckBrowser) -> None:
|
||||
self.deck_browser = deck_browser
|
||||
|
||||
|
||||
|
@ -51,14 +51,14 @@ class DeckBrowser:
|
|||
self.bottom = BottomBar(mw, mw.bottomWeb)
|
||||
self.scrollPos = QPoint(0, 0)
|
||||
|
||||
def show(self):
|
||||
def show(self) -> None:
|
||||
av_player.stop_and_clear_queue()
|
||||
self.web.set_bridge_command(self._linkHandler, self)
|
||||
self._renderPage()
|
||||
# redraw top bar for theme change
|
||||
self.mw.toolbar.redraw()
|
||||
|
||||
def refresh(self):
|
||||
def refresh(self) -> None:
|
||||
self._renderPage()
|
||||
|
||||
# Event handlers
|
||||
|
@ -90,7 +90,7 @@ class DeckBrowser:
|
|||
self._collapse(int(arg))
|
||||
return False
|
||||
|
||||
def _selDeck(self, did):
|
||||
def _selDeck(self, did) -> None:
|
||||
self.mw.col.decks.select(did)
|
||||
self.mw.onOverview()
|
||||
|
||||
|
@ -108,14 +108,14 @@ class DeckBrowser:
|
|||
</center>
|
||||
"""
|
||||
|
||||
def _renderPage(self, reuse=False):
|
||||
def _renderPage(self, reuse=False) -> None:
|
||||
if not reuse:
|
||||
self._dueTree = self.mw.col.sched.deck_due_tree()
|
||||
self.__renderPage(None)
|
||||
return
|
||||
self.web.evalWithCallback("window.pageYOffset", self.__renderPage)
|
||||
|
||||
def __renderPage(self, offset):
|
||||
def __renderPage(self, offset) -> None:
|
||||
content = DeckBrowserContent(
|
||||
tree=self._renderDeckTree(self._dueTree),
|
||||
stats=self._renderStats(),
|
||||
|
@ -137,10 +137,10 @@ class DeckBrowser:
|
|||
self._scrollToOffset(offset)
|
||||
gui_hooks.deck_browser_did_render(self)
|
||||
|
||||
def _scrollToOffset(self, offset):
|
||||
def _scrollToOffset(self, offset) -> None:
|
||||
self.web.eval("$(function() { window.scrollTo(0, %d, 'instant'); });" % offset)
|
||||
|
||||
def _renderStats(self):
|
||||
def _renderStats(self) -> str:
|
||||
return '<div id="studiedToday"><span>{}</span></div>'.format(
|
||||
self.mw.col.studied_today(),
|
||||
)
|
||||
|
@ -170,7 +170,7 @@ class DeckBrowser:
|
|||
|
||||
due = node.review_count + node.learn_count
|
||||
|
||||
def indent():
|
||||
def indent() -> str:
|
||||
return " " * 6 * (node.level - 1)
|
||||
|
||||
if node.deck_id == ctx.current_deck_id:
|
||||
|
@ -202,7 +202,7 @@ class DeckBrowser:
|
|||
node.name,
|
||||
)
|
||||
# due counts
|
||||
def nonzeroColour(cnt, klass):
|
||||
def nonzeroColour(cnt: int, klass: str) -> str:
|
||||
if not cnt:
|
||||
klass = "zero-count"
|
||||
return f'<span class="{klass}">{cnt}</span>'
|
||||
|
@ -222,7 +222,7 @@ class DeckBrowser:
|
|||
buf += self._render_deck_node(child, ctx)
|
||||
return buf
|
||||
|
||||
def _topLevelDragRow(self):
|
||||
def _topLevelDragRow(self) -> str:
|
||||
return "<tr class='top-level-drag-row'><td colspan='6'> </td></tr>"
|
||||
|
||||
# Options
|
||||
|
@ -260,7 +260,7 @@ class DeckBrowser:
|
|||
return
|
||||
self.show()
|
||||
|
||||
def _options(self, did):
|
||||
def _options(self, did) -> None:
|
||||
# select the deck first, because the dyn deck conf assumes the deck
|
||||
# we're editing is the current one
|
||||
self.mw.col.decks.select(did)
|
||||
|
@ -297,10 +297,10 @@ class DeckBrowser:
|
|||
def _delete(self, did: int) -> None:
|
||||
if self.ask_delete_deck(did):
|
||||
|
||||
def do_delete():
|
||||
def do_delete() -> None:
|
||||
return self.mw.col.decks.rem(did, True)
|
||||
|
||||
def on_done(fut: Future):
|
||||
def on_done(fut: Future) -> None:
|
||||
self.show()
|
||||
res = fut.result() # Required to check for errors
|
||||
|
||||
|
@ -316,7 +316,7 @@ class DeckBrowser:
|
|||
["Ctrl+Shift+I", "import", tr(TR.DECKS_IMPORT_FILE)],
|
||||
]
|
||||
|
||||
def _drawButtons(self):
|
||||
def _drawButtons(self) -> None:
|
||||
buf = ""
|
||||
drawLinks = deepcopy(self.drawLinks)
|
||||
for b in drawLinks:
|
||||
|
@ -332,5 +332,5 @@ class DeckBrowser:
|
|||
web_context=DeckBrowserBottomBar(self),
|
||||
)
|
||||
|
||||
def _onShared(self):
|
||||
def _onShared(self) -> None:
|
||||
openLink(aqt.appShared + "decks/")
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
from operator import itemgetter
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from PyQt5.QtWidgets import QLineEdit
|
||||
|
||||
import aqt
|
||||
from anki.consts import NEW_CARDS_RANDOM
|
||||
from anki.decks import DeckConfig
|
||||
from anki.lang import without_unicode_isolation
|
||||
from aqt import gui_hooks
|
||||
from aqt.qt import *
|
||||
|
@ -28,7 +29,7 @@ from aqt.utils import (
|
|||
|
||||
|
||||
class DeckConf(QDialog):
|
||||
def __init__(self, mw: aqt.AnkiQt, deck: Dict):
|
||||
def __init__(self, mw: aqt.AnkiQt, deck: Dict) -> None:
|
||||
QDialog.__init__(self, mw)
|
||||
self.mw = mw
|
||||
self.deck = deck
|
||||
|
@ -60,7 +61,7 @@ class DeckConf(QDialog):
|
|||
self.exec_()
|
||||
saveGeom(self, "deckconf")
|
||||
|
||||
def setupCombos(self):
|
||||
def setupCombos(self) -> None:
|
||||
import anki.consts as cs
|
||||
|
||||
f = self.form
|
||||
|
@ -70,12 +71,12 @@ class DeckConf(QDialog):
|
|||
# Conf list
|
||||
######################################################################
|
||||
|
||||
def setupConfs(self):
|
||||
def setupConfs(self) -> None:
|
||||
qconnect(self.form.dconf.currentIndexChanged, self.onConfChange)
|
||||
self.conf = None
|
||||
self.conf: Optional[DeckConfig] = None
|
||||
self.loadConfs()
|
||||
|
||||
def loadConfs(self):
|
||||
def loadConfs(self) -> None:
|
||||
current = self.deck["conf"]
|
||||
self.confList = self.mw.col.decks.allConf()
|
||||
self.confList.sort(key=itemgetter("name"))
|
||||
|
@ -92,7 +93,7 @@ class DeckConf(QDialog):
|
|||
self._origNewOrder = self.confList[startOn]["new"]["order"]
|
||||
self.onConfChange(startOn)
|
||||
|
||||
def confOpts(self):
|
||||
def confOpts(self) -> None:
|
||||
m = QMenu(self.mw)
|
||||
a = m.addAction(tr(TR.ACTIONS_ADD))
|
||||
qconnect(a.triggered, self.addGroup)
|
||||
|
@ -106,7 +107,7 @@ class DeckConf(QDialog):
|
|||
a.setEnabled(False)
|
||||
m.exec_(QCursor.pos())
|
||||
|
||||
def onConfChange(self, idx):
|
||||
def onConfChange(self, idx) -> None:
|
||||
if self.ignoreConfChange:
|
||||
return
|
||||
if self.conf:
|
||||
|
@ -159,7 +160,7 @@ class DeckConf(QDialog):
|
|||
self.saveConf()
|
||||
self.loadConfs()
|
||||
|
||||
def setChildren(self):
|
||||
def setChildren(self) -> None:
|
||||
if not askUser(tr(TR.SCHEDULING_SET_ALL_DECKS_BELOW_TO, val=self.deck["name"])):
|
||||
return
|
||||
for did in self.childDids:
|
||||
|
@ -173,8 +174,8 @@ class DeckConf(QDialog):
|
|||
# Loading
|
||||
##################################################
|
||||
|
||||
def listToUser(self, l):
|
||||
def num_to_user(n: Union[int, float]):
|
||||
def listToUser(self, l) -> str:
|
||||
def num_to_user(n: Union[int, float]) -> str:
|
||||
if n == round(n):
|
||||
return str(int(n))
|
||||
else:
|
||||
|
@ -182,7 +183,7 @@ class DeckConf(QDialog):
|
|||
|
||||
return " ".join(map(num_to_user, l))
|
||||
|
||||
def parentLimText(self, type="new"):
|
||||
def parentLimText(self, type="new") -> str:
|
||||
# top level?
|
||||
if "::" not in self.deck["name"]:
|
||||
return ""
|
||||
|
@ -196,7 +197,7 @@ class DeckConf(QDialog):
|
|||
lim = min(x, lim)
|
||||
return tr(TR.SCHEDULING_PARENT_LIMIT, val=lim)
|
||||
|
||||
def loadConf(self):
|
||||
def loadConf(self) -> None:
|
||||
self.conf = self.mw.col.decks.confForDid(self.deck["id"])
|
||||
# new
|
||||
c = self.conf["new"]
|
||||
|
@ -238,7 +239,7 @@ class DeckConf(QDialog):
|
|||
f.desc.setPlainText(self.deck["desc"])
|
||||
gui_hooks.deck_conf_did_load_config(self, self.deck, self.conf)
|
||||
|
||||
def onRestore(self):
|
||||
def onRestore(self) -> None:
|
||||
self.mw.progress.start()
|
||||
self.mw.col.decks.restoreToDefault(self.conf)
|
||||
self.mw.progress.finish()
|
||||
|
@ -247,7 +248,7 @@ class DeckConf(QDialog):
|
|||
# New order
|
||||
##################################################
|
||||
|
||||
def onNewOrderChanged(self, new):
|
||||
def onNewOrderChanged(self, new) -> None:
|
||||
old = self.conf["new"]["order"]
|
||||
if old == new:
|
||||
return
|
||||
|
@ -280,7 +281,7 @@ class DeckConf(QDialog):
|
|||
return
|
||||
conf[key] = ret
|
||||
|
||||
def saveConf(self):
|
||||
def saveConf(self) -> None:
|
||||
# new
|
||||
c = self.conf["new"]
|
||||
f = self.form
|
||||
|
@ -324,10 +325,10 @@ class DeckConf(QDialog):
|
|||
self.mw.col.decks.save(self.deck)
|
||||
self.mw.col.decks.save(self.conf)
|
||||
|
||||
def reject(self):
|
||||
def reject(self) -> None:
|
||||
self.accept()
|
||||
|
||||
def accept(self):
|
||||
def accept(self) -> None:
|
||||
self.saveConf()
|
||||
self.mw.reset()
|
||||
QDialog.accept(self)
|
||||
|
|
|
@ -145,7 +145,7 @@ class DeckConf(QDialog):
|
|||
|
||||
self.mw.col.decks.save(d)
|
||||
|
||||
def reject(self):
|
||||
def reject(self) -> None:
|
||||
self.ok = False
|
||||
QDialog.reject(self)
|
||||
|
||||
|
@ -164,7 +164,7 @@ class DeckConf(QDialog):
|
|||
# Step load/save - fixme: share with std options screen
|
||||
########################################################
|
||||
|
||||
def listToUser(self, l):
|
||||
def listToUser(self, l) -> str:
|
||||
return " ".join([str(x) for x in l])
|
||||
|
||||
def userToList(self, w, minSize=1) -> Optional[List[Union[float, int]]]:
|
||||
|
|
|
@ -48,7 +48,7 @@ class EditCurrent(QDialog):
|
|||
return
|
||||
self.editor.setNote(n)
|
||||
|
||||
def reopen(self, mw):
|
||||
def reopen(self, mw) -> None:
|
||||
tooltip("Please finish editing the existing card first.")
|
||||
self.onReset()
|
||||
|
||||
|
@ -74,8 +74,8 @@ class EditCurrent(QDialog):
|
|||
aqt.dialogs.markClosed("EditCurrent")
|
||||
QDialog.reject(self)
|
||||
|
||||
def closeWithCallback(self, onsuccess):
|
||||
def callback():
|
||||
def closeWithCallback(self, onsuccess) -> None:
|
||||
def callback() -> None:
|
||||
self._saveAndClose()
|
||||
onsuccess()
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ from aqt.utils import TR, disable_help_button, restoreGeom, saveGeom, tooltip, t
|
|||
def show_empty_cards(mw: aqt.main.AnkiQt) -> None:
|
||||
mw.progress.start()
|
||||
|
||||
def on_done(fut):
|
||||
def on_done(fut) -> None:
|
||||
mw.progress.finish()
|
||||
report: EmptyCardsReport = fut.result()
|
||||
if not report.notes:
|
||||
|
@ -54,7 +54,7 @@ class EmptyCardsDialog(QDialog):
|
|||
style = "<style>.allempty { color: red; }</style>"
|
||||
self.form.webview.stdHtml(style + html, context=self)
|
||||
|
||||
def on_finished(code):
|
||||
def on_finished(code) -> None:
|
||||
saveGeom(self, "emptycards")
|
||||
|
||||
qconnect(self.finished, on_finished)
|
||||
|
@ -65,16 +65,16 @@ class EmptyCardsDialog(QDialog):
|
|||
self._delete_button.setAutoDefault(False)
|
||||
self._delete_button.clicked.connect(self._on_delete)
|
||||
|
||||
def _on_note_link_clicked(self, link):
|
||||
def _on_note_link_clicked(self, link) -> None:
|
||||
self.mw.browser_search(link)
|
||||
|
||||
def _on_delete(self) -> None:
|
||||
self.mw.progress.start()
|
||||
|
||||
def delete():
|
||||
def delete() -> int:
|
||||
return self._delete_cards(self.form.keep_notes.isChecked())
|
||||
|
||||
def on_done(fut):
|
||||
def on_done(fut) -> None:
|
||||
self.mw.progress.finish()
|
||||
try:
|
||||
count = fut.result()
|
||||
|
|
|
@ -16,7 +16,7 @@ from aqt.utils import TR, showText, showWarning, supportText, tr
|
|||
|
||||
if not os.environ.get("DEBUG"):
|
||||
|
||||
def excepthook(etype, val, tb):
|
||||
def excepthook(etype, val, tb) -> None:
|
||||
sys.stderr.write(
|
||||
"Caught exception:\n%s\n"
|
||||
% ("".join(traceback.format_exception(etype, val, tb)))
|
||||
|
@ -65,7 +65,7 @@ class ErrorHandler(QObject):
|
|||
self.timer.setSingleShot(True)
|
||||
self.timer.start()
|
||||
|
||||
def tempFolderMsg(self):
|
||||
def tempFolderMsg(self) -> str:
|
||||
return tr(TR.QT_MISC_UNABLE_TO_ACCESS_ANKI_MEDIA_FOLDER)
|
||||
|
||||
def onTimeout(self) -> None:
|
||||
|
@ -105,7 +105,7 @@ class ErrorHandler(QObject):
|
|||
txt = txt + "<div style='white-space: pre-wrap'>" + error + "</div>"
|
||||
showText(txt, type="html", copyBtn=True)
|
||||
|
||||
def _addonText(self, error):
|
||||
def _addonText(self, error: str) -> str:
|
||||
matches = re.findall(r"addons21/(.*?)/", error)
|
||||
if not matches:
|
||||
return ""
|
||||
|
|
|
@ -42,7 +42,7 @@ class ExportDialog(QDialog):
|
|||
self.setup(did)
|
||||
self.exec_()
|
||||
|
||||
def setup(self, did: Optional[int]):
|
||||
def setup(self, did: Optional[int]) -> None:
|
||||
self.exporters = exporters(self.col)
|
||||
# if a deck specified, start with .apkg type selected
|
||||
idx = 0
|
||||
|
@ -155,17 +155,17 @@ class ExportDialog(QDialog):
|
|||
os.unlink(file)
|
||||
|
||||
# progress handler
|
||||
def exported_media(cnt):
|
||||
def exported_media(cnt) -> None:
|
||||
self.mw.taskman.run_on_main(
|
||||
lambda: self.mw.progress.update(
|
||||
label=tr(TR.EXPORTING_EXPORTED_MEDIA_FILE, count=cnt)
|
||||
)
|
||||
)
|
||||
|
||||
def do_export():
|
||||
def do_export() -> None:
|
||||
self.exporter.exportInto(file)
|
||||
|
||||
def on_done(future: Future):
|
||||
def on_done(future: Future) -> None:
|
||||
self.mw.progress.finish()
|
||||
hooks.media_files_did_export.remove(exported_media)
|
||||
# raises if exporter failed
|
||||
|
|
|
@ -23,7 +23,7 @@ from aqt.utils import (
|
|||
|
||||
|
||||
class FieldDialog(QDialog):
|
||||
def __init__(self, mw: AnkiQt, nt: NoteType, parent=None):
|
||||
def __init__(self, mw: AnkiQt, nt: NoteType, parent=None) -> None:
|
||||
QDialog.__init__(self, parent or mw)
|
||||
self.mw = mw
|
||||
self.col = self.mw.col
|
||||
|
@ -68,7 +68,7 @@ class FieldDialog(QDialog):
|
|||
qconnect(f.sortField.clicked, self.onSortField)
|
||||
qconnect(f.buttonBox.helpRequested, self.onHelp)
|
||||
|
||||
def onDrop(self, ev):
|
||||
def onDrop(self, ev) -> None:
|
||||
fieldList = self.form.fieldList
|
||||
indicatorPos = fieldList.dropIndicatorPosition()
|
||||
dropPos = fieldList.indexAt(ev.pos()).row()
|
||||
|
@ -113,7 +113,7 @@ class FieldDialog(QDialog):
|
|||
return None
|
||||
return txt
|
||||
|
||||
def onRename(self):
|
||||
def onRename(self) -> None:
|
||||
idx = self.currentIdx
|
||||
f = self.model["flds"][idx]
|
||||
name = self._uniqueName(tr(TR.ACTIONS_NEW_NAME), self.currentIdx, f["name"])
|
||||
|
@ -141,9 +141,10 @@ class FieldDialog(QDialog):
|
|||
self.fillFields()
|
||||
self.form.fieldList.setCurrentRow(len(self.model["flds"]) - 1)
|
||||
|
||||
def onDelete(self):
|
||||
def onDelete(self) -> None:
|
||||
if len(self.model["flds"]) < 2:
|
||||
return showWarning(tr(TR.FIELDS_NOTES_REQUIRE_AT_LEAST_ONE_FIELD))
|
||||
showWarning(tr(TR.FIELDS_NOTES_REQUIRE_AT_LEAST_ONE_FIELD))
|
||||
return
|
||||
count = self.mm.useCount(self.model)
|
||||
c = tr(TR.BROWSING_NOTE_COUNT, count=count)
|
||||
if not askUser(tr(TR.FIELDS_DELETE_FIELD_FROM, val=c)):
|
||||
|
@ -157,7 +158,7 @@ class FieldDialog(QDialog):
|
|||
self.fillFields()
|
||||
self.form.fieldList.setCurrentRow(0)
|
||||
|
||||
def onPosition(self, delta=-1):
|
||||
def onPosition(self, delta=-1) -> None:
|
||||
idx = self.currentIdx
|
||||
l = len(self.model["flds"])
|
||||
txt = getOnlyText(tr(TR.FIELDS_NEW_POSITION_1, val=l), default=str(idx + 1))
|
||||
|
@ -171,16 +172,16 @@ class FieldDialog(QDialog):
|
|||
return
|
||||
self.moveField(pos)
|
||||
|
||||
def onSortField(self):
|
||||
def onSortField(self) -> None:
|
||||
if not self.change_tracker.mark_schema():
|
||||
return False
|
||||
return
|
||||
# don't allow user to disable; it makes no sense
|
||||
self.form.sortField.setChecked(True)
|
||||
self.mm.set_sort_index(self.model, self.form.fieldList.currentRow())
|
||||
|
||||
def moveField(self, pos):
|
||||
def moveField(self, pos) -> None:
|
||||
if not self.change_tracker.mark_schema():
|
||||
return False
|
||||
return
|
||||
self.saveField()
|
||||
f = self.model["flds"][self.currentIdx]
|
||||
self.mm.reposition_field(self.model, f, pos - 1)
|
||||
|
@ -231,10 +232,10 @@ class FieldDialog(QDialog):
|
|||
def accept(self) -> None:
|
||||
self.saveField()
|
||||
|
||||
def save():
|
||||
def save() -> None:
|
||||
self.mm.save(self.model)
|
||||
|
||||
def on_done(fut):
|
||||
def on_done(fut) -> None:
|
||||
try:
|
||||
fut.result()
|
||||
except TemplateError as e:
|
||||
|
@ -247,5 +248,5 @@ class FieldDialog(QDialog):
|
|||
|
||||
self.mw.taskman.with_progress(save, on_done, self)
|
||||
|
||||
def onHelp(self):
|
||||
def onHelp(self) -> None:
|
||||
openHelp(HelpPage.CUSTOMIZING_FIELDS)
|
||||
|
|
|
@ -35,7 +35,7 @@ from aqt.utils import (
|
|||
|
||||
|
||||
class ChangeMap(QDialog):
|
||||
def __init__(self, mw: AnkiQt, model, current):
|
||||
def __init__(self, mw: AnkiQt, model, current) -> None:
|
||||
QDialog.__init__(self, mw, Qt.Window)
|
||||
self.mw = mw
|
||||
self.model = model
|
||||
|
@ -60,11 +60,11 @@ class ChangeMap(QDialog):
|
|||
self.frm.fields.setCurrentRow(n + 1)
|
||||
self.field: Optional[str] = None
|
||||
|
||||
def getField(self):
|
||||
def getField(self) -> str:
|
||||
self.exec_()
|
||||
return self.field
|
||||
|
||||
def accept(self):
|
||||
def accept(self) -> None:
|
||||
row = self.frm.fields.currentRow()
|
||||
if row < len(self.model["flds"]):
|
||||
self.field = self.model["flds"][row]["name"]
|
||||
|
@ -74,7 +74,7 @@ class ChangeMap(QDialog):
|
|||
self.field = None
|
||||
QDialog.accept(self)
|
||||
|
||||
def reject(self):
|
||||
def reject(self) -> None:
|
||||
self.accept()
|
||||
|
||||
|
||||
|
@ -119,7 +119,7 @@ class ImportDialog(QDialog):
|
|||
self.importer.initMapping()
|
||||
self.showMapping()
|
||||
|
||||
def onDelimiter(self):
|
||||
def onDelimiter(self) -> None:
|
||||
str = (
|
||||
getOnlyText(
|
||||
tr(TR.IMPORTING_BY_DEFAULT_ANKI_WILL_DETECT_THE),
|
||||
|
@ -136,7 +136,7 @@ class ImportDialog(QDialog):
|
|||
return
|
||||
self.hideMapping()
|
||||
|
||||
def updateDelim():
|
||||
def updateDelim() -> None:
|
||||
self.importer.delimiter = str
|
||||
self.importer.updateDelimiter()
|
||||
|
||||
|
@ -183,7 +183,7 @@ class ImportDialog(QDialog):
|
|||
self.mw.progress.start()
|
||||
self.mw.checkpoint(tr(TR.ACTIONS_IMPORT))
|
||||
|
||||
def on_done(future: Future):
|
||||
def on_done(future: Future) -> None:
|
||||
self.mw.progress.finish()
|
||||
|
||||
try:
|
||||
|
@ -221,7 +221,7 @@ class ImportDialog(QDialog):
|
|||
self.mapbox.setContentsMargins(0, 0, 0, 0)
|
||||
self.mapwidget: Optional[QWidget] = None
|
||||
|
||||
def hideMapping(self):
|
||||
def hideMapping(self) -> None:
|
||||
self.frm.mappingGroup.hide()
|
||||
|
||||
def showMapping(
|
||||
|
@ -258,7 +258,7 @@ class ImportDialog(QDialog):
|
|||
self.grid.addWidget(button, num, 2)
|
||||
qconnect(button.clicked, lambda _, s=self, n=num: s.changeMappingNum(n))
|
||||
|
||||
def changeMappingNum(self, n):
|
||||
def changeMappingNum(self, n) -> None:
|
||||
f = ChangeMap(self.mw, self.importer.model, self.mapping[n]).getField()
|
||||
try:
|
||||
# make sure we don't have it twice
|
||||
|
@ -270,7 +270,7 @@ class ImportDialog(QDialog):
|
|||
if getattr(self.importer, "delimiter", False):
|
||||
self.savedDelimiter = self.importer.delimiter
|
||||
|
||||
def updateDelim():
|
||||
def updateDelim() -> None:
|
||||
self.importer.delimiter = self.savedDelimiter
|
||||
|
||||
self.showMapping(hook=updateDelim, keepMapping=True)
|
||||
|
@ -283,17 +283,17 @@ class ImportDialog(QDialog):
|
|||
gui_hooks.current_note_type_did_change.remove(self.modelChanged)
|
||||
QDialog.reject(self)
|
||||
|
||||
def helpRequested(self):
|
||||
def helpRequested(self) -> None:
|
||||
openHelp(HelpPage.IMPORTING)
|
||||
|
||||
def importModeChanged(self, newImportMode):
|
||||
def importModeChanged(self, newImportMode) -> None:
|
||||
if newImportMode == 0:
|
||||
self.frm.tagModified.setEnabled(True)
|
||||
else:
|
||||
self.frm.tagModified.setEnabled(False)
|
||||
|
||||
|
||||
def showUnicodeWarning():
|
||||
def showUnicodeWarning() -> None:
|
||||
"""Shorthand to show a standard warning."""
|
||||
showWarning(tr(TR.IMPORTING_SELECTED_FILE_WAS_NOT_IN_UTF8))
|
||||
|
||||
|
@ -374,7 +374,7 @@ def importFile(mw: AnkiQt, file: str) -> None:
|
|||
# importing non-colpkg files
|
||||
mw.progress.start(immediate=True)
|
||||
|
||||
def on_done(future: Future):
|
||||
def on_done(future: Future) -> None:
|
||||
mw.progress.finish()
|
||||
try:
|
||||
future.result()
|
||||
|
@ -405,7 +405,7 @@ def importFile(mw: AnkiQt, file: str) -> None:
|
|||
mw.taskman.run_in_background(importer.run, on_done)
|
||||
|
||||
|
||||
def invalidZipMsg():
|
||||
def invalidZipMsg() -> str:
|
||||
return tr(TR.IMPORTING_THIS_FILE_DOES_NOT_APPEAR_TO)
|
||||
|
||||
|
||||
|
@ -430,14 +430,14 @@ def setupApkgImport(mw: AnkiQt, importer: AnkiPackageImporter) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def replaceWithApkg(mw, file, backup):
|
||||
def replaceWithApkg(mw, file, backup) -> None:
|
||||
mw.unloadCollection(lambda: _replaceWithApkg(mw, file, backup))
|
||||
|
||||
|
||||
def _replaceWithApkg(mw, filename, backup):
|
||||
def _replaceWithApkg(mw, filename, backup) -> None:
|
||||
mw.progress.start(immediate=True)
|
||||
|
||||
def do_import():
|
||||
def do_import() -> None:
|
||||
z = zipfile.ZipFile(filename)
|
||||
|
||||
# v2 scheduler?
|
||||
|
@ -472,7 +472,7 @@ def _replaceWithApkg(mw, filename, backup):
|
|||
|
||||
z.close()
|
||||
|
||||
def on_done(future: Future):
|
||||
def on_done(future: Future) -> None:
|
||||
mw.progress.finish()
|
||||
|
||||
try:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
Legacy support
|
||||
"""
|
||||
|
||||
from typing import List
|
||||
from typing import Any, List
|
||||
|
||||
import anki
|
||||
import aqt
|
||||
|
@ -31,7 +31,14 @@ def stripSounds(text) -> str:
|
|||
return aqt.mw.col.media.strip_av_tags(text)
|
||||
|
||||
|
||||
def fmtTimeSpan(time, pad=0, point=0, short=False, inTime=False, unit=99):
|
||||
def fmtTimeSpan(
|
||||
time: Any,
|
||||
pad: Any = 0,
|
||||
point: Any = 0,
|
||||
short: Any = False,
|
||||
inTime: Any = False,
|
||||
unit: Any = 99,
|
||||
) -> Any:
|
||||
print("fmtTimeSpan() has become col.format_timespan()")
|
||||
return aqt.mw.col.format_timespan(time)
|
||||
|
||||
|
|
102
qt/aqt/main.py
102
qt/aqt/main.py
|
@ -87,7 +87,7 @@ class ResetReason(enum.Enum):
|
|||
|
||||
|
||||
class ResetRequired:
|
||||
def __init__(self, mw: AnkiQt):
|
||||
def __init__(self, mw: AnkiQt) -> None:
|
||||
self.mw = mw
|
||||
|
||||
|
||||
|
@ -139,7 +139,7 @@ class AnkiQt(QMainWindow):
|
|||
else:
|
||||
fn = self.setupProfile
|
||||
|
||||
def on_window_init():
|
||||
def on_window_init() -> None:
|
||||
fn()
|
||||
gui_hooks.main_window_did_init()
|
||||
|
||||
|
@ -175,7 +175,7 @@ class AnkiQt(QMainWindow):
|
|||
"Actions that are deferred until after add-on loading."
|
||||
self.toolbar.draw()
|
||||
|
||||
def setupProfileAfterWebviewsLoaded(self):
|
||||
def setupProfileAfterWebviewsLoaded(self) -> None:
|
||||
for w in (self.web, self.bottomWeb):
|
||||
if not w._domDone:
|
||||
self.progress.timer(
|
||||
|
@ -206,7 +206,7 @@ class AnkiQt(QMainWindow):
|
|||
self.onClose.emit() # type: ignore
|
||||
evt.accept()
|
||||
|
||||
def closeWithoutQuitting(self):
|
||||
def closeWithoutQuitting(self) -> None:
|
||||
self.closeFires = False
|
||||
self.close()
|
||||
self.closeFires = True
|
||||
|
@ -275,9 +275,10 @@ class AnkiQt(QMainWindow):
|
|||
name = self.pm.profiles()[n]
|
||||
self.pm.load(name)
|
||||
|
||||
def openProfile(self):
|
||||
def openProfile(self) -> None:
|
||||
name = self.pm.profiles()[self.profileForm.profiles.currentRow()]
|
||||
return self.pm.load(name)
|
||||
self.pm.load(name)
|
||||
return
|
||||
|
||||
def onOpenProfile(self) -> None:
|
||||
self.profileDiag.hide()
|
||||
|
@ -288,34 +289,37 @@ class AnkiQt(QMainWindow):
|
|||
def profileNameOk(self, name: str) -> bool:
|
||||
return not checkInvalidFilename(name) and name != "addons21"
|
||||
|
||||
def onAddProfile(self):
|
||||
def onAddProfile(self) -> None:
|
||||
name = getOnlyText(tr(TR.ACTIONS_NAME)).strip()
|
||||
if name:
|
||||
if name in self.pm.profiles():
|
||||
return showWarning(tr(TR.QT_MISC_NAME_EXISTS))
|
||||
showWarning(tr(TR.QT_MISC_NAME_EXISTS))
|
||||
return
|
||||
if not self.profileNameOk(name):
|
||||
return
|
||||
self.pm.create(name)
|
||||
self.pm.name = name
|
||||
self.refreshProfilesList()
|
||||
|
||||
def onRenameProfile(self):
|
||||
def onRenameProfile(self) -> None:
|
||||
name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=self.pm.name).strip()
|
||||
if not name:
|
||||
return
|
||||
if name == self.pm.name:
|
||||
return
|
||||
if name in self.pm.profiles():
|
||||
return showWarning(tr(TR.QT_MISC_NAME_EXISTS))
|
||||
showWarning(tr(TR.QT_MISC_NAME_EXISTS))
|
||||
return
|
||||
if not self.profileNameOk(name):
|
||||
return
|
||||
self.pm.rename(name)
|
||||
self.refreshProfilesList()
|
||||
|
||||
def onRemProfile(self):
|
||||
def onRemProfile(self) -> None:
|
||||
profs = self.pm.profiles()
|
||||
if len(profs) < 2:
|
||||
return showWarning(tr(TR.QT_MISC_THERE_MUST_BE_AT_LEAST_ONE))
|
||||
showWarning(tr(TR.QT_MISC_THERE_MUST_BE_AT_LEAST_ONE))
|
||||
return
|
||||
# sure?
|
||||
if not askUser(
|
||||
tr(TR.QT_MISC_ALL_CARDS_NOTES_AND_MEDIA_FOR),
|
||||
|
@ -326,7 +330,7 @@ class AnkiQt(QMainWindow):
|
|||
self.pm.remove(self.pm.name)
|
||||
self.refreshProfilesList()
|
||||
|
||||
def onOpenBackup(self):
|
||||
def onOpenBackup(self) -> None:
|
||||
if not askUser(
|
||||
tr(TR.QT_MISC_REPLACE_YOUR_COLLECTION_WITH_AN_EARLIER),
|
||||
msgfunc=QMessageBox.warning,
|
||||
|
@ -334,7 +338,7 @@ class AnkiQt(QMainWindow):
|
|||
):
|
||||
return
|
||||
|
||||
def doOpen(path):
|
||||
def doOpen(path) -> None:
|
||||
self._openBackup(path)
|
||||
|
||||
getFile(
|
||||
|
@ -345,7 +349,7 @@ class AnkiQt(QMainWindow):
|
|||
dir=self.pm.backupFolder(),
|
||||
)
|
||||
|
||||
def _openBackup(self, path):
|
||||
def _openBackup(self, path) -> None:
|
||||
try:
|
||||
# move the existing collection to the trash, as it may not open
|
||||
self.pm.trashCollection()
|
||||
|
@ -360,14 +364,14 @@ class AnkiQt(QMainWindow):
|
|||
|
||||
self.onOpenProfile()
|
||||
|
||||
def _on_downgrade(self):
|
||||
def _on_downgrade(self) -> None:
|
||||
self.progress.start()
|
||||
profiles = self.pm.profiles()
|
||||
|
||||
def downgrade():
|
||||
def downgrade() -> List[str]:
|
||||
return self.pm.downgrade(profiles)
|
||||
|
||||
def on_done(future):
|
||||
def on_done(future) -> None:
|
||||
self.progress.finish()
|
||||
problems = future.result()
|
||||
if not problems:
|
||||
|
@ -409,7 +413,7 @@ class AnkiQt(QMainWindow):
|
|||
self.pendingImport = None
|
||||
gui_hooks.profile_did_open()
|
||||
|
||||
def _onsuccess():
|
||||
def _onsuccess() -> None:
|
||||
self._refresh_after_sync()
|
||||
if onsuccess:
|
||||
onsuccess()
|
||||
|
@ -417,7 +421,7 @@ class AnkiQt(QMainWindow):
|
|||
self.maybe_auto_sync_on_open_close(_onsuccess)
|
||||
|
||||
def unloadProfile(self, onsuccess: Callable) -> None:
|
||||
def callback():
|
||||
def callback() -> None:
|
||||
self._unloadProfile()
|
||||
onsuccess()
|
||||
|
||||
|
@ -447,7 +451,7 @@ class AnkiQt(QMainWindow):
|
|||
def unloadProfileAndExit(self) -> None:
|
||||
self.unloadProfile(self.cleanupAndExit)
|
||||
|
||||
def unloadProfileAndShowProfileManager(self):
|
||||
def unloadProfileAndShowProfileManager(self) -> None:
|
||||
self.unloadProfile(self.showProfileManager)
|
||||
|
||||
def cleanupAndExit(self) -> None:
|
||||
|
@ -520,14 +524,14 @@ class AnkiQt(QMainWindow):
|
|||
self.col.reopen()
|
||||
|
||||
def unloadCollection(self, onsuccess: Callable) -> None:
|
||||
def after_media_sync():
|
||||
def after_media_sync() -> None:
|
||||
self._unloadCollection()
|
||||
onsuccess()
|
||||
|
||||
def after_sync():
|
||||
def after_sync() -> None:
|
||||
self.media_syncer.show_diag_until_finished(after_media_sync)
|
||||
|
||||
def before_sync():
|
||||
def before_sync() -> None:
|
||||
self.setEnabled(False)
|
||||
self.maybe_auto_sync_on_open_close(after_sync)
|
||||
|
||||
|
@ -565,7 +569,7 @@ class AnkiQt(QMainWindow):
|
|||
##########################################################################
|
||||
|
||||
class BackupThread(Thread):
|
||||
def __init__(self, path, data):
|
||||
def __init__(self, path, data) -> None:
|
||||
Thread.__init__(self)
|
||||
self.path = path
|
||||
self.data = data
|
||||
|
@ -574,7 +578,7 @@ class AnkiQt(QMainWindow):
|
|||
with open(self.path, "wb") as file:
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
z = zipfile.ZipFile(self.path, "w", zipfile.ZIP_DEFLATED)
|
||||
z.writestr("collection.anki2", self.data)
|
||||
z.writestr("media", "{}")
|
||||
|
@ -700,7 +704,7 @@ class AnkiQt(QMainWindow):
|
|||
self.state = self.returnState
|
||||
self.reset()
|
||||
|
||||
def delayedMaybeReset(self):
|
||||
def delayedMaybeReset(self) -> None:
|
||||
# if we redraw the page in a button click event it will often crash on
|
||||
# windows
|
||||
self.progress.timer(100, self.maybeReset, False)
|
||||
|
@ -801,9 +805,9 @@ title="%s" %s>%s</button>""" % (
|
|||
signal.signal(signal.SIGINT, self.onUnixSignal)
|
||||
signal.signal(signal.SIGTERM, self.onUnixSignal)
|
||||
|
||||
def onUnixSignal(self, signum, frame):
|
||||
def onUnixSignal(self, signum, frame) -> None:
|
||||
# schedule a rollback & quit
|
||||
def quit():
|
||||
def quit() -> None:
|
||||
self.col.db.rollback()
|
||||
self.close()
|
||||
|
||||
|
@ -888,13 +892,13 @@ title="%s" %s>%s</button>""" % (
|
|||
def _refresh_after_sync(self) -> None:
|
||||
self.toolbar.redraw()
|
||||
|
||||
def _sync_collection_and_media(self, after_sync: Callable[[], None]):
|
||||
def _sync_collection_and_media(self, after_sync: Callable[[], None]) -> None:
|
||||
"Caller should ensure auth available."
|
||||
# start media sync if not already running
|
||||
if not self.media_syncer.is_syncing():
|
||||
self.media_syncer.start()
|
||||
|
||||
def on_collection_sync_finished():
|
||||
def on_collection_sync_finished() -> None:
|
||||
self.col.clearUndo()
|
||||
self.col.models._clear_cache()
|
||||
gui_hooks.sync_did_finish()
|
||||
|
@ -927,7 +931,7 @@ title="%s" %s>%s</button>""" % (
|
|||
)
|
||||
|
||||
# legacy
|
||||
def _sync(self):
|
||||
def _sync(self) -> None:
|
||||
pass
|
||||
|
||||
onSync = on_sync_button_clicked
|
||||
|
@ -1057,7 +1061,7 @@ title="%s" %s>%s</button>""" % (
|
|||
def onEditCurrent(self) -> None:
|
||||
aqt.dialogs.open("EditCurrent", self)
|
||||
|
||||
def onDeckConf(self, deck=None):
|
||||
def onDeckConf(self, deck=None) -> None:
|
||||
if not deck:
|
||||
deck = self.col.decks.current()
|
||||
if deck["dyn"]:
|
||||
|
@ -1069,7 +1073,7 @@ title="%s" %s>%s</button>""" % (
|
|||
|
||||
aqt.deckconf.DeckConf(self, deck)
|
||||
|
||||
def onOverview(self):
|
||||
def onOverview(self) -> None:
|
||||
self.col.reset()
|
||||
self.moveToState("overview")
|
||||
|
||||
|
@ -1083,7 +1087,7 @@ title="%s" %s>%s</button>""" % (
|
|||
else:
|
||||
aqt.dialogs.open("NewDeckStats", self)
|
||||
|
||||
def onPrefs(self):
|
||||
def onPrefs(self) -> None:
|
||||
aqt.dialogs.open("Preferences", self)
|
||||
|
||||
def onNoteTypes(self) -> None:
|
||||
|
@ -1091,13 +1095,13 @@ title="%s" %s>%s</button>""" % (
|
|||
|
||||
aqt.models.Models(self, self, fromMain=True)
|
||||
|
||||
def onAbout(self):
|
||||
def onAbout(self) -> None:
|
||||
aqt.dialogs.open("About", self)
|
||||
|
||||
def onDonate(self):
|
||||
def onDonate(self) -> None:
|
||||
openLink(aqt.appDonate)
|
||||
|
||||
def onDocumentation(self):
|
||||
def onDocumentation(self) -> None:
|
||||
openHelp(HelpPage.INDEX)
|
||||
|
||||
# Importing & exporting
|
||||
|
@ -1126,7 +1130,7 @@ title="%s" %s>%s</button>""" % (
|
|||
# Installing add-ons from CLI / mimetype handler
|
||||
##########################################################################
|
||||
|
||||
def installAddon(self, path: str, startup: bool = False):
|
||||
def installAddon(self, path: str, startup: bool = False) -> None:
|
||||
from aqt.addons import installAddonPackages
|
||||
|
||||
installAddonPackages(
|
||||
|
@ -1201,14 +1205,14 @@ title="%s" %s>%s</button>""" % (
|
|||
qconnect(self.autoUpdate.clockIsOff, self.clockIsOff)
|
||||
self.autoUpdate.start()
|
||||
|
||||
def newVerAvail(self, ver):
|
||||
def newVerAvail(self, ver) -> None:
|
||||
if self.pm.meta.get("suppressUpdate", None) != ver:
|
||||
aqt.update.askAndUpdate(self, ver)
|
||||
|
||||
def newMsg(self, data):
|
||||
def newMsg(self, data) -> None:
|
||||
aqt.update.showMessages(self, data)
|
||||
|
||||
def clockIsOff(self, diff):
|
||||
def clockIsOff(self, diff) -> None:
|
||||
if devMode:
|
||||
print("clock is off; ignoring")
|
||||
return
|
||||
|
@ -1229,7 +1233,7 @@ title="%s" %s>%s</button>""" % (
|
|||
# SIGINT/SIGTERM is processed without a long delay
|
||||
self.progress.timer(1000, lambda: None, True, False)
|
||||
|
||||
def onRefreshTimer(self):
|
||||
def onRefreshTimer(self) -> None:
|
||||
if self.state == "deckBrowser":
|
||||
self.deckBrowser.refresh()
|
||||
elif self.state == "overview":
|
||||
|
@ -1256,7 +1260,7 @@ title="%s" %s>%s</button>""" % (
|
|||
|
||||
self._activeWindowOnPlay: Optional[QWidget] = None
|
||||
|
||||
def onOdueInvalid(self):
|
||||
def onOdueInvalid(self) -> None:
|
||||
showWarning(tr(TR.QT_MISC_INVALID_PROPERTY_FOUND_ON_CARD_PLEASE))
|
||||
|
||||
def _isVideo(self, tag: AVTag) -> bool:
|
||||
|
@ -1343,11 +1347,11 @@ title="%s" %s>%s</button>""" % (
|
|||
# Debugging
|
||||
######################################################################
|
||||
|
||||
def onDebug(self):
|
||||
def onDebug(self) -> None:
|
||||
frm = self.debug_diag_form = aqt.forms.debug.Ui_Dialog()
|
||||
|
||||
class DebugDialog(QDialog):
|
||||
def reject(self):
|
||||
def reject(self) -> None:
|
||||
super().reject()
|
||||
saveSplitter(frm.splitter, "DebugConsoleWindow")
|
||||
saveGeom(self, "DebugConsoleWindow")
|
||||
|
@ -1394,7 +1398,7 @@ title="%s" %s>%s</button>""" % (
|
|||
mw = self
|
||||
|
||||
class Stream:
|
||||
def write(self, data):
|
||||
def write(self, data) -> None:
|
||||
mw._output += data
|
||||
|
||||
if on:
|
||||
|
@ -1445,7 +1449,7 @@ title="%s" %s>%s</button>""" % (
|
|||
self._card_repr(card)
|
||||
return card
|
||||
|
||||
def onDebugPrint(self, frm):
|
||||
def onDebugPrint(self, frm) -> None:
|
||||
cursor = frm.text.textCursor()
|
||||
position = cursor.position()
|
||||
cursor.select(QTextCursor.LineUnderCursor)
|
||||
|
@ -1458,7 +1462,7 @@ title="%s" %s>%s</button>""" % (
|
|||
frm.text.setTextCursor(cursor)
|
||||
self.onDebugRet(frm)
|
||||
|
||||
def onDebugRet(self, frm):
|
||||
def onDebugRet(self, frm) -> None:
|
||||
import pprint
|
||||
import traceback
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ class MediaChecker:
|
|||
diag.exec_()
|
||||
saveGeom(diag, "checkmediadb")
|
||||
|
||||
def _on_render_latex(self):
|
||||
def _on_render_latex(self) -> None:
|
||||
self.progress_dialog = self.mw.progress.start()
|
||||
try:
|
||||
out = self.mw.col.media.render_all_latex(self._on_render_latex_progress)
|
||||
|
@ -160,7 +160,7 @@ class MediaChecker:
|
|||
self.mw.progress.update(tr(TR.MEDIA_CHECK_CHECKED, count=count))
|
||||
return True
|
||||
|
||||
def _on_trash_files(self, fnames: Sequence[str]):
|
||||
def _on_trash_files(self, fnames: Sequence[str]) -> None:
|
||||
if not askUser(tr(TR.MEDIA_CHECK_DELETE_UNUSED_CONFIRM)):
|
||||
return
|
||||
|
||||
|
@ -183,14 +183,14 @@ class MediaChecker:
|
|||
|
||||
tooltip(tr(TR.MEDIA_CHECK_DELETE_UNUSED_COMPLETE, count=total))
|
||||
|
||||
def _on_empty_trash(self):
|
||||
def _on_empty_trash(self) -> None:
|
||||
self.progress_dialog = self.mw.progress.start()
|
||||
self._set_progress_enabled(True)
|
||||
|
||||
def empty_trash():
|
||||
def empty_trash() -> None:
|
||||
self.mw.col.media.empty_trash()
|
||||
|
||||
def on_done(fut: Future):
|
||||
def on_done(fut: Future) -> None:
|
||||
self.mw.progress.finish()
|
||||
self._set_progress_enabled(False)
|
||||
# check for errors
|
||||
|
@ -200,14 +200,14 @@ class MediaChecker:
|
|||
|
||||
self.mw.taskman.run_in_background(empty_trash, on_done)
|
||||
|
||||
def _on_restore_trash(self):
|
||||
def _on_restore_trash(self) -> None:
|
||||
self.progress_dialog = self.mw.progress.start()
|
||||
self._set_progress_enabled(True)
|
||||
|
||||
def restore_trash():
|
||||
def restore_trash() -> None:
|
||||
self.mw.col.media.restore_trash()
|
||||
|
||||
def on_done(fut: Future):
|
||||
def on_done(fut: Future) -> None:
|
||||
self.mw.progress.finish()
|
||||
self._set_progress_enabled(False)
|
||||
# check for errors
|
||||
|
|
|
@ -12,6 +12,7 @@ import threading
|
|||
import time
|
||||
import traceback
|
||||
from http import HTTPStatus
|
||||
from typing import Tuple
|
||||
|
||||
import flask
|
||||
import flask_cors # type: ignore
|
||||
|
@ -52,11 +53,11 @@ class MediaServer(threading.Thread):
|
|||
_ready = threading.Event()
|
||||
daemon = True
|
||||
|
||||
def __init__(self, mw: aqt.main.AnkiQt, *args, **kwargs):
|
||||
def __init__(self, mw: aqt.main.AnkiQt, *args, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.is_shutdown = False
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
try:
|
||||
if devMode:
|
||||
# idempotent if logging has already been set up
|
||||
|
@ -97,7 +98,7 @@ class MediaServer(threading.Thread):
|
|||
|
||||
|
||||
@app.route("/<path:pathin>", methods=["GET", "POST"])
|
||||
def allroutes(pathin):
|
||||
def allroutes(pathin) -> Response:
|
||||
try:
|
||||
directory, path = _redirectWebExports(pathin)
|
||||
except TypeError:
|
||||
|
@ -171,7 +172,7 @@ def allroutes(pathin):
|
|||
)
|
||||
|
||||
|
||||
def _redirectWebExports(path):
|
||||
def _redirectWebExports(path) -> Tuple[str, str]:
|
||||
# catch /_anki references and rewrite them to web export folder
|
||||
targetPath = "_anki/"
|
||||
if path.startswith(targetPath):
|
||||
|
|
|
@ -28,14 +28,14 @@ class LogEntryWithTime:
|
|||
|
||||
|
||||
class MediaSyncer:
|
||||
def __init__(self, mw: aqt.main.AnkiQt):
|
||||
def __init__(self, mw: aqt.main.AnkiQt) -> None:
|
||||
self.mw = mw
|
||||
self._syncing: bool = False
|
||||
self._log: List[LogEntryWithTime] = []
|
||||
self._progress_timer: Optional[QTimer] = None
|
||||
gui_hooks.media_sync_did_start_or_stop.append(self._on_start_stop)
|
||||
|
||||
def _on_progress(self):
|
||||
def _on_progress(self) -> None:
|
||||
progress = self.mw.col.latest_progress()
|
||||
if progress.kind != ProgressKind.MediaSync:
|
||||
return
|
||||
|
@ -88,7 +88,7 @@ class MediaSyncer:
|
|||
else:
|
||||
self._log_and_notify(tr(TR.SYNC_MEDIA_COMPLETE))
|
||||
|
||||
def _handle_sync_error(self, exc: BaseException):
|
||||
def _handle_sync_error(self, exc: BaseException) -> None:
|
||||
if isinstance(exc, Interrupted):
|
||||
self._log_and_notify(tr(TR.SYNC_MEDIA_ABORTED))
|
||||
return
|
||||
|
@ -116,10 +116,10 @@ class MediaSyncer:
|
|||
def _on_start_stop(self, running: bool) -> None:
|
||||
self.mw.toolbar.set_sync_active(running)
|
||||
|
||||
def show_sync_log(self):
|
||||
def show_sync_log(self) -> None:
|
||||
aqt.dialogs.open("sync_log", self.mw, self)
|
||||
|
||||
def show_diag_until_finished(self, on_finished: Callable[[], None]):
|
||||
def show_diag_until_finished(self, on_finished: Callable[[], None]) -> None:
|
||||
# nothing to do if not syncing
|
||||
if not self.is_syncing():
|
||||
return on_finished()
|
||||
|
@ -129,7 +129,7 @@ class MediaSyncer:
|
|||
|
||||
timer: Optional[QTimer] = None
|
||||
|
||||
def check_finished():
|
||||
def check_finished() -> None:
|
||||
if not self.is_syncing():
|
||||
timer.stop()
|
||||
on_finished()
|
||||
|
@ -197,7 +197,7 @@ class MediaSyncDialog(QDialog):
|
|||
asctime = time.asctime(time.localtime(stamp))
|
||||
return f"{asctime}: {text}"
|
||||
|
||||
def _entry_to_text(self, entry: LogEntryWithTime):
|
||||
def _entry_to_text(self, entry: LogEntryWithTime) -> str:
|
||||
if isinstance(entry.entry, str):
|
||||
txt = entry.entry
|
||||
elif isinstance(entry.entry, MediaSyncProgress):
|
||||
|
@ -209,7 +209,7 @@ class MediaSyncDialog(QDialog):
|
|||
def _logentry_to_text(self, e: MediaSyncProgress) -> str:
|
||||
return f"{e.added}, {e.removed}, {e.checked}"
|
||||
|
||||
def _on_log_entry(self, entry: LogEntryWithTime):
|
||||
def _on_log_entry(self, entry: LogEntryWithTime) -> None:
|
||||
self.form.plainTextEdit.appendPlainText(self._entry_to_text(entry))
|
||||
if not self._syncer.is_syncing():
|
||||
self.abort_button.setHidden(True)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright: Ankitects Pty Ltd and contributors
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
|
||||
from aqt import AnkiQt, gui_hooks
|
||||
from aqt.qt import *
|
||||
|
@ -74,7 +74,7 @@ class ModelChooser(QHBoxLayout):
|
|||
# edit button
|
||||
edit = QPushButton(tr(TR.QT_MISC_MANAGE), clicked=self.onEdit) # type: ignore
|
||||
|
||||
def nameFunc():
|
||||
def nameFunc() -> List[str]:
|
||||
return sorted(self.deck.models.allNames())
|
||||
|
||||
ret = StudyDeck(
|
||||
|
|
|
@ -219,7 +219,7 @@ class Models(QDialog):
|
|||
class AddModel(QDialog):
|
||||
model: Optional[NoteType]
|
||||
|
||||
def __init__(self, mw: AnkiQt, parent: Optional[QWidget] = None):
|
||||
def __init__(self, mw: AnkiQt, parent: Optional[QWidget] = None) -> None:
|
||||
self.parent_ = parent or mw
|
||||
self.mw = mw
|
||||
self.col = mw.col
|
||||
|
|
|
@ -15,7 +15,7 @@ from aqt.utils import TR, askUserDialog, openLink, shortcut, tooltip, tr
|
|||
|
||||
|
||||
class OverviewBottomBar:
|
||||
def __init__(self, overview: Overview):
|
||||
def __init__(self, overview: Overview) -> None:
|
||||
self.overview = overview
|
||||
|
||||
|
||||
|
@ -104,12 +104,12 @@ class Overview:
|
|||
def _filteredDeck(self) -> int:
|
||||
return self.mw.col.decks.current()["dyn"]
|
||||
|
||||
def onRebuildKey(self):
|
||||
def onRebuildKey(self) -> None:
|
||||
if self._filteredDeck():
|
||||
self.mw.col.sched.rebuild_filtered_deck(self.mw.col.decks.selected())
|
||||
self.mw.reset()
|
||||
|
||||
def onEmptyKey(self):
|
||||
def onEmptyKey(self) -> None:
|
||||
if self._filteredDeck():
|
||||
self.mw.col.sched.empty_filtered_deck(self.mw.col.decks.selected())
|
||||
self.mw.reset()
|
||||
|
@ -118,7 +118,7 @@ class Overview:
|
|||
if not self._filteredDeck():
|
||||
self.onStudyMore()
|
||||
|
||||
def onUnbury(self):
|
||||
def onUnbury(self) -> None:
|
||||
if self.mw.col.schedVer() == 1:
|
||||
self.mw.col.sched.unburyCardsForDeck()
|
||||
self.mw.reset()
|
||||
|
|
|
@ -34,7 +34,7 @@ def video_driver_name_for_platform(driver: VideoDriver) -> str:
|
|||
|
||||
|
||||
class Preferences(QDialog):
|
||||
def __init__(self, mw: AnkiQt):
|
||||
def __init__(self, mw: AnkiQt) -> None:
|
||||
QDialog.__init__(self, mw, Qt.Window)
|
||||
self.mw = mw
|
||||
self.prof = self.mw.pm.profile
|
||||
|
@ -55,7 +55,7 @@ class Preferences(QDialog):
|
|||
self.setupOptions()
|
||||
self.show()
|
||||
|
||||
def accept(self):
|
||||
def accept(self) -> None:
|
||||
# avoid exception if main window is already closed
|
||||
if not self.mw.col:
|
||||
return
|
||||
|
@ -68,19 +68,19 @@ class Preferences(QDialog):
|
|||
self.done(0)
|
||||
aqt.dialogs.markClosed("Preferences")
|
||||
|
||||
def reject(self):
|
||||
def reject(self) -> None:
|
||||
self.accept()
|
||||
|
||||
# Language
|
||||
######################################################################
|
||||
|
||||
def setupLang(self):
|
||||
def setupLang(self) -> None:
|
||||
f = self.form
|
||||
f.lang.addItems([x[0] for x in anki.lang.langs])
|
||||
f.lang.setCurrentIndex(self.langIdx())
|
||||
qconnect(f.lang.currentIndexChanged, self.onLangIdxChanged)
|
||||
|
||||
def langIdx(self):
|
||||
def langIdx(self) -> int:
|
||||
codes = [x[1] for x in anki.lang.langs]
|
||||
lang = anki.lang.currentLang
|
||||
if lang in anki.lang.compatMap:
|
||||
|
@ -92,7 +92,7 @@ class Preferences(QDialog):
|
|||
except:
|
||||
return codes.index("en_US")
|
||||
|
||||
def onLangIdxChanged(self, idx):
|
||||
def onLangIdxChanged(self, idx) -> None:
|
||||
code = anki.lang.langs[idx][1]
|
||||
self.mw.pm.setLang(code)
|
||||
showInfo(
|
||||
|
@ -102,7 +102,7 @@ class Preferences(QDialog):
|
|||
# Collection options
|
||||
######################################################################
|
||||
|
||||
def setupCollection(self):
|
||||
def setupCollection(self) -> None:
|
||||
import anki.consts as c
|
||||
|
||||
f = self.form
|
||||
|
@ -130,7 +130,7 @@ class Preferences(QDialog):
|
|||
f.newSched.setChecked(True)
|
||||
f.new_timezone.setChecked(s.new_timezone)
|
||||
|
||||
def setup_video_driver(self):
|
||||
def setup_video_driver(self) -> None:
|
||||
self.video_drivers = VideoDriver.all_for_platform()
|
||||
names = [
|
||||
tr(TR.PREFERENCES_VIDEO_DRIVER, driver=video_driver_name_for_platform(d))
|
||||
|
@ -141,13 +141,13 @@ class Preferences(QDialog):
|
|||
self.video_drivers.index(self.mw.pm.video_driver())
|
||||
)
|
||||
|
||||
def update_video_driver(self):
|
||||
def update_video_driver(self) -> None:
|
||||
new_driver = self.video_drivers[self.form.video_driver.currentIndex()]
|
||||
if new_driver != self.mw.pm.video_driver():
|
||||
self.mw.pm.set_video_driver(new_driver)
|
||||
showInfo(tr(TR.PREFERENCES_CHANGES_WILL_TAKE_EFFECT_WHEN_YOU))
|
||||
|
||||
def updateCollection(self):
|
||||
def updateCollection(self) -> None:
|
||||
f = self.form
|
||||
d = self.mw.col
|
||||
|
||||
|
@ -176,7 +176,7 @@ class Preferences(QDialog):
|
|||
# Scheduler version
|
||||
######################################################################
|
||||
|
||||
def _updateSchedVer(self, wantNew):
|
||||
def _updateSchedVer(self, wantNew) -> None:
|
||||
haveNew = self.mw.col.schedVer() == 2
|
||||
|
||||
# nothing to do?
|
||||
|
@ -194,7 +194,7 @@ class Preferences(QDialog):
|
|||
# Network
|
||||
######################################################################
|
||||
|
||||
def setupNetwork(self):
|
||||
def setupNetwork(self) -> None:
|
||||
self.form.media_log.setText(tr(TR.SYNC_MEDIA_LOG_BUTTON))
|
||||
qconnect(self.form.media_log.clicked, self.on_media_log)
|
||||
self.form.syncOnProgramOpen.setChecked(self.prof["autoSync"])
|
||||
|
@ -207,10 +207,10 @@ class Preferences(QDialog):
|
|||
qconnect(self.form.syncDeauth.clicked, self.onSyncDeauth)
|
||||
self.form.syncDeauth.setText(tr(TR.SYNC_LOG_OUT_BUTTON))
|
||||
|
||||
def on_media_log(self):
|
||||
def on_media_log(self) -> None:
|
||||
self.mw.media_syncer.show_sync_log()
|
||||
|
||||
def _hideAuth(self):
|
||||
def _hideAuth(self) -> None:
|
||||
self.form.syncDeauth.setVisible(False)
|
||||
self.form.syncUser.setText("")
|
||||
self.form.syncLabel.setText(
|
||||
|
@ -225,7 +225,7 @@ class Preferences(QDialog):
|
|||
self.mw.col.media.force_resync()
|
||||
self._hideAuth()
|
||||
|
||||
def updateNetwork(self):
|
||||
def updateNetwork(self) -> None:
|
||||
self.prof["autoSync"] = self.form.syncOnProgramOpen.isChecked()
|
||||
self.prof["syncMedia"] = self.form.syncMedia.isChecked()
|
||||
self.mw.pm.set_auto_sync_media_minutes(
|
||||
|
@ -238,16 +238,16 @@ class Preferences(QDialog):
|
|||
# Backup
|
||||
######################################################################
|
||||
|
||||
def setupBackup(self):
|
||||
def setupBackup(self) -> None:
|
||||
self.form.numBackups.setValue(self.prof["numBackups"])
|
||||
|
||||
def updateBackup(self):
|
||||
def updateBackup(self) -> None:
|
||||
self.prof["numBackups"] = self.form.numBackups.value()
|
||||
|
||||
# Basic & Advanced Options
|
||||
######################################################################
|
||||
|
||||
def setupOptions(self):
|
||||
def setupOptions(self) -> None:
|
||||
self.form.pastePNG.setChecked(self.prof.get("pastePNG", False))
|
||||
self.form.uiScale.setValue(int(self.mw.pm.uiScale() * 100))
|
||||
self.form.pasteInvert.setChecked(self.prof.get("pasteInvert", False))
|
||||
|
@ -270,7 +270,7 @@ class Preferences(QDialog):
|
|||
self._recording_drivers.index(self.mw.pm.recording_driver())
|
||||
)
|
||||
|
||||
def updateOptions(self):
|
||||
def updateOptions(self) -> None:
|
||||
restart_required = False
|
||||
|
||||
self.prof["pastePNG"] = self.form.pastePNG.isChecked()
|
||||
|
|
|
@ -40,7 +40,9 @@ class Previewer(QDialog):
|
|||
_timer: Optional[QTimer] = None
|
||||
_show_both_sides = False
|
||||
|
||||
def __init__(self, parent: QWidget, mw: AnkiQt, on_close: Callable[[], None]):
|
||||
def __init__(
|
||||
self, parent: QWidget, mw: AnkiQt, on_close: Callable[[], None]
|
||||
) -> None:
|
||||
super().__init__(None, Qt.Window)
|
||||
self._open = True
|
||||
self._parent = parent
|
||||
|
@ -259,14 +261,14 @@ class MultiCardPreviewer(Previewer):
|
|||
qconnect(self._prev.clicked, self._on_prev)
|
||||
qconnect(self._next.clicked, self._on_next)
|
||||
|
||||
def _on_prev(self):
|
||||
def _on_prev(self) -> None:
|
||||
if self._state == "answer" and not self._show_both_sides:
|
||||
self._state = "question"
|
||||
self.render_card()
|
||||
else:
|
||||
self._on_prev_card()
|
||||
|
||||
def _on_prev_card(self):
|
||||
def _on_prev_card(self) -> None:
|
||||
pass
|
||||
|
||||
def _on_next(self) -> None:
|
||||
|
@ -276,7 +278,7 @@ class MultiCardPreviewer(Previewer):
|
|||
else:
|
||||
self._on_next_card()
|
||||
|
||||
def _on_next_card(self):
|
||||
def _on_next_card(self) -> None:
|
||||
pass
|
||||
|
||||
def _updateButtons(self) -> None:
|
||||
|
@ -315,7 +317,7 @@ class BrowserPreviewer(MultiCardPreviewer):
|
|||
self._last_card_id = c.id
|
||||
return changed
|
||||
|
||||
def _on_prev_card(self):
|
||||
def _on_prev_card(self) -> None:
|
||||
self._parent.editor.saveNow(
|
||||
lambda: self._parent._moveCur(QAbstractItemView.MoveUp)
|
||||
)
|
||||
|
|
|
@ -113,13 +113,13 @@ class LoadMetaResult:
|
|||
|
||||
|
||||
class AnkiRestart(SystemExit):
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
self.exitcode = kwargs.pop("exitcode", 0)
|
||||
super().__init__(*args, **kwargs) # type: ignore
|
||||
|
||||
|
||||
class ProfileManager:
|
||||
def __init__(self, base: Optional[str] = None) -> None:
|
||||
def __init__(self, base: Optional[str] = None) -> None: #
|
||||
## Settings which should be forgotten each Anki restart
|
||||
self.session: Dict[str, Any] = {}
|
||||
self.name: Optional[str] = None
|
||||
|
@ -185,7 +185,7 @@ class ProfileManager:
|
|||
self.base = newBase
|
||||
shutil.move(oldBase, self.base)
|
||||
|
||||
def _tryToMigrateFolder(self, oldBase):
|
||||
def _tryToMigrateFolder(self, oldBase) -> None:
|
||||
from PyQt5 import QtGui, QtWidgets
|
||||
|
||||
app = QtWidgets.QApplication([])
|
||||
|
@ -269,7 +269,7 @@ class ProfileManager:
|
|||
fn = super().find_class(module, name)
|
||||
if module == "sip" and name == "_unpickle_type":
|
||||
|
||||
def wrapper(mod, obj, args):
|
||||
def wrapper(mod, obj, args) -> Any:
|
||||
if mod.startswith("PyQt4") and obj == "QByteArray":
|
||||
# can't trust str objects from python 2
|
||||
return QByteArray()
|
||||
|
@ -534,7 +534,7 @@ create table if not exists profiles
|
|||
def setDefaultLang(self, idx: int) -> None:
|
||||
# create dialog
|
||||
class NoCloseDiag(QDialog):
|
||||
def reject(self):
|
||||
def reject(self) -> None:
|
||||
pass
|
||||
|
||||
d = self.langDiag = NoCloseDiag()
|
||||
|
@ -665,7 +665,7 @@ create table if not exists profiles
|
|||
pass
|
||||
return RecordingDriver.QtAudioInput
|
||||
|
||||
def set_recording_driver(self, driver: RecordingDriver):
|
||||
def set_recording_driver(self, driver: RecordingDriver) -> None:
|
||||
self.profile["recordingDriver"] = driver.value
|
||||
|
||||
######################################################################
|
||||
|
|
|
@ -43,7 +43,7 @@ class ProgressManager:
|
|||
timer to fire even when there is no collection, but will still
|
||||
only fire when there is no current progress dialog."""
|
||||
|
||||
def handler():
|
||||
def handler() -> None:
|
||||
if requiresCollection and not self.mw.col:
|
||||
# no current collection; timer is no longer valid
|
||||
print("Ignored progress func as collection unloaded: %s" % repr(func))
|
||||
|
@ -225,14 +225,14 @@ class ProgressDialog(QDialog):
|
|||
self._closingDown = True
|
||||
self.hide()
|
||||
|
||||
def closeEvent(self, evt):
|
||||
def closeEvent(self, evt) -> None:
|
||||
if self._closingDown:
|
||||
evt.accept()
|
||||
else:
|
||||
self.wantCancel = True
|
||||
evt.ignore()
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
def keyPressEvent(self, evt) -> None:
|
||||
if evt.key() == Qt.Key_Escape:
|
||||
evt.ignore()
|
||||
self.wantCancel = True
|
||||
|
|
|
@ -30,7 +30,7 @@ except ImportError:
|
|||
import sip # type: ignore
|
||||
|
||||
|
||||
def debug():
|
||||
def debug() -> None:
|
||||
from pdb import set_trace
|
||||
|
||||
pyqtRemoveInputHook()
|
||||
|
@ -39,7 +39,7 @@ def debug():
|
|||
|
||||
if os.environ.get("DEBUG"):
|
||||
|
||||
def info(type, value, tb):
|
||||
def info(type, value, tb) -> None:
|
||||
for line in traceback.format_exception(type, value, tb):
|
||||
sys.stdout.write(line)
|
||||
pyqtRemoveInputHook()
|
||||
|
|
|
@ -8,7 +8,7 @@ import html
|
|||
import json
|
||||
import re
|
||||
import unicodedata as ucd
|
||||
from typing import Any, Callable, List, Optional, Tuple, Union
|
||||
from typing import Any, Callable, List, Match, Optional, Tuple, Union
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
|
@ -426,7 +426,7 @@ class Reviewer:
|
|||
# compare with typed answer
|
||||
res = self.correct(given, cor, showBad=False)
|
||||
# and update the type answer area
|
||||
def repl(match):
|
||||
def repl(match: Match) -> str:
|
||||
# can't pass a string in directly, and can't use re.escape as it
|
||||
# escapes too much
|
||||
s = """
|
||||
|
@ -448,7 +448,7 @@ class Reviewer:
|
|||
if not matches:
|
||||
return None
|
||||
|
||||
def noHint(txt):
|
||||
def noHint(txt) -> str:
|
||||
if "::" in txt:
|
||||
return txt.split("::")[0]
|
||||
return txt
|
||||
|
@ -652,7 +652,7 @@ time = %(time)d;
|
|||
def _answerButtons(self) -> str:
|
||||
default = self._defaultEase()
|
||||
|
||||
def but(i, label):
|
||||
def but(i, label) -> str:
|
||||
if i == default:
|
||||
extra = """id="defease" class="focus" """
|
||||
else:
|
||||
|
@ -834,7 +834,7 @@ time = %(time)d;
|
|||
tooltip(tr(TR.STUDYING_NOTE_BURIED))
|
||||
|
||||
def onRecordVoice(self) -> None:
|
||||
def after_record(path: str):
|
||||
def after_record(path: str) -> None:
|
||||
self._recordedAudio = path
|
||||
self.onReplayRecorded()
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class Change(enum.Enum):
|
|||
class ChangeTracker:
|
||||
_changed = Change.NO_CHANGE
|
||||
|
||||
def __init__(self, mw: AnkiQt):
|
||||
def __init__(self, mw: AnkiQt) -> None:
|
||||
self.mw = mw
|
||||
|
||||
def mark_basic(self) -> None:
|
||||
|
|
|
@ -438,7 +438,7 @@ class MpvManager(MPV, SoundOrVideoPlayer):
|
|||
|
||||
|
||||
class SimpleMplayerSlaveModePlayer(SimpleMplayerPlayer):
|
||||
def __init__(self, taskman: TaskManager):
|
||||
def __init__(self, taskman: TaskManager) -> None:
|
||||
super().__init__(taskman)
|
||||
self.args.append("-slave")
|
||||
|
||||
|
@ -494,7 +494,7 @@ def encode_mp3(mw: aqt.AnkiQt, src_wav: str, on_done: Callable[[str], None]) ->
|
|||
"Encode the provided wav file to .mp3, and call on_done() with the path."
|
||||
dst_mp3 = src_wav.replace(".wav", "%d.mp3" % time.time())
|
||||
|
||||
def _on_done(fut: Future):
|
||||
def _on_done(fut: Future) -> None:
|
||||
fut.result()
|
||||
on_done(dst_mp3)
|
||||
|
||||
|
@ -509,7 +509,7 @@ class Recorder(ABC):
|
|||
# seconds to wait before recording
|
||||
STARTUP_DELAY = 0.3
|
||||
|
||||
def __init__(self, output_path: str):
|
||||
def __init__(self, output_path: str) -> None:
|
||||
self.output_path = output_path
|
||||
|
||||
def start(self, on_done: Callable[[], None]) -> None:
|
||||
|
@ -517,7 +517,7 @@ class Recorder(ABC):
|
|||
self._started_at = time.time()
|
||||
on_done()
|
||||
|
||||
def stop(self, on_done: Callable[[str], None]):
|
||||
def stop(self, on_done: Callable[[str], None]) -> None:
|
||||
"Stop recording, then call on_done() when finished."
|
||||
on_done(self.output_path)
|
||||
|
||||
|
@ -525,7 +525,7 @@ class Recorder(ABC):
|
|||
"Seconds since recording started."
|
||||
return time.time() - self._started_at
|
||||
|
||||
def on_timer(self):
|
||||
def on_timer(self) -> None:
|
||||
"Will be called periodically."
|
||||
|
||||
|
||||
|
@ -534,7 +534,7 @@ class Recorder(ABC):
|
|||
|
||||
|
||||
class QtAudioInputRecorder(Recorder):
|
||||
def __init__(self, output_path: str, mw: aqt.AnkiQt, parent: QWidget):
|
||||
def __init__(self, output_path: str, mw: aqt.AnkiQt, parent: QWidget) -> None:
|
||||
super().__init__(output_path)
|
||||
|
||||
self.mw = mw
|
||||
|
@ -567,11 +567,11 @@ class QtAudioInputRecorder(Recorder):
|
|||
self._iodevice.readyRead.connect(self._on_read_ready) # type: ignore
|
||||
super().start(on_done)
|
||||
|
||||
def _on_read_ready(self):
|
||||
def _on_read_ready(self) -> None:
|
||||
self._buffer += self._iodevice.readAll()
|
||||
|
||||
def stop(self, on_done: Callable[[str], None]):
|
||||
def on_stop_timer():
|
||||
def stop(self, on_done: Callable[[str], None]) -> None:
|
||||
def on_stop_timer() -> None:
|
||||
# read anything remaining in buffer & stop
|
||||
self._on_read_ready()
|
||||
self._audio_input.stop()
|
||||
|
@ -580,7 +580,7 @@ class QtAudioInputRecorder(Recorder):
|
|||
showWarning(f"recording failed: {err}")
|
||||
return
|
||||
|
||||
def write_file():
|
||||
def write_file() -> None:
|
||||
# swallow the first 300ms to allow audio device to quiesce
|
||||
wait = int(44100 * self.STARTUP_DELAY)
|
||||
if len(self._buffer) <= wait:
|
||||
|
@ -595,7 +595,7 @@ class QtAudioInputRecorder(Recorder):
|
|||
wf.writeframes(self._buffer)
|
||||
wf.close()
|
||||
|
||||
def and_then(fut):
|
||||
def and_then(fut) -> None:
|
||||
fut.result()
|
||||
Recorder.stop(self, on_done)
|
||||
|
||||
|
@ -672,7 +672,7 @@ class PyAudioThreadedRecorder(threading.Thread):
|
|||
|
||||
|
||||
class PyAudioRecorder(Recorder):
|
||||
def __init__(self, mw: aqt.AnkiQt, output_path: str):
|
||||
def __init__(self, mw: aqt.AnkiQt, output_path: str) -> None:
|
||||
super().__init__(output_path)
|
||||
self.mw = mw
|
||||
|
||||
|
@ -686,7 +686,7 @@ class PyAudioRecorder(Recorder):
|
|||
while self.duration() < 1:
|
||||
time.sleep(0.1)
|
||||
|
||||
def func(fut):
|
||||
def func(fut) -> None:
|
||||
Recorder.stop(self, on_done)
|
||||
|
||||
self.thread.finish = True
|
||||
|
@ -715,7 +715,7 @@ class RecordDialog(QDialog):
|
|||
self._start_recording()
|
||||
self._setup_dialog()
|
||||
|
||||
def _setup_dialog(self):
|
||||
def _setup_dialog(self) -> None:
|
||||
self.setWindowTitle("Anki")
|
||||
icon = QLabel()
|
||||
icon.setPixmap(QPixmap(":/icons/media-record.png"))
|
||||
|
@ -740,10 +740,10 @@ class RecordDialog(QDialog):
|
|||
restoreGeom(self, "audioRecorder2")
|
||||
self.show()
|
||||
|
||||
def _save_diag(self):
|
||||
def _save_diag(self) -> None:
|
||||
saveGeom(self, "audioRecorder2")
|
||||
|
||||
def _start_recording(self):
|
||||
def _start_recording(self) -> None:
|
||||
driver = self.mw.pm.recording_driver()
|
||||
if driver is RecordingDriver.PyAudio:
|
||||
self._recorder = PyAudioRecorder(self.mw, namedtmp("rec.wav"))
|
||||
|
@ -755,18 +755,18 @@ class RecordDialog(QDialog):
|
|||
assert_exhaustive(driver)
|
||||
self._recorder.start(self._start_timer)
|
||||
|
||||
def _start_timer(self):
|
||||
def _start_timer(self) -> None:
|
||||
self._timer = t = QTimer(self._parent)
|
||||
t.timeout.connect(self._on_timer) # type: ignore
|
||||
t.setSingleShot(False)
|
||||
t.start(100)
|
||||
|
||||
def _on_timer(self):
|
||||
def _on_timer(self) -> None:
|
||||
self._recorder.on_timer()
|
||||
duration = self._recorder.duration()
|
||||
self.label.setText(tr(TR.MEDIA_RECORDINGTIME, secs="%0.1f" % duration))
|
||||
|
||||
def accept(self):
|
||||
def accept(self) -> None:
|
||||
self._timer.stop()
|
||||
|
||||
try:
|
||||
|
@ -775,10 +775,10 @@ class RecordDialog(QDialog):
|
|||
finally:
|
||||
QDialog.accept(self)
|
||||
|
||||
def reject(self):
|
||||
def reject(self) -> None:
|
||||
self._timer.stop()
|
||||
|
||||
def cleanup(out: str):
|
||||
def cleanup(out: str) -> None:
|
||||
os.unlink(out)
|
||||
|
||||
try:
|
||||
|
@ -790,7 +790,7 @@ class RecordDialog(QDialog):
|
|||
def record_audio(
|
||||
parent: QWidget, mw: aqt.AnkiQt, encode: bool, on_done: Callable[[str], None]
|
||||
):
|
||||
def after_record(path: str):
|
||||
def after_record(path: str) -> None:
|
||||
if not encode:
|
||||
on_done(path)
|
||||
else:
|
||||
|
|
|
@ -25,7 +25,7 @@ from aqt.utils import (
|
|||
class NewDeckStats(QDialog):
|
||||
"""New deck stats."""
|
||||
|
||||
def __init__(self, mw: aqt.main.AnkiQt):
|
||||
def __init__(self, mw: aqt.main.AnkiQt) -> None:
|
||||
QDialog.__init__(self, mw, Qt.Window)
|
||||
mw.setupDialogGC(self)
|
||||
self.mw = mw
|
||||
|
@ -60,11 +60,11 @@ class NewDeckStats(QDialog):
|
|||
aqt.dialogs.markClosed("NewDeckStats")
|
||||
QDialog.reject(self)
|
||||
|
||||
def closeWithCallback(self, callback):
|
||||
def closeWithCallback(self, callback) -> None:
|
||||
self.reject()
|
||||
callback()
|
||||
|
||||
def _imagePath(self):
|
||||
def _imagePath(self) -> str:
|
||||
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
|
||||
name = "anki-" + tr(TR.STATISTICS_STATS) + name
|
||||
file = getSaveFile(
|
||||
|
@ -77,17 +77,17 @@ class NewDeckStats(QDialog):
|
|||
)
|
||||
return file
|
||||
|
||||
def saveImage(self):
|
||||
def saveImage(self) -> None:
|
||||
path = self._imagePath()
|
||||
if not path:
|
||||
return
|
||||
self.form.web.page().printToPdf(path)
|
||||
tooltip(tr(TR.STATISTICS_SAVED))
|
||||
|
||||
def changePeriod(self, n):
|
||||
def changePeriod(self, n) -> None:
|
||||
pass
|
||||
|
||||
def changeScope(self, type):
|
||||
def changeScope(self, type) -> None:
|
||||
pass
|
||||
|
||||
def _on_bridge_cmd(self, cmd: str) -> bool:
|
||||
|
@ -149,11 +149,11 @@ class DeckStats(QDialog):
|
|||
aqt.dialogs.markClosed("DeckStats")
|
||||
QDialog.reject(self)
|
||||
|
||||
def closeWithCallback(self, callback):
|
||||
def closeWithCallback(self, callback) -> None:
|
||||
self.reject()
|
||||
callback()
|
||||
|
||||
def _imagePath(self):
|
||||
def _imagePath(self) -> str:
|
||||
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
|
||||
name = "anki-" + tr(TR.STATISTICS_STATS) + name
|
||||
file = getSaveFile(
|
||||
|
@ -166,7 +166,7 @@ class DeckStats(QDialog):
|
|||
)
|
||||
return file
|
||||
|
||||
def saveImage(self):
|
||||
def saveImage(self) -> None:
|
||||
path = self._imagePath()
|
||||
if not path:
|
||||
return
|
||||
|
|
|
@ -135,7 +135,7 @@ class StudyDeck(QDialog):
|
|||
return False
|
||||
return True
|
||||
|
||||
def onReset(self):
|
||||
def onReset(self) -> None:
|
||||
# model updated?
|
||||
if self.nameFunc:
|
||||
self.origNames = self.nameFunc()
|
||||
|
|
|
@ -40,12 +40,14 @@ class FullSyncChoice(enum.Enum):
|
|||
DOWNLOAD = 2
|
||||
|
||||
|
||||
def get_sync_status(mw: aqt.main.AnkiQt, callback: Callable[[SyncStatus], None]):
|
||||
def get_sync_status(
|
||||
mw: aqt.main.AnkiQt, callback: Callable[[SyncStatus], None]
|
||||
) -> None:
|
||||
auth = mw.pm.sync_auth()
|
||||
if not auth:
|
||||
return SyncStatus(required=SyncStatus.NO_CHANGES) # pylint:disable=no-member
|
||||
callback(SyncStatus(required=SyncStatus.NO_CHANGES)) # pylint:disable=no-member
|
||||
|
||||
def on_future_done(fut):
|
||||
def on_future_done(fut) -> None:
|
||||
try:
|
||||
out = fut.result()
|
||||
except Exception as e:
|
||||
|
@ -57,7 +59,7 @@ def get_sync_status(mw: aqt.main.AnkiQt, callback: Callable[[SyncStatus], None])
|
|||
mw.taskman.run_in_background(lambda: mw.col.sync_status(auth), on_future_done)
|
||||
|
||||
|
||||
def handle_sync_error(mw: aqt.main.AnkiQt, err: Exception):
|
||||
def handle_sync_error(mw: aqt.main.AnkiQt, err: Exception) -> None:
|
||||
if isinstance(err, SyncError):
|
||||
if err.is_auth_error():
|
||||
mw.pm.clear_sync_auth()
|
||||
|
@ -87,14 +89,14 @@ def sync_collection(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
|
|||
auth = mw.pm.sync_auth()
|
||||
assert auth
|
||||
|
||||
def on_timer():
|
||||
def on_timer() -> None:
|
||||
on_normal_sync_timer(mw)
|
||||
|
||||
timer = QTimer(mw)
|
||||
qconnect(timer.timeout, on_timer)
|
||||
timer.start(150)
|
||||
|
||||
def on_future_done(fut):
|
||||
def on_future_done(fut) -> None:
|
||||
mw.col.db.begin()
|
||||
timer.stop()
|
||||
try:
|
||||
|
@ -171,14 +173,14 @@ def on_full_sync_timer(mw: aqt.main.AnkiQt) -> None:
|
|||
def full_download(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
|
||||
mw.col.close_for_full_sync()
|
||||
|
||||
def on_timer():
|
||||
def on_timer() -> None:
|
||||
on_full_sync_timer(mw)
|
||||
|
||||
timer = QTimer(mw)
|
||||
qconnect(timer.timeout, on_timer)
|
||||
timer.start(150)
|
||||
|
||||
def on_future_done(fut):
|
||||
def on_future_done(fut) -> None:
|
||||
timer.stop()
|
||||
mw.col.reopen(after_full_sync=True)
|
||||
mw.reset()
|
||||
|
@ -199,14 +201,14 @@ def full_download(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
|
|||
def full_upload(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
|
||||
mw.col.close_for_full_sync()
|
||||
|
||||
def on_timer():
|
||||
def on_timer() -> None:
|
||||
on_full_sync_timer(mw)
|
||||
|
||||
timer = QTimer(mw)
|
||||
qconnect(timer.timeout, on_timer)
|
||||
timer.start(150)
|
||||
|
||||
def on_future_done(fut):
|
||||
def on_future_done(fut) -> None:
|
||||
timer.stop()
|
||||
mw.col.reopen(after_full_sync=True)
|
||||
mw.reset()
|
||||
|
@ -235,7 +237,7 @@ def sync_login(
|
|||
if username and password:
|
||||
break
|
||||
|
||||
def on_future_done(fut):
|
||||
def on_future_done(fut) -> None:
|
||||
try:
|
||||
auth = fut.result()
|
||||
except SyncError as e:
|
||||
|
|
|
@ -68,7 +68,7 @@ class TagLimit(QDialog):
|
|||
idx = self.dialog.inactiveList.indexFromItem(item)
|
||||
self.dialog.inactiveList.selectionModel().select(idx, mode)
|
||||
|
||||
def reject(self):
|
||||
def reject(self) -> None:
|
||||
self.tags = ""
|
||||
QDialog.reject(self)
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ class TaskManager(QObject):
|
|||
self._closures_lock = Lock()
|
||||
qconnect(self._closures_pending, self._on_closures_pending)
|
||||
|
||||
def run_on_main(self, closure: Closure):
|
||||
def run_on_main(self, closure: Closure) -> None:
|
||||
"Run the provided closure on the main thread."
|
||||
with self._closures_lock:
|
||||
self._closures.append(closure)
|
||||
|
@ -71,7 +71,7 @@ class TaskManager(QObject):
|
|||
):
|
||||
self.mw.progress.start(parent=parent, label=label, immediate=immediate)
|
||||
|
||||
def wrapped_done(fut):
|
||||
def wrapped_done(fut) -> None:
|
||||
self.mw.progress.finish()
|
||||
if on_done:
|
||||
on_done(fut)
|
||||
|
|
|
@ -481,7 +481,7 @@ if isWin:
|
|||
return []
|
||||
return list(map(self._voice_to_object, self.speaker.GetVoices()))
|
||||
|
||||
def _voice_to_object(self, voice: Any):
|
||||
def _voice_to_object(self, voice: Any) -> WindowsVoice:
|
||||
lang = voice.GetAttribute("language")
|
||||
lang = lcid_hex_str_to_lang_code(lang)
|
||||
name = self._tidy_name(voice.GetAttribute("name"))
|
||||
|
@ -561,7 +561,7 @@ if isWin:
|
|||
)
|
||||
asyncio.run(self.speakText(tag, voice.id))
|
||||
|
||||
def _on_done(self, ret: Future, cb: OnDoneCallback):
|
||||
def _on_done(self, ret: Future, cb: OnDoneCallback) -> None:
|
||||
ret.result()
|
||||
|
||||
# inject file into the top of the audio queue
|
||||
|
@ -572,7 +572,7 @@ if isWin:
|
|||
# then tell player to advance, which will cause the file to be played
|
||||
cb()
|
||||
|
||||
async def speakText(self, tag: TTSTag, voice_id):
|
||||
async def speakText(self, tag: TTSTag, voice_id) -> None:
|
||||
import winrt.windows.media.speechsynthesis as speechsynthesis # type: ignore
|
||||
import winrt.windows.storage.streams as streams # type: ignore
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import time
|
||||
from typing import Any, Dict
|
||||
|
||||
import requests
|
||||
|
||||
|
@ -23,7 +24,7 @@ class LatestVersionFinder(QThread):
|
|||
self.main = main
|
||||
self.config = main.pm.meta
|
||||
|
||||
def _data(self):
|
||||
def _data(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"ver": versionWithBuild(),
|
||||
"os": platDesc(),
|
||||
|
@ -32,7 +33,7 @@ class LatestVersionFinder(QThread):
|
|||
"crt": self.config["created"],
|
||||
}
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
if not self.config["updates"]:
|
||||
return
|
||||
d = self._data()
|
||||
|
@ -55,7 +56,7 @@ class LatestVersionFinder(QThread):
|
|||
self.clockIsOff.emit(diff) # type: ignore
|
||||
|
||||
|
||||
def askAndUpdate(mw, ver):
|
||||
def askAndUpdate(mw, ver) -> None:
|
||||
baseStr = tr(TR.QT_MISC_ANKI_UPDATEDANKI_HAS_BEEN_RELEASED, val=ver)
|
||||
msg = QMessageBox(mw)
|
||||
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) # type: ignore
|
||||
|
@ -72,6 +73,6 @@ def askAndUpdate(mw, ver):
|
|||
openLink(aqt.appWebsite)
|
||||
|
||||
|
||||
def showMessages(mw, data):
|
||||
def showMessages(mw, data) -> None:
|
||||
showText(data["msg"], parent=mw, type="html")
|
||||
mw.pm.meta["lastMsg"] = data["msgId"]
|
||||
|
|
|
@ -22,7 +22,7 @@ serverbaseurl = re.compile(r"^.+:\/\/[^\/]+")
|
|||
|
||||
|
||||
class AnkiWebPage(QWebEnginePage):
|
||||
def __init__(self, onBridgeCmd):
|
||||
def __init__(self, onBridgeCmd) -> None:
|
||||
QWebEnginePage.__init__(self)
|
||||
self._onBridgeCmd = onBridgeCmd
|
||||
self._setupBridge()
|
||||
|
@ -31,7 +31,7 @@ class AnkiWebPage(QWebEnginePage):
|
|||
def _setupBridge(self) -> None:
|
||||
class Bridge(QObject):
|
||||
@pyqtSlot(str, result=str) # type: ignore
|
||||
def cmd(self, str):
|
||||
def cmd(self, str) -> Any:
|
||||
return json.dumps(self.onCmd(str))
|
||||
|
||||
self._bridge = Bridge()
|
||||
|
@ -74,7 +74,7 @@ class AnkiWebPage(QWebEnginePage):
|
|||
script.setRunsOnSubFrames(False)
|
||||
self.profile().scripts().insert(script)
|
||||
|
||||
def javaScriptConsoleMessage(self, level, msg, line, srcID):
|
||||
def javaScriptConsoleMessage(self, level, msg, line, srcID) -> None:
|
||||
# not translated because console usually not visible,
|
||||
# and may only accept ascii text
|
||||
if srcID.startswith("data"):
|
||||
|
@ -101,7 +101,7 @@ class AnkiWebPage(QWebEnginePage):
|
|||
# https://github.com/ankitects/anki/pull/560
|
||||
sys.stdout.write(buf)
|
||||
|
||||
def acceptNavigationRequest(self, url, navType, isMainFrame):
|
||||
def acceptNavigationRequest(self, url, navType, isMainFrame) -> bool:
|
||||
if not self.open_links_externally:
|
||||
return super().acceptNavigationRequest(url, navType, isMainFrame)
|
||||
|
||||
|
@ -120,10 +120,10 @@ class AnkiWebPage(QWebEnginePage):
|
|||
openLink(url)
|
||||
return False
|
||||
|
||||
def _onCmd(self, str):
|
||||
def _onCmd(self, str) -> None:
|
||||
return self._onBridgeCmd(str)
|
||||
|
||||
def javaScriptAlert(self, url: QUrl, text: str):
|
||||
def javaScriptAlert(self, url: QUrl, text: str) -> None:
|
||||
showInfo(text)
|
||||
|
||||
|
||||
|
@ -150,7 +150,7 @@ class WebContent:
|
|||
You should avoid overwriting or interfering with existing data as much
|
||||
as possible, instead opting to append your own changes, e.g.:
|
||||
|
||||
def on_webview_will_set_content(web_content: WebContent, context):
|
||||
def on_webview_will_set_content(web_content: WebContent, context) -> None:
|
||||
web_content.body += "<my_html>"
|
||||
web_content.head += "<my_head>"
|
||||
|
||||
|
@ -173,7 +173,7 @@ class WebContent:
|
|||
Then append the subpaths to the corresponding web_content fields
|
||||
within a function subscribing to gui_hooks.webview_will_set_content:
|
||||
|
||||
def on_webview_will_set_content(web_content: WebContent, context):
|
||||
def on_webview_will_set_content(web_content: WebContent, context) -> None:
|
||||
addon_package = mw.addonManager.addonFromModule(__name__)
|
||||
web_content.css.append(
|
||||
f"/_addons/{addon_package}/web/my-addon.css")
|
||||
|
@ -251,7 +251,7 @@ class AnkiWebView(QWebEngineView):
|
|||
def set_open_links_externally(self, enable: bool) -> None:
|
||||
self._page.open_links_externally = enable
|
||||
|
||||
def onEsc(self):
|
||||
def onEsc(self) -> None:
|
||||
w = self.parent()
|
||||
while w:
|
||||
if isinstance(w, QDialog) or isinstance(w, QMainWindow):
|
||||
|
@ -266,7 +266,7 @@ class AnkiWebView(QWebEngineView):
|
|||
break
|
||||
w = w.parent()
|
||||
|
||||
def onCopy(self):
|
||||
def onCopy(self) -> None:
|
||||
if not self.selectedText():
|
||||
ctx = self._page.contextMenuData()
|
||||
if ctx and ctx.mediaType() == QWebEngineContextMenuData.MediaTypeImage:
|
||||
|
@ -274,16 +274,16 @@ class AnkiWebView(QWebEngineView):
|
|||
else:
|
||||
self.triggerPageAction(QWebEnginePage.Copy)
|
||||
|
||||
def onCut(self):
|
||||
def onCut(self) -> None:
|
||||
self.triggerPageAction(QWebEnginePage.Cut)
|
||||
|
||||
def onPaste(self):
|
||||
def onPaste(self) -> None:
|
||||
self.triggerPageAction(QWebEnginePage.Paste)
|
||||
|
||||
def onMiddleClickPaste(self):
|
||||
def onMiddleClickPaste(self) -> None:
|
||||
self.triggerPageAction(QWebEnginePage.Paste)
|
||||
|
||||
def onSelectAll(self):
|
||||
def onSelectAll(self) -> None:
|
||||
self.triggerPageAction(QWebEnginePage.SelectAll)
|
||||
|
||||
def contextMenuEvent(self, evt: QContextMenuEvent) -> None:
|
||||
|
@ -293,7 +293,7 @@ class AnkiWebView(QWebEngineView):
|
|||
gui_hooks.webview_will_show_context_menu(self, m)
|
||||
m.popup(QCursor.pos())
|
||||
|
||||
def dropEvent(self, evt):
|
||||
def dropEvent(self, evt) -> None:
|
||||
pass
|
||||
|
||||
def setHtml(self, html: str) -> None: # type: ignore
|
||||
|
@ -312,7 +312,7 @@ class AnkiWebView(QWebEngineView):
|
|||
if oldFocus:
|
||||
oldFocus.setFocus()
|
||||
|
||||
def load(self, url: QUrl):
|
||||
def load(self, url: QUrl) -> None:
|
||||
# allow queuing actions when loading url directly
|
||||
self._domDone = False
|
||||
super().load(url)
|
||||
|
@ -364,7 +364,7 @@ class AnkiWebView(QWebEngineView):
|
|||
else:
|
||||
return 3
|
||||
|
||||
def _getWindowColor(self):
|
||||
def _getWindowColor(self) -> QColor:
|
||||
if theme_manager.night_mode:
|
||||
return theme_manager.qcolor("window-bg")
|
||||
if isMac:
|
||||
|
@ -508,7 +508,7 @@ body {{ zoom: {zoom}; background: {background}; direction: {lang_dir}; {font} }}
|
|||
def _evalWithCallback(self, js: str, cb: Callable[[Any], Any]) -> None:
|
||||
if cb:
|
||||
|
||||
def handler(val):
|
||||
def handler(val) -> None:
|
||||
if self._shouldIgnoreWebEvent():
|
||||
print("ignored late js callback", cb)
|
||||
return
|
||||
|
@ -597,18 +597,18 @@ body {{ zoom: {zoom}; background: {background}; direction: {lang_dir}; {font} }}
|
|||
self.onBridgeCmd = func
|
||||
self._bridge_context = context
|
||||
|
||||
def hide_while_preserving_layout(self):
|
||||
def hide_while_preserving_layout(self) -> None:
|
||||
"Hide but keep existing size."
|
||||
sp = self.sizePolicy()
|
||||
sp.setRetainSizeWhenHidden(True)
|
||||
self.setSizePolicy(sp)
|
||||
self.hide()
|
||||
|
||||
def inject_dynamic_style_and_show(self):
|
||||
def inject_dynamic_style_and_show(self) -> None:
|
||||
"Add dynamic styling, and reveal."
|
||||
css = self.standard_css()
|
||||
|
||||
def after_style(arg):
|
||||
def after_style(arg) -> None:
|
||||
gui_hooks.webview_did_inject_style_into_page(self)
|
||||
self.show()
|
||||
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
|
||||
(sleep 1 && touch aqt)
|
||||
. ~/pyenv/bin/activate
|
||||
fswatch -o aqt | xargs -n1 -I{} sh -c 'printf \\033c; dmypy run aqt'
|
||||
fswatch -o aqt | xargs -n1 -I{} sh -c 'printf \\033c\\n; dmypy run aqt'
|
||||
|
||||
|
|
Loading…
Reference in a new issue