mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
more typing updates
This commit is contained in:
parent
4b112950b8
commit
6426edb0ac
23 changed files with 151 additions and 122 deletions
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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>"
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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] = []
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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...""",
|
||||
|
|
Loading…
Reference in a new issue