more typing updates

This commit is contained in:
Damien Elmes 2021-02-02 23:30:53 +10:00
parent 4b112950b8
commit 6426edb0ac
23 changed files with 151 additions and 122 deletions

View file

@ -136,7 +136,7 @@ class DialogManager:
def register_dialog(
self, name: str, creator: Union[Callable, type], instance: Optional[Any] = None
):
) -> None:
"""Allows add-ons to register a custom dialog to be managed by Anki's dialog
manager, which ensures that only one copy of the window is open at once,
and that the dialog cleans up asynchronously when the collection closes
@ -189,12 +189,12 @@ def setupLangAndBackend(
pass
# add _ and ngettext globals used by legacy code
def fn__(arg) -> None:
def fn__(arg) -> None: # type: ignore
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) -> None:
def fn_ngettext(a, b, c) -> None: # type: ignore
print("".join(traceback.format_stack()[-2]))
print("ngettext global will break in the future; please see anki/lang.py")
return b
@ -244,7 +244,7 @@ class AnkiApp(QApplication):
KEY = "anki" + checksum(getpass.getuser())
TMOUT = 30000
def __init__(self, argv) -> None:
def __init__(self, argv: List[str]) -> None:
QApplication.__init__(self, argv)
self._argv = argv
@ -267,7 +267,7 @@ class AnkiApp(QApplication):
self._srv.listen(self.KEY)
return False
def sendMsg(self, txt) -> bool:
def sendMsg(self, txt: str) -> bool:
sock = QLocalSocket(self)
sock.connectToServer(self.KEY, QIODevice.WriteOnly)
if not sock.waitForConnected(self.TMOUT):
@ -298,14 +298,14 @@ class AnkiApp(QApplication):
# OS X file/url handler
##################################################
def event(self, evt) -> bool:
def event(self, evt: QEvent) -> 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) -> Tuple[argparse.Namespace, List[str]]:
def parseArgs(argv: List[str]) -> 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) -> Tuple[argparse.Namespace, List[str]]:
return parser.parse_known_args(argv[1:])
def setupGL(pm) -> None:
def setupGL(pm: aqt.profiles.ProfileManager) -> None:
if isMac:
return
@ -343,7 +343,7 @@ def setupGL(pm) -> None:
ctypes.CDLL("libGL.so.1", ctypes.RTLD_GLOBAL)
# catch opengl errors
def msgHandler(category, ctx, msg) -> None:
def msgHandler(category: Any, ctx: Any, msg: Any) -> None:
if category == QtDebugMsg:
category = "debug"
elif category == QtInfoMsg:
@ -420,7 +420,7 @@ def run() -> None:
)
def _run(argv=None, exec=True) -> Optional[AnkiApp]:
def _run(argv: Optional[List[str]] = None, exec: bool = 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

View file

@ -4,6 +4,7 @@
import copy
import json
import re
from concurrent.futures import Future
from typing import Any, Dict, List, Match, Optional
import aqt
@ -45,10 +46,10 @@ class CardLayout(QDialog):
self,
mw: AnkiQt,
note: Note,
ord=0,
ord: int = 0,
parent: Optional[QWidget] = None,
fill_empty: bool = False,
):
) -> None:
QDialog.__init__(self, parent or mw, Qt.Window)
mw.setupDialogGC(self)
self.mw = aqt.mw
@ -564,7 +565,7 @@ class CardLayout(QDialog):
def get_count() -> int:
return self.mm.template_use_count(self.model["id"], self.ord)
def on_done(fut) -> None:
def on_done(fut: Future) -> None:
card_cnt = fut.result()
template = self.current_template()
@ -798,7 +799,7 @@ class CardLayout(QDialog):
def save() -> None:
self.mm.save(self.model)
def on_done(fut) -> None:
def on_done(fut: Future) -> None:
try:
fut.result()
except TemplateError as e:

View file

@ -22,7 +22,7 @@ TYPE_ALL = 3
class CustomStudy(QDialog):
def __init__(self, mw) -> None:
def __init__(self, mw: aqt.AnkiQt) -> None:
QDialog.__init__(self, mw)
self.mw = mw
self.deck = self.mw.col.decks.current()
@ -57,7 +57,7 @@ class CustomStudy(QDialog):
typeShow = False
ok = tr(TR.CUSTOM_STUDY_OK)
def plus(num) -> str:
def plus(num: Union[int, str]) -> str:
if num == 1000:
num = "1000+"
return "<b>" + str(num) + "</b>"

View file

@ -3,6 +3,8 @@
from __future__ import annotations
from concurrent.futures import Future
import aqt
from anki.collection import DatabaseCheckProgress, ProgressKind
from aqt.qt import *
@ -31,7 +33,7 @@ def check_db(mw: aqt.AnkiQt) -> None:
qconnect(timer.timeout, on_timer)
timer.start(100)
def on_future_done(fut) -> None:
def on_future_done(fut: Future) -> None:
timer.stop()
ret, ok = fut.result()

View file

@ -13,13 +13,13 @@ class DeckChooser(QHBoxLayout):
self, mw: AnkiQt, widget: QWidget, label: bool = True, start: Any = None
) -> None:
QHBoxLayout.__init__(self)
self.widget = widget # type: ignore
self._widget = widget # type: ignore
self.mw = mw
self.label = label
self.setContentsMargins(0, 0, 0, 0)
self.setSpacing(8)
self.setupDecks()
self.widget.setLayout(self)
self._widget.setLayout(self)
gui_hooks.current_note_type_did_change.append(self.onModelChangeNew)
def setupDecks(self) -> None:
@ -30,7 +30,7 @@ class DeckChooser(QHBoxLayout):
self.deck = QPushButton(clicked=self.onDeckChange) # type: ignore
self.deck.setAutoDefault(False)
self.deck.setToolTip(shortcut(tr(TR.QT_MISC_TARGET_DECK_CTRLANDD)))
QShortcut(QKeySequence("Ctrl+D"), self.widget, activated=self.onDeckChange) # type: ignore
QShortcut(QKeySequence("Ctrl+D"), self._widget, activated=self.onDeckChange) # type: ignore
self.addWidget(self.deck)
# starting label
if self.mw.col.conf.get("addToCur", True):
@ -59,10 +59,10 @@ class DeckChooser(QHBoxLayout):
self.deck.setSizePolicy(sizePolicy)
def show(self) -> None:
self.widget.show() # type: ignore
self._widget.show() # type: ignore
def hide(self) -> None:
self.widget.hide() # type: ignore
self._widget.hide() # type: ignore
def cleanup(self) -> None:
gui_hooks.current_note_type_did_change.remove(self.onModelChangeNew)
@ -88,7 +88,7 @@ class DeckChooser(QHBoxLayout):
title=tr(TR.QT_MISC_CHOOSE_DECK),
help=HelpPage.EDITING,
cancel=False,
parent=self.widget,
parent=self._widget,
geomKey="selectDeck",
)
if ret.name:

View file

@ -4,6 +4,7 @@
from __future__ import annotations
import re
from concurrent.futures import Future
import aqt
from anki.collection import EmptyCardsReport, NoteWithEmptyCards
@ -15,7 +16,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) -> None:
def on_done(fut: Future) -> None:
mw.progress.finish()
report: EmptyCardsReport = fut.result()
if not report.notes:
@ -74,7 +75,7 @@ class EmptyCardsDialog(QDialog):
def delete() -> int:
return self._delete_cards(self.form.keep_notes.isChecked())
def on_done(fut) -> None:
def on_done(fut: Future) -> None:
self.mw.progress.finish()
try:
count = fut.result()

View file

@ -1,6 +1,8 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from concurrent.futures import Future
import aqt
from anki.consts import *
from anki.errors import TemplateError
@ -235,7 +237,7 @@ class FieldDialog(QDialog):
def save() -> None:
self.mm.save(self.model)
def on_done(fut) -> None:
def on_done(fut: Future) -> None:
try:
fut.result()
except TemplateError as e:

View file

@ -13,8 +13,9 @@ import time
import weakref
import zipfile
from argparse import Namespace
from concurrent.futures import Future
from threading import Thread
from typing import Any, Callable, List, Optional, Sequence, TextIO, Tuple, cast
from typing import Any, Callable, Dict, List, Optional, Sequence, TextIO, Tuple, cast
import anki
import aqt
@ -337,13 +338,13 @@ class AnkiQt(QMainWindow):
):
return
def doOpen(path) -> None:
def doOpen(path: str) -> None:
self._openBackup(path)
getFile(
self.profileDiag,
tr(TR.QT_MISC_REVERT_TO_BACKUP),
cb=doOpen,
cb=doOpen, # type: ignore
filter="*.colpkg",
dir=self.pm.backupFolder(),
)
@ -370,7 +371,7 @@ class AnkiQt(QMainWindow):
def downgrade() -> List[str]:
return self.pm.downgrade(profiles)
def on_done(future) -> None:
def on_done(future: Future) -> None:
self.progress.finish()
problems = future.result()
if not problems:
@ -568,7 +569,7 @@ class AnkiQt(QMainWindow):
##########################################################################
class BackupThread(Thread):
def __init__(self, path, data) -> None:
def __init__(self, path: str, data: bytes) -> None:
Thread.__init__(self)
self.path = path
self.data = data
@ -629,7 +630,7 @@ class AnkiQt(QMainWindow):
# State machine
##########################################################################
def moveToState(self, state: str, *args) -> None:
def moveToState(self, state: str, *args: Any) -> None:
# print("-> move from", self.state, "to", state)
oldState = self.state or "dummy"
cleanup = getattr(self, "_" + oldState + "Cleanup", None)
@ -804,7 +805,7 @@ title="%s" %s>%s</button>""" % (
signal.signal(signal.SIGINT, self.onUnixSignal)
signal.signal(signal.SIGTERM, self.onUnixSignal)
def onUnixSignal(self, signum, frame) -> None:
def onUnixSignal(self, signum: Any, frame: Any) -> None:
# schedule a rollback & quit
def quit() -> None:
self.col.db.rollback()
@ -1184,14 +1185,14 @@ title="%s" %s>%s</button>""" % (
qconnect(self.autoUpdate.clockIsOff, self.clockIsOff)
self.autoUpdate.start()
def newVerAvail(self, ver) -> None:
def newVerAvail(self, ver: str) -> None:
if self.pm.meta.get("suppressUpdate", None) != ver:
aqt.update.askAndUpdate(self, ver)
def newMsg(self, data) -> None:
def newMsg(self, data: Dict) -> None:
aqt.update.showMessages(self, data)
def clockIsOff(self, diff) -> None:
def clockIsOff(self, diff: int) -> None:
if devMode:
print("clock is off; ignoring")
return
@ -1374,11 +1375,11 @@ title="%s" %s>%s</button>""" % (
d.show()
def _captureOutput(self, on: bool) -> None:
mw = self
mw2 = self
class Stream:
def write(self, data) -> None:
mw._output += data
def write(self, data: str) -> None:
mw2._output += data
if on:
self._output = ""
@ -1428,7 +1429,7 @@ title="%s" %s>%s</button>""" % (
self._card_repr(card)
return card
def onDebugPrint(self, frm) -> None:
def onDebugPrint(self, frm: aqt.forms.debug.Ui_Dialog) -> None:
cursor = frm.text.textCursor()
position = cursor.position()
cursor.select(QTextCursor.LineUnderCursor)
@ -1441,7 +1442,7 @@ title="%s" %s>%s</button>""" % (
frm.text.setTextCursor(cursor)
self.onDebugRet(frm)
def onDebugRet(self, frm) -> None:
def onDebugRet(self, frm: aqt.forms.debug.Ui_Dialog) -> None:
import pprint
import traceback

View file

@ -20,7 +20,7 @@ class ModelChooser(QHBoxLayout):
and the caller can call .onModelChange() to pull up the dialog when they
are ready."""
QHBoxLayout.__init__(self)
self.widget = widget # type: ignore
self._widget = widget # type: ignore
self.mw = mw
self.deck = mw.col
self.label = label
@ -32,7 +32,7 @@ class ModelChooser(QHBoxLayout):
self.setSpacing(8)
self.setupModels()
gui_hooks.state_did_reset.append(self.onReset)
self.widget.setLayout(self)
self._widget.setLayout(self)
def setupModels(self) -> None:
if self.label:
@ -41,7 +41,7 @@ class ModelChooser(QHBoxLayout):
# models box
self.models = QPushButton()
self.models.setToolTip(shortcut(tr(TR.QT_MISC_CHANGE_NOTE_TYPE_CTRLANDN)))
QShortcut(QKeySequence("Ctrl+N"), self.widget, activated=self.on_activated) # type: ignore
QShortcut(QKeySequence("Ctrl+N"), self._widget, activated=self.on_activated) # type: ignore
self.models.setAutoDefault(False)
self.addWidget(self.models)
qconnect(self.models.clicked, self.onModelChange)
@ -57,15 +57,15 @@ class ModelChooser(QHBoxLayout):
self.updateModels()
def show(self) -> None:
self.widget.show() # type: ignore
self._widget.show() # type: ignore
def hide(self) -> None:
self.widget.hide() # type: ignore
self._widget.hide() # type: ignore
def onEdit(self) -> None:
import aqt.models
aqt.models.Models(self.mw, self.widget)
aqt.models.Models(self.mw, self._widget)
def onModelChange(self) -> None:
from aqt.studydeck import StudyDeck
@ -84,7 +84,7 @@ class ModelChooser(QHBoxLayout):
title=tr(TR.QT_MISC_CHOOSE_NOTE_TYPE),
help=HelpPage.NOTE_TYPE,
current=current,
parent=self.widget,
parent=self._widget,
buttons=[edit],
cancel=True,
geomKey="selectModel",

View file

@ -1,6 +1,7 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from concurrent.futures import Future
from operator import itemgetter
from typing import Any, List, Optional, Sequence
@ -93,7 +94,7 @@ class Models(QDialog):
qconnect(f.modelsList.itemDoubleClicked, self.onRename)
def on_done(fut) -> None:
def on_done(fut: Future) -> None:
self.updateModelsList(fut.result())
self.maybe_select_provided_notetype()
@ -113,7 +114,7 @@ class Models(QDialog):
self.mm.save(nt)
return self.col.models.all_use_counts()
def on_done(fut) -> None:
def on_done(fut: Future) -> None:
self.updateModelsList(fut.result())
self.mw.taskman.with_progress(save, on_done, self)
@ -163,7 +164,7 @@ class Models(QDialog):
self.mm.rem(nt)
return self.col.models.all_use_counts()
def on_done(fut) -> None:
def on_done(fut: Future) -> None:
self.updateModelsList(fut.result())
self.mw.taskman.with_progress(save, on_done, self)

View file

@ -113,9 +113,9 @@ class LoadMetaResult:
class AnkiRestart(SystemExit):
def __init__(self, *args, **kwargs) -> None:
self.exitcode = kwargs.pop("exitcode", 0)
super().__init__(*args, **kwargs) # type: ignore
def __init__(self, exitcode: int = 0) -> None:
self.exitcode = exitcode
super().__init__()
class ProfileManager:
@ -136,7 +136,7 @@ class ProfileManager:
return res
# profile load on startup
def openProfile(self, profile) -> None:
def openProfile(self, profile: str) -> None:
if profile:
if profile not in self.profiles():
QMessageBox.critical(
@ -185,7 +185,7 @@ class ProfileManager:
self.base = newBase
shutil.move(oldBase, self.base)
def _tryToMigrateFolder(self, oldBase) -> None:
def _tryToMigrateFolder(self, oldBase: str) -> None:
from PyQt5 import QtGui, QtWidgets
app = QtWidgets.QApplication([])
@ -257,7 +257,7 @@ class ProfileManager:
return n
def _unpickle(self, data) -> Any:
def _unpickle(self, data: bytes) -> Any:
class Unpickler(pickle.Unpickler):
def find_class(self, module: str, name: str) -> Any:
if module == "PyQt5.sip":
@ -282,7 +282,7 @@ class ProfileManager:
up = Unpickler(io.BytesIO(data), errors="ignore")
return up.load()
def _pickle(self, obj) -> bytes:
def _pickle(self, obj: Any) -> bytes:
# pyqt needs to be updated to fix
# 'PY_SSIZE_T_CLEAN will be required for '#' formats' warning
# check if this is still required for pyqt6
@ -290,7 +290,7 @@ class ProfileManager:
warnings.simplefilter("ignore")
return pickle.dumps(obj, protocol=4)
def load(self, name) -> bool:
def load(self, name: str) -> bool:
assert name != "_global"
data = self.db.scalar(
"select cast(data as blob) from profiles where name = ?", name
@ -316,14 +316,14 @@ class ProfileManager:
self.db.execute(sql, self._pickle(self.meta), "_global")
self.db.commit()
def create(self, name) -> None:
def create(self, name: str) -> None:
prof = profileConf.copy()
self.db.execute(
"insert or ignore into profiles values (?, ?)", name, self._pickle(prof)
)
self.db.commit()
def remove(self, name) -> None:
def remove(self, name: str) -> None:
p = self.profileFolder()
if os.path.exists(p):
send2trash(p)
@ -335,7 +335,7 @@ class ProfileManager:
if os.path.exists(p):
send2trash(p)
def rename(self, name) -> None:
def rename(self, name: str) -> None:
oldName = self.name
oldFolder = self.profileFolder()
self.name = name
@ -379,7 +379,7 @@ class ProfileManager:
# Folder handling
######################################################################
def profileFolder(self, create=True) -> str:
def profileFolder(self, create: bool = True) -> str:
path = os.path.join(self.base, self.name)
if create:
self._ensureExists(path)
@ -397,7 +397,7 @@ class ProfileManager:
# Downgrade
######################################################################
def downgrade(self, profiles=List[str]) -> List[str]:
def downgrade(self, profiles: List[str]) -> List[str]:
"Downgrade all profiles. Return a list of profiles that couldn't be opened."
problem_profiles = []
for name in profiles:
@ -449,7 +449,7 @@ class ProfileManager:
os.makedirs(dataDir)
return os.path.join(dataDir, "Anki2")
def _loadMeta(self, retrying=False) -> LoadMetaResult:
def _loadMeta(self, retrying: bool = False) -> LoadMetaResult:
result = LoadMetaResult()
result.firstTime = False
result.loadError = retrying
@ -560,7 +560,7 @@ create table if not exists profiles
return self.setDefaultLang(f.lang.currentRow())
self.setLang(code)
def setLang(self, code) -> None:
def setLang(self, code: str) -> None:
self.meta["defaultLang"] = code
sql = "update profiles set data = ? where name = ?"
self.db.execute(sql, self._pickle(self.meta), "_global")
@ -602,7 +602,7 @@ create table if not exists profiles
def last_addon_update_check(self) -> int:
return self.meta.get("last_addon_update_check", 0)
def set_last_addon_update_check(self, secs) -> None:
def set_last_addon_update_check(self, secs: int) -> None:
self.meta["last_addon_update_check"] = secs
def night_mode(self) -> bool:

View file

@ -39,7 +39,7 @@ def debug() -> None:
if os.environ.get("DEBUG"):
def info(type, value, tb) -> None:
def info(type, value, tb) -> None: # type: ignore
for line in traceback.format_exception(type, value, tb):
sys.stdout.write(line)
pyqtRemoveInputHook()

View file

@ -595,7 +595,7 @@ class QtAudioInputRecorder(Recorder):
wf.writeframes(self._buffer)
wf.close()
def and_then(fut) -> None:
def and_then(fut: Future) -> None:
fut.result()
Recorder.stop(self, on_done)
@ -686,7 +686,7 @@ class PyAudioRecorder(Recorder):
while self.duration() < 1:
time.sleep(0.1)
def func(fut) -> None:
def func(fut: Future) -> None:
Recorder.stop(self, on_done)
self.thread.finish = True
@ -789,7 +789,7 @@ class RecordDialog(QDialog):
def record_audio(
parent: QWidget, mw: aqt.AnkiQt, encode: bool, on_done: Callable[[str], None]
):
) -> None:
def after_record(path: str) -> None:
if not encode:
on_done(path)
@ -812,7 +812,7 @@ def play(filename: str) -> None:
av_player.play_file(filename)
def playFromText(text) -> None:
def playFromText(text: Any) -> None:
print("playFromText() deprecated")

View file

@ -4,6 +4,7 @@
from __future__ import annotations
import time
from typing import Any
import aqt
from aqt import gui_hooks
@ -60,7 +61,7 @@ class NewDeckStats(QDialog):
aqt.dialogs.markClosed("NewDeckStats")
QDialog.reject(self)
def closeWithCallback(self, callback) -> None:
def closeWithCallback(self, callback: Callable[[], None]) -> None:
self.reject()
callback()
@ -84,10 +85,11 @@ class NewDeckStats(QDialog):
self.form.web.page().printToPdf(path)
tooltip(tr(TR.STATISTICS_SAVED))
def changePeriod(self, n) -> None:
# legacy add-ons
def changePeriod(self, n: Any) -> None:
pass
def changeScope(self, type) -> None:
def changeScope(self, type: Any) -> None:
pass
def _on_bridge_cmd(self, cmd: str) -> bool:
@ -149,7 +151,7 @@ class DeckStats(QDialog):
aqt.dialogs.markClosed("DeckStats")
QDialog.reject(self)
def closeWithCallback(self, callback) -> None:
def closeWithCallback(self, callback: Callable[[], None]) -> None:
self.reject()
callback()

View file

@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from typing import Optional
from typing import List, Optional
import aqt
from aqt import gui_hooks
@ -25,17 +25,17 @@ from aqt.utils import (
class StudyDeck(QDialog):
def __init__(
self,
mw,
names=None,
accept=None,
title=None,
mw: aqt.AnkiQt,
names: Callable = None,
accept: str = None,
title: str = None,
help: HelpPageArgument = HelpPage.KEYBOARD_SHORTCUTS,
current=None,
cancel=True,
parent=None,
dyn=False,
buttons=None,
geomKey="default",
current: Optional[str] = None,
cancel: bool = True,
parent: Optional[QDialog] = None,
dyn: bool = False,
buttons: Optional[List[str]] = None,
geomKey: str = "default",
) -> None:
QDialog.__init__(self, parent or mw)
if buttons is None:
@ -65,18 +65,18 @@ class StudyDeck(QDialog):
if title:
self.setWindowTitle(title)
if not names:
names = [
names_ = [
d.name
for d in self.mw.col.decks.all_names_and_ids(
include_filtered=dyn, skip_empty_default=True
)
]
self.nameFunc = None
self.origNames = names
self.origNames = names_
else:
self.nameFunc = names
self.origNames = names()
self.name = None
self.name: Optional[str] = None
self.ok = self.form.buttonBox.addButton(
accept or tr(TR.DECKS_STUDY), QDialogButtonBox.AcceptRole
)

View file

@ -5,6 +5,7 @@ from __future__ import annotations
import enum
import os
from concurrent.futures import Future
from typing import Callable, Tuple
import aqt
@ -48,7 +49,7 @@ def get_sync_status(
callback(SyncStatus(required=SyncStatus.NO_CHANGES)) # pylint:disable=no-member
return
def on_future_done(fut) -> None:
def on_future_done(fut: Future) -> None:
try:
out = fut.result()
except Exception as e:
@ -97,7 +98,7 @@ def sync_collection(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
qconnect(timer.timeout, on_timer)
timer.start(150)
def on_future_done(fut) -> None:
def on_future_done(fut: Future) -> None:
mw.col.db.begin()
timer.stop()
try:
@ -181,7 +182,7 @@ def full_download(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
qconnect(timer.timeout, on_timer)
timer.start(150)
def on_future_done(fut) -> None:
def on_future_done(fut: Future) -> None:
timer.stop()
mw.col.reopen(after_full_sync=True)
mw.reset()
@ -209,7 +210,7 @@ def full_upload(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
qconnect(timer.timeout, on_timer)
timer.start(150)
def on_future_done(fut) -> None:
def on_future_done(fut: Future) -> None:
timer.stop()
mw.col.reopen(after_full_sync=True)
mw.reset()
@ -229,7 +230,10 @@ def full_upload(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
def sync_login(
mw: aqt.main.AnkiQt, on_success: Callable[[], None], username="", password=""
mw: aqt.main.AnkiQt,
on_success: Callable[[], None],
username: str = "",
password: str = "",
) -> None:
while True:
(username, password) = get_id_and_pass_from_user(mw, username, password)
@ -238,7 +242,7 @@ def sync_login(
if username and password:
break
def on_future_done(fut) -> None:
def on_future_done(fut: Future) -> None:
try:
auth = fut.result()
except SyncError as e:
@ -282,7 +286,7 @@ def ask_user_to_decide_direction() -> FullSyncChoice:
def get_id_and_pass_from_user(
mw: aqt.main.AnkiQt, username="", password=""
mw: aqt.main.AnkiQt, username: str = "", password: str = ""
) -> Tuple[str, str]:
diag = QDialog(mw)
diag.setWindowTitle("Anki")

View file

@ -92,7 +92,7 @@ class TagEdit(QLineEdit):
self.completer.setCompletionPrefix(self.text())
self.completer.complete()
def focusOutEvent(self, evt) -> None:
def focusOutEvent(self, evt: QFocusEvent) -> None:
QLineEdit.focusOutEvent(self, evt)
self.lostFocus.emit() # type: ignore
self.completer.popup().hide()
@ -109,7 +109,6 @@ class TagCompleter(QCompleter):
model: QStringListModel,
parent: QWidget,
edit: TagEdit,
*args,
) -> None:
QCompleter.__init__(self, model, parent)
self.tags: List[str] = []

View file

@ -68,10 +68,10 @@ class TaskManager(QObject):
parent: Optional[QWidget] = None,
label: Optional[str] = None,
immediate: bool = False,
):
) -> None:
self.mw.progress.start(parent=parent, label=label, immediate=immediate)
def wrapped_done(fut) -> None:
def wrapped_done(fut: Future) -> None:
self.mw.progress.finish()
if on_done:
on_done(fut)

View file

@ -35,6 +35,7 @@ from dataclasses import dataclass
from operator import attrgetter
from typing import Any, List, Optional, cast
import anki
from anki import hooks
from anki.sound import AVTag, TTSTag
from anki.utils import checksum, isWin, tmpdir
@ -125,7 +126,9 @@ def all_tts_voices() -> List[TTSVoice]:
return all_voices
def on_tts_voices(text: str, field, filter: str, ctx) -> str:
def on_tts_voices(
text: str, field: str, filter: str, ctx: anki.template.TemplateRenderContext
) -> str:
if filter != "tts-voices":
return text
voices = all_tts_voices()
@ -572,7 +575,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) -> None:
async def speakText(self, tag: TTSTag, voice_id: Any) -> None:
import winrt.windows.media.speechsynthesis as speechsynthesis # type: ignore
import winrt.windows.storage.streams as streams # type: ignore

View file

@ -56,7 +56,7 @@ class LatestVersionFinder(QThread):
self.clockIsOff.emit(diff) # type: ignore
def askAndUpdate(mw, ver) -> None:
def askAndUpdate(mw: aqt.AnkiQt, ver: str) -> None:
baseStr = tr(TR.QT_MISC_ANKI_UPDATEDANKI_HAS_BEEN_RELEASED, val=ver)
msg = QMessageBox(mw)
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) # type: ignore
@ -73,6 +73,6 @@ def askAndUpdate(mw, ver) -> None:
openLink(aqt.appWebsite)
def showMessages(mw, data) -> None:
def showMessages(mw: aqt.AnkiQt, data: Dict) -> None:
showText(data["msg"], parent=mw, type="html")
mw.pm.meta["lastMsg"] = data["msgId"]

View file

@ -468,6 +468,7 @@ def disable_help_button(widget: QWidget) -> None:
def getFile(
parent: QDialog,
title: str,
# single file returned unless multi=True
cb: Optional[Callable[[Union[str, Sequence[str]]], None]],
filter: str = "*.*",
dir: Optional[str] = None,

View file

@ -5,7 +5,7 @@ import dataclasses
import json
import re
import sys
from typing import Any, Callable, List, Optional, Sequence, Tuple
from typing import Any, Callable, List, Optional, Sequence, Tuple, cast
import anki
from anki.lang import is_rtl
@ -20,9 +20,11 @@ serverbaseurl = re.compile(r"^.+:\/\/[^\/]+")
# Page for debug messages
##########################################################################
BridgeCommandHandler = Callable[[str], Any]
class AnkiWebPage(QWebEnginePage):
def __init__(self, onBridgeCmd) -> None:
def __init__(self, onBridgeCmd: BridgeCommandHandler) -> None:
QWebEnginePage.__init__(self)
self._onBridgeCmd = onBridgeCmd
self._setupBridge()
@ -31,7 +33,7 @@ class AnkiWebPage(QWebEnginePage):
def _setupBridge(self) -> None:
class Bridge(QObject):
@pyqtSlot(str, result=str) # type: ignore
def cmd(self, str) -> Any:
def cmd(self, str: str) -> Any:
return json.dumps(self.onCmd(str))
self._bridge = Bridge()
@ -74,7 +76,13 @@ class AnkiWebPage(QWebEnginePage):
script.setRunsOnSubFrames(False)
self.profile().scripts().insert(script)
def javaScriptConsoleMessage(self, level, msg, line, srcID) -> None:
def javaScriptConsoleMessage(
self,
level: QWebEnginePage.JavaScriptConsoleMessageLevel,
msg: str,
line: int,
srcID: str,
) -> None:
# not translated because console usually not visible,
# and may only accept ascii text
if srcID.startswith("data"):
@ -82,13 +90,15 @@ class AnkiWebPage(QWebEnginePage):
else:
srcID = serverbaseurl.sub("", srcID[:80], 1)
if level == QWebEnginePage.InfoMessageLevel:
level = "info"
level_str = "info"
elif level == QWebEnginePage.WarningMessageLevel:
level = "warning"
level_str = "warning"
elif level == QWebEnginePage.ErrorMessageLevel:
level = "error"
level_str = "error"
else:
level_str = str(level)
buf = "JS %(t)s %(f)s:%(a)d %(b)s" % dict(
t=level, a=line, f=srcID, b=msg + "\n"
t=level_str, a=line, f=srcID, b=msg + "\n"
)
if "MathJax localStorage" in buf:
# silence localStorage noise
@ -101,7 +111,9 @@ class AnkiWebPage(QWebEnginePage):
# https://github.com/ankitects/anki/pull/560
sys.stdout.write(buf)
def acceptNavigationRequest(self, url, navType, isMainFrame) -> bool:
def acceptNavigationRequest(
self, url: QUrl, navType: Any, isMainFrame: bool
) -> bool:
if not self.open_links_externally:
return super().acceptNavigationRequest(url, navType, isMainFrame)
@ -113,14 +125,14 @@ class AnkiWebPage(QWebEnginePage):
# catch buggy <a href='#' onclick='func()'> links
from aqt import mw
if url.matches(QUrl(mw.serverURL()), QUrl.RemoveFragment):
if url.matches(QUrl(mw.serverURL()), cast(Any, QUrl.RemoveFragment)):
print("onclick handler needs to return false")
return False
# load all other links in browser
openLink(url)
return False
def _onCmd(self, str) -> None:
def _onCmd(self, str: str) -> None:
return self._onBridgeCmd(str)
def javaScriptAlert(self, url: QUrl, text: str) -> None:
@ -293,7 +305,7 @@ class AnkiWebView(QWebEngineView):
gui_hooks.webview_will_show_context_menu(self, m)
m.popup(QCursor.pos())
def dropEvent(self, evt) -> None:
def dropEvent(self, evt: QDropEvent) -> None:
pass
def setHtml(self, html: str) -> None: # type: ignore
@ -348,7 +360,7 @@ class AnkiWebView(QWebEngineView):
QWebEngineSettings.PlaybackRequiresUserGesture, value
)
def _getQtIntScale(self, screen) -> int:
def _getQtIntScale(self, screen: QWidget) -> int:
# try to detect if Qt has scaled the screen
# - qt will round the scale factor to a whole number, so a dpi of 125% = 1x,
# and a dpi of 150% = 2x
@ -434,7 +446,7 @@ body {{ zoom: {zoom}; background: {background}; direction: {lang_dir}; {font} }}
js: Optional[List[str]] = None,
head: str = "",
context: Optional[Any] = None,
):
) -> None:
web_content = WebContent(
body=body,
@ -508,7 +520,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) -> None:
def handler(val: Any) -> None:
if self._shouldIgnoreWebEvent():
print("ignored late js callback", cb)
return
@ -608,7 +620,7 @@ body {{ zoom: {zoom}; background: {background}; direction: {lang_dir}; {font} }}
"Add dynamic styling, and reveal."
css = self.standard_css()
def after_style(arg) -> None:
def after_style(arg: Any) -> None:
gui_hooks.webview_did_inject_style_into_page(self)
self.show()

View file

@ -165,7 +165,7 @@ hooks = [
),
Hook(
name="debug_console_did_evaluate_python",
args=["output: str", "query: str", "debug_window: QDialog"],
args=["output: str", "query: str", "debug_window: aqt.forms.debug.Ui_Dialog"],
return_type="str",
doc="""Allows processing the debug result. E.g. logging queries and
result, saving last query to display it later...""",