diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py
index 350a24446..03187804b 100644
--- a/qt/aqt/__init__.py
+++ b/qt/aqt/__init__.py
@@ -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
diff --git a/qt/aqt/about.py b/qt/aqt/about.py
index 66165ee62..b014ab7a5 100644
--- a/qt/aqt/about.py
+++ b/qt/aqt/about.py
@@ -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 = []
diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py
index 296dda0a0..bb1a80820 100644
--- a/qt/aqt/addcards.py
+++ b/qt/aqt/addcards.py
@@ -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()
diff --git a/qt/aqt/addons.py b/qt/aqt/addons.py
index 5b32d21e2..e91317edb 100644
--- a/qt/aqt/addons.py
+++ b/qt/aqt/addons.py
@@ -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):
diff --git a/qt/aqt/clayout.py b/qt/aqt/clayout.py
index 1525f9793..2386bb5b3 100644
--- a/qt/aqt/clayout.py
+++ b/qt/aqt/clayout.py
@@ -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("
", "")
hadHR = origLen != len(txt)
- def answerRepl(match):
+ def answerRepl(match: Match) -> str:
res = self.mw.reviewer.correct("exomple", "an example")
if hadHR:
res = "
" + 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)(.+)
(.+)", 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
\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{{%s}}
\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)
diff --git a/qt/aqt/customstudy.py b/qt/aqt/customstudy.py
index ff0ed557c..70fe0483b 100644
--- a/qt/aqt/customstudy.py
+++ b/qt/aqt/customstudy.py
@@ -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 "" + str(num) + ""
diff --git a/qt/aqt/dbcheck.py b/qt/aqt/dbcheck.py
index ad46bf231..3024973b6 100644
--- a/qt/aqt/dbcheck.py
+++ b/qt/aqt/dbcheck.py
@@ -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()
diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py
index ef8e0a621..1d0b28cdb 100644
--- a/qt/aqt/deckbrowser.py
+++ b/qt/aqt/deckbrowser.py
@@ -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:
"""
- 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 '{}
'.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'{cnt}'
@@ -222,7 +222,7 @@ class DeckBrowser:
buf += self._render_deck_node(child, ctx)
return buf
- def _topLevelDragRow(self):
+ def _topLevelDragRow(self) -> str:
return " |
"
# 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/")
diff --git a/qt/aqt/deckconf.py b/qt/aqt/deckconf.py
index f5446fa85..66b792f94 100644
--- a/qt/aqt/deckconf.py
+++ b/qt/aqt/deckconf.py
@@ -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)
diff --git a/qt/aqt/dyndeckconf.py b/qt/aqt/dyndeckconf.py
index 0082537d5..b63c638c7 100644
--- a/qt/aqt/dyndeckconf.py
+++ b/qt/aqt/dyndeckconf.py
@@ -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]]]:
diff --git a/qt/aqt/editcurrent.py b/qt/aqt/editcurrent.py
index f066c76ae..25616d466 100644
--- a/qt/aqt/editcurrent.py
+++ b/qt/aqt/editcurrent.py
@@ -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()
diff --git a/qt/aqt/emptycards.py b/qt/aqt/emptycards.py
index aa1016776..0c64e2e0b 100644
--- a/qt/aqt/emptycards.py
+++ b/qt/aqt/emptycards.py
@@ -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 = ""
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()
diff --git a/qt/aqt/errors.py b/qt/aqt/errors.py
index 485ddc898..d085b4b6d 100644
--- a/qt/aqt/errors.py
+++ b/qt/aqt/errors.py
@@ -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 + "" + error + "
"
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 ""
diff --git a/qt/aqt/exporting.py b/qt/aqt/exporting.py
index dd3157365..c22c3019a 100644
--- a/qt/aqt/exporting.py
+++ b/qt/aqt/exporting.py
@@ -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
diff --git a/qt/aqt/fields.py b/qt/aqt/fields.py
index 33b448dba..1f7c2a804 100644
--- a/qt/aqt/fields.py
+++ b/qt/aqt/fields.py
@@ -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)
diff --git a/qt/aqt/importing.py b/qt/aqt/importing.py
index e0b77df11..956c8374e 100644
--- a/qt/aqt/importing.py
+++ b/qt/aqt/importing.py
@@ -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:
diff --git a/qt/aqt/legacy.py b/qt/aqt/legacy.py
index 50729eb12..47a2242f3 100644
--- a/qt/aqt/legacy.py
+++ b/qt/aqt/legacy.py
@@ -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)
diff --git a/qt/aqt/main.py b/qt/aqt/main.py
index c549e5052..17e9619dd 100644
--- a/qt/aqt/main.py
+++ b/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""" % (
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""" % (
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""" % (
)
# legacy
- def _sync(self):
+ def _sync(self) -> None:
pass
onSync = on_sync_button_clicked
@@ -1057,7 +1061,7 @@ title="%s" %s>%s""" % (
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""" % (
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""" % (
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""" % (
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""" % (
# 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""" % (
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""" % (
# 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""" % (
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""" % (
# 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""" % (
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""" % (
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""" % (
frm.text.setTextCursor(cursor)
self.onDebugRet(frm)
- def onDebugRet(self, frm):
+ def onDebugRet(self, frm) -> None:
import pprint
import traceback
diff --git a/qt/aqt/mediacheck.py b/qt/aqt/mediacheck.py
index 0f844a643..42cd96a60 100644
--- a/qt/aqt/mediacheck.py
+++ b/qt/aqt/mediacheck.py
@@ -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
diff --git a/qt/aqt/mediasrv.py b/qt/aqt/mediasrv.py
index 1af54e39d..45d52e01e 100644
--- a/qt/aqt/mediasrv.py
+++ b/qt/aqt/mediasrv.py
@@ -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("/", 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):
diff --git a/qt/aqt/mediasync.py b/qt/aqt/mediasync.py
index ba5cd95d4..ad9eb9e9c 100644
--- a/qt/aqt/mediasync.py
+++ b/qt/aqt/mediasync.py
@@ -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)
diff --git a/qt/aqt/modelchooser.py b/qt/aqt/modelchooser.py
index 754d7b31a..d94dd6f03 100644
--- a/qt/aqt/modelchooser.py
+++ b/qt/aqt/modelchooser.py
@@ -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(
diff --git a/qt/aqt/models.py b/qt/aqt/models.py
index df8154ee7..ef17820b2 100644
--- a/qt/aqt/models.py
+++ b/qt/aqt/models.py
@@ -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
diff --git a/qt/aqt/overview.py b/qt/aqt/overview.py
index e2756bbc1..1bd461de4 100644
--- a/qt/aqt/overview.py
+++ b/qt/aqt/overview.py
@@ -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()
diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py
index 1248696d8..c00783a92 100644
--- a/qt/aqt/preferences.py
+++ b/qt/aqt/preferences.py
@@ -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()
diff --git a/qt/aqt/previewer.py b/qt/aqt/previewer.py
index 7557a6412..e0262562e 100644
--- a/qt/aqt/previewer.py
+++ b/qt/aqt/previewer.py
@@ -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)
)
diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py
index 6a42e4938..efecd2525 100644
--- a/qt/aqt/profiles.py
+++ b/qt/aqt/profiles.py
@@ -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
######################################################################
diff --git a/qt/aqt/progress.py b/qt/aqt/progress.py
index 47229a3ee..ad351d8ba 100644
--- a/qt/aqt/progress.py
+++ b/qt/aqt/progress.py
@@ -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
diff --git a/qt/aqt/qt.py b/qt/aqt/qt.py
index 43c42b17d..c31e3346b 100644
--- a/qt/aqt/qt.py
+++ b/qt/aqt/qt.py
@@ -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()
diff --git a/qt/aqt/reviewer.py b/qt/aqt/reviewer.py
index 8a3e05998..1a806a864 100644
--- a/qt/aqt/reviewer.py
+++ b/qt/aqt/reviewer.py
@@ -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()
diff --git a/qt/aqt/schema_change_tracker.py b/qt/aqt/schema_change_tracker.py
index e489f6de6..3d61fe516 100644
--- a/qt/aqt/schema_change_tracker.py
+++ b/qt/aqt/schema_change_tracker.py
@@ -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:
diff --git a/qt/aqt/sound.py b/qt/aqt/sound.py
index 6e53bf8fa..04b835e3f 100644
--- a/qt/aqt/sound.py
+++ b/qt/aqt/sound.py
@@ -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:
diff --git a/qt/aqt/stats.py b/qt/aqt/stats.py
index d9fe1c870..a1c290fc6 100644
--- a/qt/aqt/stats.py
+++ b/qt/aqt/stats.py
@@ -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
diff --git a/qt/aqt/studydeck.py b/qt/aqt/studydeck.py
index 5ee750687..61f0ec38c 100644
--- a/qt/aqt/studydeck.py
+++ b/qt/aqt/studydeck.py
@@ -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()
diff --git a/qt/aqt/sync.py b/qt/aqt/sync.py
index 695fe8d02..9e81277cd 100644
--- a/qt/aqt/sync.py
+++ b/qt/aqt/sync.py
@@ -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:
diff --git a/qt/aqt/taglimit.py b/qt/aqt/taglimit.py
index c28392a6d..e9e182ebf 100644
--- a/qt/aqt/taglimit.py
+++ b/qt/aqt/taglimit.py
@@ -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)
diff --git a/qt/aqt/taskman.py b/qt/aqt/taskman.py
index 264b4f6c1..53040d7b4 100644
--- a/qt/aqt/taskman.py
+++ b/qt/aqt/taskman.py
@@ -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)
diff --git a/qt/aqt/tts.py b/qt/aqt/tts.py
index 0bf9f9342..875983685 100644
--- a/qt/aqt/tts.py
+++ b/qt/aqt/tts.py
@@ -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
diff --git a/qt/aqt/update.py b/qt/aqt/update.py
index 32f956eb6..9c940fe3c 100644
--- a/qt/aqt/update.py
+++ b/qt/aqt/update.py
@@ -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"]
diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py
index 8fe1b8438..869f30928 100644
--- a/qt/aqt/webview.py
+++ b/qt/aqt/webview.py
@@ -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 += ""
web_content.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()
diff --git a/qt/dmypy-watch.sh b/qt/dmypy-watch.sh
index d5e2b3a00..86109eb62 100755
--- a/qt/dmypy-watch.sh
+++ b/qt/dmypy-watch.sh
@@ -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'