From f15715fb07bad68ebf1f985dd8cab8e12640e1ef Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 1 Feb 2021 22:08:56 +1000 Subject: [PATCH] add types to various other files Mainly automated with MonkeyType --- qt/aqt/addcards.py | 8 +++--- qt/aqt/clayout.py | 51 +++++++++++++++++---------------- qt/aqt/customstudy.py | 21 ++++++++------ qt/aqt/dyndeckconf.py | 21 +++++++++----- qt/aqt/editcurrent.py | 4 +-- qt/aqt/emptycards.py | 2 +- qt/aqt/errors.py | 28 +++++++++++------- qt/aqt/exporting.py | 6 ++-- qt/aqt/fields.py | 30 ++++++++++--------- qt/aqt/importing.py | 26 ++++++++++------- qt/aqt/main.py | 2 +- qt/aqt/mediasrv.py | 6 ++-- qt/aqt/models.py | 2 +- qt/aqt/overview.py | 24 ++++++++-------- qt/aqt/previewer.py | 49 ++++++++++++++++--------------- qt/aqt/profiles.py | 18 ++++++------ qt/aqt/progress.py | 28 +++++++++--------- qt/aqt/reviewer.py | 4 +-- qt/aqt/schema_change_tracker.py | 2 +- qt/aqt/stats.py | 14 ++++----- qt/aqt/studydeck.py | 6 ++-- qt/aqt/tagedit.py | 33 +++++++++++++-------- qt/aqt/taglimit.py | 19 ++++++------ qt/aqt/taskman.py | 2 +- qt/aqt/update.py | 3 +- 25 files changed, 227 insertions(+), 182 deletions(-) diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py index 5a8d07607..296dda0a0 100644 --- a/qt/aqt/addcards.py +++ b/qt/aqt/addcards.py @@ -137,7 +137,7 @@ class AddCards(QDialog): def removeTempNote(self, note: Note) -> None: print("removeTempNote() will go away") - def addHistory(self, note): + def addHistory(self, note: Note) -> None: self.history.insert(0, note.id) self.history = self.history[:15] self.historyButton.setEnabled(True) @@ -186,10 +186,10 @@ class AddCards(QDialog): gui_hooks.add_cards_did_add_note(note) return note - def addCards(self): + def addCards(self) -> None: self.editor.saveNow(self._addCards) - def _addCards(self): + def _addCards(self) -> None: self.editor.saveAddModeVars() if not self.addNote(self.editor.note): return @@ -202,7 +202,7 @@ class AddCards(QDialog): self.onReset(keep=True) self.mw.col.autosave() - def keyPressEvent(self, evt): + def keyPressEvent(self, evt: QKeyEvent) -> None: "Show answer on RET or register answer." if evt.key() in (Qt.Key_Enter, Qt.Key_Return) and self.editor.tags.hasFocus(): evt.accept() diff --git a/qt/aqt/clayout.py b/qt/aqt/clayout.py index 011b8fe5f..1525f9793 100644 --- a/qt/aqt/clayout.py +++ b/qt/aqt/clayout.py @@ -14,6 +14,7 @@ from anki.lang import without_unicode_isolation from anki.notes import Note from anki.template import TemplateRenderContext from aqt import AnkiQt, gui_hooks +from aqt.forms.browserdisp import Ui_Dialog from aqt.qt import * from aqt.schema_change_tracker import ChangeTracker from aqt.sound import av_player, play_clicked_audio @@ -90,7 +91,7 @@ class CardLayout(QDialog): # as users tend to accidentally type into the template self.setFocus() - def redraw_everything(self): + def redraw_everything(self) -> None: self.ignore_change_signals = True self.updateTopArea() self.ignore_change_signals = False @@ -104,13 +105,13 @@ class CardLayout(QDialog): self.fill_fields_from_template() self.renderPreview() - def _isCloze(self): + def _isCloze(self) -> bool: return self.model["type"] == MODEL_CLOZE # Top area ########################################################################## - def setupTopArea(self): + def setupTopArea(self) -> None: self.topArea = QWidget() self.topArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) self.topAreaForm = aqt.forms.clayout_top.Ui_Form() @@ -125,10 +126,10 @@ class CardLayout(QDialog): ) self.topAreaForm.card_type_label.setText(tr(TR.CARD_TEMPLATES_CARD_TYPE)) - def updateTopArea(self): + def updateTopArea(self) -> None: self.updateCardNames() - def updateCardNames(self): + def updateCardNames(self) -> None: self.ignore_change_signals = True combo = self.topAreaForm.templatesBox combo.clear() @@ -170,7 +171,7 @@ class CardLayout(QDialog): s += "+..." return s - def setupShortcuts(self): + def setupShortcuts(self) -> None: self.tform.front_button.setToolTip(shortcut("Ctrl+1")) self.tform.back_button.setToolTip(shortcut("Ctrl+2")) self.tform.style_button.setToolTip(shortcut("Ctrl+3")) @@ -193,7 +194,7 @@ class CardLayout(QDialog): # Main area setup ########################################################################## - def setupMainArea(self): + def setupMainArea(self) -> None: split = self.mainArea = QSplitter() split.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) split.setOrientation(Qt.Horizontal) @@ -216,7 +217,7 @@ class CardLayout(QDialog): split.addWidget(right) split.setCollapsible(1, False) - def setup_edit_area(self): + def setup_edit_area(self) -> None: tform = self.tform tform.front_button.setText(tr(TR.CARD_TEMPLATES_FRONT_TEMPLATE)) @@ -248,7 +249,7 @@ class CardLayout(QDialog): qconnect(widg.textChanged, self.on_search_changed) qconnect(widg.returnPressed, self.on_search_next) - def setup_cloze_number_box(self): + def setup_cloze_number_box(self) -> None: names = (tr(TR.CARD_TEMPLATES_CLOZE, val=n) for n in self.cloze_numbers) self.pform.cloze_number_combo.addItems(names) try: @@ -266,7 +267,7 @@ class CardLayout(QDialog): self.have_autoplayed = False self._renderPreview() - def on_editor_toggled(self): + def on_editor_toggled(self) -> None: if self.tform.front_button.isChecked(): self.current_editor_index = 0 self.pform.preview_front.setChecked(True) @@ -297,7 +298,7 @@ class CardLayout(QDialog): text = self.tform.search_edit.text() self.on_search_changed(text) - def setup_preview(self): + def setup_preview(self) -> None: pform = self.pform self.preview_web = AnkiWebView(title="card layout") pform.verticalLayout.addWidget(self.preview_web) @@ -336,7 +337,7 @@ class CardLayout(QDialog): self.cloze_numbers = [] self.pform.cloze_number_combo.setHidden(True) - def on_fill_empty_action_toggled(self): + def on_fill_empty_action_toggled(self) -> None: self.fill_empty_action_toggled = not self.fill_empty_action_toggled self.on_preview_toggled() @@ -344,11 +345,11 @@ class CardLayout(QDialog): self.night_mode_is_enabled = not self.night_mode_is_enabled self.on_preview_toggled() - def on_mobile_class_action_toggled(self): + def on_mobile_class_action_toggled(self) -> None: self.mobile_emulation_enabled = not self.mobile_emulation_enabled self.on_preview_toggled() - def on_preview_settings(self): + def on_preview_settings(self) -> None: m = QMenu(self) a = m.addAction(tr(TR.CARD_TEMPLATES_FILL_EMPTY)) @@ -370,7 +371,7 @@ class CardLayout(QDialog): m.exec_(self.pform.preview_settings.mapToGlobal(QPoint(0, 0))) - def on_preview_toggled(self): + def on_preview_toggled(self) -> None: self.have_autoplayed = False self._renderPreview() @@ -388,7 +389,7 @@ class CardLayout(QDialog): # Buttons ########################################################################## - def setupButtons(self): + def setupButtons(self) -> None: l = self.buttons = QHBoxLayout() help = QPushButton(tr(TR.ACTIONS_HELP)) help.setAutoDefault(False) @@ -424,7 +425,7 @@ class CardLayout(QDialog): return self.templates[0] return self.templates[self.ord] - def fill_fields_from_template(self): + def fill_fields_from_template(self) -> None: t = self.current_template() self.ignore_change_signals = True @@ -438,7 +439,7 @@ class CardLayout(QDialog): self.tform.edit_area.setPlainText(text) self.ignore_change_signals = False - def write_edits_to_template_and_redraw(self): + def write_edits_to_template_and_redraw(self) -> None: if self.ignore_change_signals: return @@ -458,14 +459,14 @@ class CardLayout(QDialog): # Preview ########################################################################## - _previewTimer = None + _previewTimer: Optional[QTimer] = None - def renderPreview(self): + def renderPreview(self) -> None: # schedule a preview when timing stops self.cancelPreviewTimer() self._previewTimer = self.mw.progress.timer(200, self._renderPreview, False) - def cancelPreviewTimer(self): + def cancelPreviewTimer(self) -> None: if self._previewTimer: self._previewTimer.stop() self._previewTimer = None @@ -512,7 +513,7 @@ class CardLayout(QDialog): self.updateCardNames() - def maybeTextInput(self, txt, type="q"): + def maybeTextInput(self, txt: str, type: str = "q") -> str: if "[[type:" not in txt: return txt origLen = len(txt) @@ -668,7 +669,7 @@ class CardLayout(QDialog): dst["qfmt"] = m.group(2).strip() return True - def onMore(self): + def onMore(self) -> None: m = QMenu(self) if not self._isCloze(): @@ -699,7 +700,7 @@ class CardLayout(QDialog): m.exec_(self.topAreaForm.templateOptions.mapToGlobal(QPoint(0, 0))) - def onBrowserDisplay(self): + def onBrowserDisplay(self) -> None: d = QDialog() disable_help_button(d) f = aqt.forms.browserdisp.Ui_Dialog() @@ -714,7 +715,7 @@ class CardLayout(QDialog): qconnect(f.buttonBox.accepted, lambda: self.onBrowserDisplayOk(f)) d.exec_() - def onBrowserDisplayOk(self, f): + def onBrowserDisplayOk(self, f: Ui_Dialog) -> None: t = self.current_template() self.change_tracker.mark_basic() t["bqfmt"] = f.qfmt.text().strip() diff --git a/qt/aqt/customstudy.py b/qt/aqt/customstudy.py index baa022243..ff0ed557c 100644 --- a/qt/aqt/customstudy.py +++ b/qt/aqt/customstudy.py @@ -1,6 +1,7 @@ # Copyright: Ankitects Pty Ltd and contributors # -*- coding: utf-8 -*- # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + import aqt from anki.collection import SearchTerm from anki.consts import * @@ -35,7 +36,7 @@ class CustomStudy(QDialog): f.radioNew.click() self.exec_() - def setupSignals(self): + def setupSignals(self) -> None: f = self.form qconnect(f.radioNew.clicked, lambda: self.onRadioChange(RADIO_NEW)) qconnect(f.radioRev.clicked, lambda: self.onRadioChange(RADIO_REV)) @@ -44,7 +45,7 @@ class CustomStudy(QDialog): qconnect(f.radioPreview.clicked, lambda: self.onRadioChange(RADIO_PREVIEW)) qconnect(f.radioCram.clicked, lambda: self.onRadioChange(RADIO_CRAM)) - def onRadioChange(self, idx): + def onRadioChange(self, idx: int) -> None: f = self.form sp = f.spin smin = 1 @@ -123,7 +124,7 @@ class CustomStudy(QDialog): f.buttonBox.button(QDialogButtonBox.Ok).setText(ok) self.radioIdx = idx - def accept(self): + def accept(self) -> None: f = self.form i = self.radioIdx spin = f.spin.value() @@ -132,13 +133,15 @@ class CustomStudy(QDialog): self.mw.col.decks.save(self.deck) self.mw.col.sched.extendLimits(spin, 0) self.mw.reset() - return QDialog.accept(self) + QDialog.accept(self) + return elif i == RADIO_REV: self.deck["extendRev"] = spin self.mw.col.decks.save(self.deck) self.mw.col.sched.extendLimits(0, spin) self.mw.reset() - return QDialog.accept(self) + QDialog.accept(self) + return elif i == RADIO_CRAM: tags = self._getTags() # the rest create a filtered deck @@ -146,7 +149,8 @@ class CustomStudy(QDialog): if cur: if not cur["dyn"]: showInfo(tr(TR.CUSTOM_STUDY_MUST_RENAME_DECK)) - return QDialog.accept(self) + QDialog.accept(self) + return else: # safe to empty self.mw.col.sched.empty_filtered_deck(cur["id"]) @@ -211,7 +215,8 @@ class CustomStudy(QDialog): # generate cards self.created_custom_study = True if not self.mw.col.sched.rebuild_filtered_deck(dyn["id"]): - return showWarning(tr(TR.CUSTOM_STUDY_NO_CARDS_MATCHED_THE_CRITERIA_YOU)) + showWarning(tr(TR.CUSTOM_STUDY_NO_CARDS_MATCHED_THE_CRITERIA_YOU)) + return self.mw.moveToState("overview") QDialog.accept(self) @@ -222,7 +227,7 @@ class CustomStudy(QDialog): # fixme: clean up the empty custom study deck QDialog.reject(self) - def _getTags(self): + def _getTags(self) -> str: from aqt.taglimit import TagLimit return TagLimit(self.mw, self).tags diff --git a/qt/aqt/dyndeckconf.py b/qt/aqt/dyndeckconf.py index 12b5180d4..0082537d5 100644 --- a/qt/aqt/dyndeckconf.py +++ b/qt/aqt/dyndeckconf.py @@ -1,12 +1,13 @@ # Copyright: Ankitects Pty Ltd and contributors # -*- coding: utf-8 -*- # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -from typing import List, Optional +from typing import Dict, List, Optional import aqt from anki.collection import SearchTerm from anki.errors import InvalidInput from anki.lang import without_unicode_isolation +from aqt.main import AnkiQt from aqt.qt import * from aqt.utils import ( TR, @@ -23,7 +24,13 @@ from aqt.utils import ( class DeckConf(QDialog): - def __init__(self, mw, first=False, search="", deck=None): + def __init__( + self, + mw: AnkiQt, + first: bool = False, + search: str = "", + deck: Optional[Dict] = None, + ) -> None: QDialog.__init__(self, mw) self.mw = mw self.deck = deck or self.mw.col.decks.current() @@ -65,7 +72,7 @@ class DeckConf(QDialog): self.exec_() saveGeom(self, "dyndeckconf") - def initialSetup(self): + def initialSetup(self) -> None: import anki.consts as cs self.form.order.addItems(list(cs.dynOrderLabels(self.mw.col).values())) @@ -73,12 +80,12 @@ class DeckConf(QDialog): qconnect(self.form.resched.stateChanged, self._onReschedToggled) - def _onReschedToggled(self, _state): + def _onReschedToggled(self, _state: int) -> None: self.form.previewDelayWidget.setVisible( not self.form.resched.isChecked() and self.mw.col.schedVer() > 1 ) - def loadConf(self): + def loadConf(self) -> None: f = self.form d = self.deck @@ -113,7 +120,7 @@ class DeckConf(QDialog): f.secondFilter.setChecked(False) f.filter2group.setVisible(False) - def saveConf(self): + def saveConf(self) -> None: f = self.form d = self.deck d["resched"] = f.resched.isChecked() @@ -142,7 +149,7 @@ class DeckConf(QDialog): self.ok = False QDialog.reject(self) - def accept(self): + def accept(self) -> None: try: self.saveConf() except InvalidInput as err: diff --git a/qt/aqt/editcurrent.py b/qt/aqt/editcurrent.py index d1bbc3491..f066c76ae 100644 --- a/qt/aqt/editcurrent.py +++ b/qt/aqt/editcurrent.py @@ -52,10 +52,10 @@ class EditCurrent(QDialog): tooltip("Please finish editing the existing card first.") self.onReset() - def reject(self): + def reject(self) -> None: self.saveAndClose() - def saveAndClose(self): + def saveAndClose(self) -> None: self.editor.saveNow(self._saveAndClose) def _saveAndClose(self) -> None: diff --git a/qt/aqt/emptycards.py b/qt/aqt/emptycards.py index b9e94d8de..aa1016776 100644 --- a/qt/aqt/emptycards.py +++ b/qt/aqt/emptycards.py @@ -68,7 +68,7 @@ class EmptyCardsDialog(QDialog): def _on_note_link_clicked(self, link): self.mw.browser_search(link) - def _on_delete(self): + def _on_delete(self) -> None: self.mw.progress.start() def delete(): diff --git a/qt/aqt/errors.py b/qt/aqt/errors.py index bfbf12ab8..485ddc898 100644 --- a/qt/aqt/errors.py +++ b/qt/aqt/errors.py @@ -5,10 +5,12 @@ import html import re import sys import traceback +from typing import Optional from markdown import markdown from aqt import mw +from aqt.main import AnkiQt from aqt.qt import * from aqt.utils import TR, showText, showWarning, supportText, tr @@ -29,20 +31,20 @@ class ErrorHandler(QObject): errorTimer = pyqtSignal() - def __init__(self, mw): + def __init__(self, mw: AnkiQt) -> None: QObject.__init__(self, mw) self.mw = mw - self.timer = None + self.timer: Optional[QTimer] = None qconnect(self.errorTimer, self._setTimer) self.pool = "" self._oldstderr = sys.stderr sys.stderr = self - def unload(self): + def unload(self) -> None: sys.stderr = self._oldstderr sys.excepthook = None - def write(self, data): + def write(self, data: str) -> None: # dump to stdout sys.stdout.write(data) # save in buffer @@ -50,12 +52,12 @@ class ErrorHandler(QObject): # and update timer self.setTimer() - def setTimer(self): + def setTimer(self) -> None: # we can't create a timer from a different thread, so we post a # message to the object on the main thread self.errorTimer.emit() # type: ignore - def _setTimer(self): + def _setTimer(self) -> None: if not self.timer: self.timer = QTimer(self.mw) qconnect(self.timer.timeout, self.onTimeout) @@ -66,7 +68,7 @@ class ErrorHandler(QObject): def tempFolderMsg(self): return tr(TR.QT_MISC_UNABLE_TO_ACCESS_ANKI_MEDIA_FOLDER) - def onTimeout(self): + def onTimeout(self) -> None: error = html.escape(self.pool) self.pool = "" self.mw.progress.clear() @@ -75,15 +77,19 @@ class ErrorHandler(QObject): if "DeprecationWarning" in error: return if "10013" in error: - return showWarning(tr(TR.QT_MISC_YOUR_FIREWALL_OR_ANTIVIRUS_PROGRAM_IS)) + showWarning(tr(TR.QT_MISC_YOUR_FIREWALL_OR_ANTIVIRUS_PROGRAM_IS)) + return if "no default input" in error.lower(): - return showWarning(tr(TR.QT_MISC_PLEASE_CONNECT_A_MICROPHONE_AND_ENSURE)) + showWarning(tr(TR.QT_MISC_PLEASE_CONNECT_A_MICROPHONE_AND_ENSURE)) + return if "invalidTempFolder" in error: - return showWarning(self.tempFolderMsg()) + showWarning(self.tempFolderMsg()) + return if "Beautiful Soup is not an HTTP client" in error: return if "database or disk is full" in error or "Errno 28" in error: - return showWarning(tr(TR.QT_MISC_YOUR_COMPUTERS_STORAGE_MAY_BE_FULL)) + showWarning(tr(TR.QT_MISC_YOUR_COMPUTERS_STORAGE_MAY_BE_FULL)) + return if "disk I/O error" in error: showWarning(markdown(tr(TR.ERRORS_ACCESSING_DB))) return diff --git a/qt/aqt/exporting.py b/qt/aqt/exporting.py index 6881dbd19..dd3157365 100644 --- a/qt/aqt/exporting.py +++ b/qt/aqt/exporting.py @@ -71,7 +71,7 @@ class ExportDialog(QDialog): index = self.frm.deck.findText(name) self.frm.deck.setCurrentIndex(index) - def exporterChanged(self, idx): + def exporterChanged(self, idx: int) -> None: self.exporter = self.exporters[idx][1](self.col) self.isApkg = self.exporter.ext == ".apkg" self.isVerbatim = getattr(self.exporter, "verbatim", False) @@ -94,7 +94,7 @@ class ExportDialog(QDialog): # show deck list? self.frm.deck.setVisible(not self.isVerbatim) - def accept(self): + def accept(self) -> None: self.exporter.includeSched = self.frm.includeSched.isChecked() self.exporter.includeMedia = self.frm.includeMedia.isChecked() self.exporter.includeTags = self.frm.includeTags.isChecked() @@ -177,7 +177,7 @@ class ExportDialog(QDialog): self.mw.taskman.run_in_background(do_export, on_done) - def on_export_finished(self): + def on_export_finished(self) -> None: if self.isVerbatim: msg = tr(TR.EXPORTING_COLLECTION_EXPORTED) self.mw.reopen() diff --git a/qt/aqt/fields.py b/qt/aqt/fields.py index 2cf6170ba..33b448dba 100644 --- a/qt/aqt/fields.py +++ b/qt/aqt/fields.py @@ -41,7 +41,7 @@ class FieldDialog(QDialog): self.form.buttonBox.button(QDialogButtonBox.Help).setAutoDefault(False) self.form.buttonBox.button(QDialogButtonBox.Cancel).setAutoDefault(False) self.form.buttonBox.button(QDialogButtonBox.Save).setAutoDefault(False) - self.currentIdx = None + self.currentIdx: Optional[int] = None self.oldSortField = self.model["sortf"] self.fillFields() self.setupSignals() @@ -52,13 +52,13 @@ class FieldDialog(QDialog): ########################################################################## - def fillFields(self): + def fillFields(self) -> None: self.currentIdx = None self.form.fieldList.clear() for c, f in enumerate(self.model["flds"]): self.form.fieldList.addItem("{}: {}".format(c + 1, f["name"])) - def setupSignals(self): + def setupSignals(self) -> None: f = self.form qconnect(f.fieldList.currentRowChanged, self.onRowChange) qconnect(f.fieldAdd.clicked, self.onAdd) @@ -86,29 +86,31 @@ class FieldDialog(QDialog): movePos -= 1 self.moveField(movePos + 1) # convert to 1 based. - def onRowChange(self, idx): + def onRowChange(self, idx: int) -> None: if idx == -1: return self.saveField() self.loadField(idx) - def _uniqueName(self, prompt, ignoreOrd=None, old=""): + def _uniqueName( + self, prompt: str, ignoreOrd: Optional[int] = None, old: str = "" + ) -> Optional[str]: txt = getOnlyText(prompt, default=old).replace('"', "").strip() if not txt: - return + return None if txt[0] in "#^/": showWarning(tr(TR.FIELDS_NAME_FIRST_LETTER_NOT_VALID)) - return + return None for letter in """:{"}""": if letter in txt: showWarning(tr(TR.FIELDS_NAME_INVALID_LETTER)) - return + return None for f in self.model["flds"]: if ignoreOrd is not None and f["ord"] == ignoreOrd: continue if f["name"] == txt: showWarning(tr(TR.FIELDS_THAT_FIELD_NAME_IS_ALREADY_USED)) - return + return None return txt def onRename(self): @@ -127,7 +129,7 @@ class FieldDialog(QDialog): self.fillFields() self.form.fieldList.setCurrentRow(idx) - def onAdd(self): + def onAdd(self) -> None: name = self._uniqueName(tr(TR.FIELDS_FIELD_NAME)) if not name: return @@ -185,7 +187,7 @@ class FieldDialog(QDialog): self.fillFields() self.form.fieldList.setCurrentRow(pos - 1) - def loadField(self, idx): + def loadField(self, idx: int) -> None: self.currentIdx = idx fld = self.model["flds"][idx] f = self.form @@ -195,7 +197,7 @@ class FieldDialog(QDialog): f.sortField.setChecked(self.model["sortf"] == fld["ord"]) f.rtl.setChecked(fld["rtl"]) - def saveField(self): + def saveField(self) -> None: # not initialized yet? if self.currentIdx is None: return @@ -219,14 +221,14 @@ class FieldDialog(QDialog): fld["rtl"] = rtl self.change_tracker.mark_basic() - def reject(self): + def reject(self) -> None: if self.change_tracker.changed(): if not askUser("Discard changes?"): return QDialog.reject(self) - def accept(self): + def accept(self) -> None: self.saveField() def save(): diff --git a/qt/aqt/importing.py b/qt/aqt/importing.py index ed69fc2b9..e0b77df11 100644 --- a/qt/aqt/importing.py +++ b/qt/aqt/importing.py @@ -9,12 +9,13 @@ import traceback import unicodedata import zipfile from concurrent.futures import Future -from typing import Optional +from typing import Any, Optional import anki.importing as importing import aqt.deckchooser import aqt.forms import aqt.modelchooser +from anki.importing.apkg import AnkiPackageImporter from aqt import AnkiQt, gui_hooks from aqt.qt import * from aqt.utils import ( @@ -106,14 +107,14 @@ class ImportDialog(QDialog): self.frm.buttonBox.addButton(b, QDialogButtonBox.AcceptRole) self.exec_() - def setupOptions(self): + def setupOptions(self) -> None: self.model = self.mw.col.models.current() self.modelChooser = aqt.modelchooser.ModelChooser( self.mw, self.frm.modelArea, label=False ) self.deck = aqt.deckchooser.DeckChooser(self.mw, self.frm.deckArea, label=False) - def modelChanged(self, unused=None): + def modelChanged(self, unused: Any = None) -> None: self.importer.model = self.mw.col.models.current() self.importer.initMapping() self.showMapping() @@ -142,7 +143,7 @@ class ImportDialog(QDialog): self.showMapping(hook=updateDelim) self.updateDelimiterButtonText() - def updateDelimiterButtonText(self): + def updateDelimiterButtonText(self) -> None: if not self.importer.needDelimiter: return if self.importer.delimiter: @@ -164,7 +165,7 @@ class ImportDialog(QDialog): txt = tr(TR.IMPORTING_FIELDS_SEPARATED_BY, val=d) self.frm.autoDetect.setText(txt) - def accept(self): + def accept(self) -> None: self.importer.mapping = self.mapping if not self.importer.mappingOk(): showWarning(tr(TR.IMPORTING_THE_FIRST_FIELD_OF_THE_NOTE)) @@ -211,19 +212,21 @@ class ImportDialog(QDialog): self.mw.taskman.run_in_background(self.importer.run, on_done) - def setupMappingFrame(self): + def setupMappingFrame(self) -> None: # qt seems to have a bug with adding/removing from a grid, so we add # to a separate object and add/remove that instead self.frame = QFrame(self.frm.mappingArea) self.frm.mappingArea.setWidget(self.frame) self.mapbox = QVBoxLayout(self.frame) self.mapbox.setContentsMargins(0, 0, 0, 0) - self.mapwidget = None + self.mapwidget: Optional[QWidget] = None def hideMapping(self): self.frm.mappingGroup.hide() - def showMapping(self, keepMapping=False, hook=None): + def showMapping( + self, keepMapping: bool = False, hook: Optional[Callable] = None + ) -> None: if hook: hook() if not keepMapping: @@ -295,7 +298,7 @@ def showUnicodeWarning(): showWarning(tr(TR.IMPORTING_SELECTED_FILE_WAS_NOT_IN_UTF8)) -def onImport(mw): +def onImport(mw: AnkiQt) -> None: filt = ";;".join([x[0] for x in importing.Importers]) file = getFile(mw, tr(TR.ACTIONS_IMPORT), None, key="import", filter=filt) if not file: @@ -314,7 +317,7 @@ def onImport(mw): importFile(mw, file) -def importFile(mw, file): +def importFile(mw: AnkiQt, file: str) -> None: importerClass = None done = False for i in importing.Importers: @@ -406,7 +409,7 @@ def invalidZipMsg(): return tr(TR.IMPORTING_THIS_FILE_DOES_NOT_APPEAR_TO) -def setupApkgImport(mw, importer): +def setupApkgImport(mw: AnkiQt, importer: AnkiPackageImporter) -> bool: base = os.path.basename(importer.file).lower() full = ( (base == "collection.apkg") @@ -424,6 +427,7 @@ def setupApkgImport(mw, importer): return False replaceWithApkg(mw, importer.file, mw.restoringBackup) + return False def replaceWithApkg(mw, file, backup): diff --git a/qt/aqt/main.py b/qt/aqt/main.py index 591df9048..c549e5052 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -1141,7 +1141,7 @@ title="%s" %s>%s""" % ( # Cramming ########################################################################## - def onCram(self, search=""): + def onCram(self, search: str = "") -> None: import aqt.dyndeckconf n = 1 diff --git a/qt/aqt/mediasrv.py b/qt/aqt/mediasrv.py index 6609a5a7c..1af54e39d 100644 --- a/qt/aqt/mediasrv.py +++ b/qt/aqt/mediasrv.py @@ -26,7 +26,7 @@ from aqt.qt import * from aqt.utils import aqt_data_folder -def _getExportFolder(): +def _getExportFolder() -> str: data_folder = aqt_data_folder() webInSrcFolder = os.path.abspath(os.path.join(data_folder, "web")) if os.path.exists(webInSrcFolder): @@ -83,7 +83,7 @@ class MediaServer(threading.Thread): if not self.is_shutdown: raise - def shutdown(self): + def shutdown(self) -> None: self.is_shutdown = True sockets = list(self.server._map.values()) # type: ignore for socket in sockets: @@ -91,7 +91,7 @@ class MediaServer(threading.Thread): # https://github.com/Pylons/webtest/blob/4b8a3ebf984185ff4fefb31b4d0cf82682e1fcf7/webtest/http.py#L93-L104 self.server.task_dispatcher.shutdown() - def getPort(self): + def getPort(self) -> int: self._ready.wait() return int(self.server.effective_port) # type: ignore diff --git a/qt/aqt/models.py b/qt/aqt/models.py index bc398a5ba..df8154ee7 100644 --- a/qt/aqt/models.py +++ b/qt/aqt/models.py @@ -57,7 +57,7 @@ class Models(QDialog): # Models ########################################################################## - def maybe_select_provided_notetype(self): + def maybe_select_provided_notetype(self) -> None: if not self.selected_notetype_id: self.form.modelsList.setCurrentRow(0) return diff --git a/qt/aqt/overview.py b/qt/aqt/overview.py index 088065c95..e2756bbc1 100644 --- a/qt/aqt/overview.py +++ b/qt/aqt/overview.py @@ -4,7 +4,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Optional +from typing import Any, Callable, Dict, List, Optional, Tuple import aqt from anki.collection import SearchTerm @@ -45,13 +45,13 @@ class Overview: self.web = mw.web self.bottom = BottomBar(mw, mw.bottomWeb) - def show(self): + def show(self) -> None: av_player.stop_and_clear_queue() self.web.set_bridge_command(self._linkHandler, self) self.mw.setStateShortcuts(self._shortcutKeys()) self.refresh() - def refresh(self): + def refresh(self) -> None: self.mw.col.reset() self._renderPage() self._renderBottom() @@ -61,7 +61,7 @@ class Overview: # Handlers ############################################################ - def _linkHandler(self, url): + def _linkHandler(self, url: str) -> bool: if url == "study": self.mw.col.startTimebox() self.mw.moveToState("review") @@ -92,7 +92,7 @@ class Overview: openLink(url) return False - def _shortcutKeys(self): + def _shortcutKeys(self) -> List[Tuple[str, Callable]]: return [ ("o", self.mw.onDeckConf), ("r", self.onRebuildKey), @@ -101,7 +101,7 @@ class Overview: ("u", self.onUnbury), ] - def _filteredDeck(self): + def _filteredDeck(self) -> int: return self.mw.col.decks.current()["dyn"] def onRebuildKey(self): @@ -114,7 +114,7 @@ class Overview: self.mw.col.sched.empty_filtered_deck(self.mw.col.decks.selected()) self.mw.reset() - def onCustomStudyKey(self): + def onCustomStudyKey(self) -> None: if not self._filteredDeck(): self.onStudyMore() @@ -150,7 +150,7 @@ class Overview: # HTML ############################################################ - def _renderPage(self): + def _renderPage(self) -> None: but = self.mw.button deck = self.mw.col.decks.current() self.sid = deck.get("sharedFrom") @@ -177,10 +177,10 @@ class Overview: context=self, ) - def _show_finished_screen(self): + def _show_finished_screen(self) -> None: self.web.load_ts_page("congrats") - def _desc(self, deck): + def _desc(self, deck: Dict[str, Any]) -> str: if deck["dyn"]: desc = tr(TR.STUDYING_THIS_IS_A_SPECIAL_DECK_FOR) desc += " " + tr(TR.STUDYING_CARDS_WILL_BE_AUTOMATICALLY_RETURNED_TO) @@ -229,7 +229,7 @@ class Overview: # Bottom area ###################################################################### - def _renderBottom(self): + def _renderBottom(self) -> None: links = [ ["O", "opts", tr(TR.ACTIONS_OPTIONS)], ] @@ -256,7 +256,7 @@ class Overview: # Studying more ###################################################################### - def onStudyMore(self): + def onStudyMore(self) -> None: import aqt.customstudy aqt.customstudy.CustomStudy(self.mw) diff --git a/qt/aqt/previewer.py b/qt/aqt/previewer.py index 5c5b70d4d..7557a6412 100644 --- a/qt/aqt/previewer.py +++ b/qt/aqt/previewer.py @@ -4,7 +4,7 @@ import json import re import time -from typing import Any, Callable, Optional, Union +from typing import Any, Callable, Optional, Tuple, Union from anki.cards import Card from anki.collection import ConfigBoolKey @@ -19,6 +19,7 @@ from aqt.qt import ( QPixmap, QShortcut, Qt, + QTimer, QVBoxLayout, QWidget, qconnect, @@ -29,12 +30,14 @@ from aqt.theme import theme_manager from aqt.utils import TR, disable_help_button, restoreGeom, saveGeom, tr from aqt.webview import AnkiWebView +LastStateAndMod = Tuple[str, int, int] + class Previewer(QDialog): - _last_state = None + _last_state: Optional[LastStateAndMod] = None _card_changed = False _last_render: Union[int, float] = 0 - _timer = None + _timer: Optional[QTimer] = None _show_both_sides = False def __init__(self, parent: QWidget, mw: AnkiQt, on_close: Callable[[], None]): @@ -54,7 +57,7 @@ class Previewer(QDialog): def card_changed(self) -> bool: raise NotImplementedError - def open(self): + def open(self) -> None: self._state = "question" self._last_state = None self._create_gui() @@ -62,7 +65,7 @@ class Previewer(QDialog): self.render_card() self.show() - def _create_gui(self): + def _create_gui(self) -> None: self.setWindowTitle(tr(TR.ACTIONS_PREVIEW)) self.close_shortcut = QShortcut(QKeySequence("Ctrl+Shift+P"), self) @@ -98,25 +101,25 @@ class Previewer(QDialog): self.setLayout(self.vbox) restoreGeom(self, "preview") - def _on_finished(self, ok): + def _on_finished(self, ok: int) -> None: saveGeom(self, "preview") self.mw.progress.timer(100, self._on_close, False) - def _on_replay_audio(self): + def _on_replay_audio(self) -> None: if self._state == "question": replay_audio(self.card(), True) elif self._state == "answer": replay_audio(self.card(), False) - def close(self): + def close(self) -> None: self._on_close() super().close() - def _on_close(self): + def _on_close(self) -> None: self._open = False self._close_callback() - def _setup_web_view(self): + def _setup_web_view(self) -> None: jsinc = [ "js/vendor/jquery.min.js", "js/vendor/css_browser_selector.min.js", @@ -136,7 +139,7 @@ class Previewer(QDialog): if cmd.startswith("play:"): play_clicked_audio(cmd, self.card()) - def render_card(self): + def render_card(self) -> None: self.cancel_timer() # Keep track of whether render() has ever been called # with cardChanged=True since the last successful render @@ -151,7 +154,7 @@ class Previewer(QDialog): else: self._render_scheduled() - def cancel_timer(self): + def cancel_timer(self) -> None: if self._timer: self._timer.stop() self._timer = None @@ -214,7 +217,7 @@ class Previewer(QDialog): self._web.eval("{}({},'{}');".format(func, json.dumps(txt), bodyclass)) self._card_changed = False - def _on_show_both_sides(self, toggle): + def _on_show_both_sides(self, toggle: bool) -> None: self._show_both_sides = toggle self.mw.col.set_config_bool(ConfigBoolKey.PREVIEW_BOTH_SIDES, toggle) self.mw.col.setMod() @@ -222,7 +225,7 @@ class Previewer(QDialog): self._state = "question" self.render_card() - def _state_and_mod(self): + def _state_and_mod(self) -> Tuple[str, int, int]: c = self.card() n = c.note() n.load() @@ -241,7 +244,7 @@ class MultiCardPreviewer(Previewer): # need to state explicitly it's not implement to avoid W0223 raise NotImplementedError - def _create_gui(self): + def _create_gui(self) -> None: super()._create_gui() self._prev = self.bbox.addButton("<", QDialogButtonBox.ActionRole) self._prev.setAutoDefault(False) @@ -266,7 +269,7 @@ class MultiCardPreviewer(Previewer): def _on_prev_card(self): pass - def _on_next(self): + def _on_next(self) -> None: if self._state == "question": self._state = "answer" self.render_card() @@ -276,19 +279,19 @@ class MultiCardPreviewer(Previewer): def _on_next_card(self): pass - def _updateButtons(self): + def _updateButtons(self) -> None: if not self._open: return self._prev.setEnabled(self._should_enable_prev()) self._next.setEnabled(self._should_enable_next()) - def _should_enable_prev(self): + def _should_enable_prev(self) -> bool: return self._state == "answer" and not self._show_both_sides - def _should_enable_next(self): + def _should_enable_next(self) -> bool: return self._state == "question" - def _on_close(self): + def _on_close(self) -> None: super()._on_close() self._prev = None self._next = None @@ -317,15 +320,15 @@ class BrowserPreviewer(MultiCardPreviewer): lambda: self._parent._moveCur(QAbstractItemView.MoveUp) ) - def _on_next_card(self): + def _on_next_card(self) -> None: self._parent.editor.saveNow( lambda: self._parent._moveCur(QAbstractItemView.MoveDown) ) - def _should_enable_prev(self): + def _should_enable_prev(self) -> bool: return super()._should_enable_prev() or self._parent.currentRow() > 0 - def _should_enable_next(self): + def _should_enable_next(self) -> bool: return ( super()._should_enable_next() or self._parent.currentRow() < self._parent.model.rowCount(None) - 1 diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py index af548c5c3..6a42e4938 100644 --- a/qt/aqt/profiles.py +++ b/qt/aqt/profiles.py @@ -119,11 +119,11 @@ class AnkiRestart(SystemExit): class ProfileManager: - def __init__(self, base=None): + def __init__(self, base: Optional[str] = None) -> None: ## Settings which should be forgotten each Anki restart - self.session = {} - self.name = None - self.db = None + self.session: Dict[str, Any] = {} + self.name: Optional[str] = None + self.db: Optional[DB] = None self.profile: Optional[Dict] = None # instantiate base folder self.base: str @@ -170,7 +170,7 @@ class ProfileManager: return p return os.path.expanduser("~/Documents/Anki") - def maybeMigrateFolder(self): + def maybeMigrateFolder(self) -> None: newBase = self.base oldBase = self._oldFolderLocation() @@ -206,7 +206,7 @@ class ProfileManager: confirmation.setText( "Anki needs to move its data folder from Documents/Anki to a new location. Proceed?" ) - retval = confirmation.exec() + retval = confirmation.exec_() if retval == QMessageBox.Ok: progress = QMessageBox() @@ -228,7 +228,7 @@ class ProfileManager: completion.setWindowTitle(window_title) completion.setText("Migration complete. Please start Anki again.") completion.show() - completion.exec() + completion.exec_() else: diag = QMessageBox() diag.setIcon(QMessageBox.Warning) @@ -239,7 +239,7 @@ class ProfileManager: "Migration aborted. If you would like to keep the old folder location, please " "see the Startup Options section of the manual. Anki will now quit." ) - diag.exec() + diag.exec_() raise AnkiRestart(exitcode=0) @@ -424,7 +424,7 @@ class ProfileManager: os.makedirs(path) return path - def _setBaseFolder(self, cmdlineBase: None) -> None: + def _setBaseFolder(self, cmdlineBase: Optional[str]) -> None: if cmdlineBase: self.base = os.path.abspath(cmdlineBase) elif os.environ.get("ANKI_BASE"): diff --git a/qt/aqt/progress.py b/qt/aqt/progress.py index 2754f9b34..47229a3ee 100644 --- a/qt/aqt/progress.py +++ b/qt/aqt/progress.py @@ -4,7 +4,7 @@ from __future__ import annotations import time -from typing import Optional +from typing import Callable, Optional import aqt.forms from aqt.qt import * @@ -15,13 +15,13 @@ from aqt.utils import TR, disable_help_button, tr class ProgressManager: - def __init__(self, mw): + def __init__(self, mw: aqt.AnkiQt) -> None: self.mw = mw self.app = QApplication.instance() self.inDB = False self.blockUpdates = False self._show_timer: Optional[QTimer] = None - self._win = None + self._win: Optional[ProgressDialog] = None self._levels = 0 # Safer timers @@ -29,7 +29,9 @@ class ProgressManager: # A custom timer which avoids firing while a progress dialog is active # (likely due to some long-running DB operation) - def timer(self, ms, func, repeat, requiresCollection=True): + def timer( + self, ms: int, func: Callable, repeat: bool, requiresCollection: bool = True + ) -> QTimer: """Create and start a standard Anki timer. If the timer fires while a progress window is shown: @@ -136,7 +138,7 @@ class ProgressManager: self._updating = False self._lastUpdate = time.time() - def finish(self): + def finish(self) -> None: self._levels -= 1 self._levels = max(0, self._levels) if self._levels == 0: @@ -147,13 +149,13 @@ class ProgressManager: self._show_timer.stop() self._show_timer = None - def clear(self): + def clear(self) -> None: "Restore the interface after an error." if self._levels: self._levels = 1 self.finish() - def _maybeShow(self): + def _maybeShow(self) -> None: if not self._levels: return if self._shown: @@ -181,17 +183,17 @@ class ProgressManager: self._win = None self._shown = 0 - def _setBusy(self): + def _setBusy(self) -> None: self.mw.app.setOverrideCursor(QCursor(Qt.WaitCursor)) - def _unsetBusy(self): + def _unsetBusy(self) -> None: self.app.restoreOverrideCursor() - def busy(self): + def busy(self) -> int: "True if processing." return self._levels - def _on_show_timer(self): + def _on_show_timer(self) -> None: self._show_timer = None self._showWin() @@ -209,7 +211,7 @@ class ProgressManager: class ProgressDialog(QDialog): - def __init__(self, parent): + def __init__(self, parent: QWidget) -> None: QDialog.__init__(self, parent) disable_help_button(self) self.form = aqt.forms.progress.Ui_Dialog() @@ -219,7 +221,7 @@ class ProgressDialog(QDialog): # required for smooth progress bars self.form.progressBar.setStyleSheet("QProgressBar::chunk { width: 1px; }") - def cancel(self): + def cancel(self) -> None: self._closingDown = True self.hide() diff --git a/qt/aqt/reviewer.py b/qt/aqt/reviewer.py index a5f12e381..8a3e05998 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 Callable, List, Optional, Tuple, Union +from typing import Any, Callable, List, Optional, Tuple, Union from PyQt5.QtCore import Qt @@ -697,7 +697,7 @@ time = %(time)d; ########################################################################## # note the shortcuts listed here also need to be defined above - def _contextMenu(self): + def _contextMenu(self) -> List[Any]: currentFlag = self.card and self.card.userFlag() opts = [ [ diff --git a/qt/aqt/schema_change_tracker.py b/qt/aqt/schema_change_tracker.py index 59e9c955c..e489f6de6 100644 --- a/qt/aqt/schema_change_tracker.py +++ b/qt/aqt/schema_change_tracker.py @@ -20,7 +20,7 @@ class ChangeTracker: def __init__(self, mw: AnkiQt): self.mw = mw - def mark_basic(self): + def mark_basic(self) -> None: if self._changed == Change.NO_CHANGE: self._changed = Change.BASIC_CHANGE diff --git a/qt/aqt/stats.py b/qt/aqt/stats.py index 2903f1917..d9fe1c870 100644 --- a/qt/aqt/stats.py +++ b/qt/aqt/stats.py @@ -54,7 +54,7 @@ class NewDeckStats(QDialog): self.form.web.set_bridge_command(self._on_bridge_cmd, self) self.activateWindow() - def reject(self): + def reject(self) -> None: self.form.web = None saveGeom(self, self.name) aqt.dialogs.markClosed("NewDeckStats") @@ -98,14 +98,14 @@ class NewDeckStats(QDialog): return False - def refresh(self): + def refresh(self) -> None: self.form.web.load_ts_page("graphs") class DeckStats(QDialog): """Legacy deck stats, used by some add-ons.""" - def __init__(self, mw): + def __init__(self, mw: aqt.main.AnkiQt) -> None: QDialog.__init__(self, mw, Qt.Window) mw.setupDialogGC(self) self.mw = mw @@ -143,7 +143,7 @@ class DeckStats(QDialog): self.refresh() self.activateWindow() - def reject(self): + def reject(self) -> None: self.form.web = None saveGeom(self, self.name) aqt.dialogs.markClosed("DeckStats") @@ -173,15 +173,15 @@ class DeckStats(QDialog): self.form.web.page().printToPdf(path) tooltip(tr(TR.STATISTICS_SAVED)) - def changePeriod(self, n): + def changePeriod(self, n: int) -> None: self.period = n self.refresh() - def changeScope(self, type): + def changeScope(self, type: str) -> None: self.wholeCollection = type == "collection" self.refresh() - def refresh(self): + def refresh(self) -> None: self.mw.progress.start(parent=self) stats = self.mw.col.stats() stats.wholeCollection = self.wholeCollection diff --git a/qt/aqt/studydeck.py b/qt/aqt/studydeck.py index 106a38635..5ee750687 100644 --- a/qt/aqt/studydeck.py +++ b/qt/aqt/studydeck.py @@ -2,6 +2,8 @@ # -*- coding: utf-8 -*- # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +from typing import Optional + import aqt from aqt import gui_hooks from aqt.qt import * @@ -109,7 +111,7 @@ class StudyDeck(QDialog): return True return False - def redraw(self, filt, focus=None): + def redraw(self, filt: str, focus: Optional[str] = None) -> None: self.filt = filt self.focus = focus self.names = [n for n in self.origNames if self._matches(n, filt)] @@ -123,7 +125,7 @@ class StudyDeck(QDialog): l.setCurrentRow(idx) l.scrollToItem(l.item(idx), QAbstractItemView.PositionAtCenter) - def _matches(self, name, filt): + def _matches(self, name: str, filt: str) -> bool: name = name.lower() filt = filt.lower() if not filt: diff --git a/qt/aqt/tagedit.py b/qt/aqt/tagedit.py index a0ba44b26..ff81f9eae 100644 --- a/qt/aqt/tagedit.py +++ b/qt/aqt/tagedit.py @@ -4,7 +4,9 @@ from __future__ import annotations import re +from typing import Iterable, List, Optional, Union +from anki.collection import Collection from aqt import gui_hooks from aqt.qt import * @@ -15,9 +17,9 @@ class TagEdit(QLineEdit): lostFocus = pyqtSignal() # 0 = tags, 1 = decks - def __init__(self, parent, type=0): + def __init__(self, parent: QDialog, type: int = 0) -> None: QLineEdit.__init__(self, parent) - self.col = None + self.col: Optional[Collection] = None self.model = QStringListModel() self.type = type if type == 0: @@ -28,19 +30,20 @@ class TagEdit(QLineEdit): self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.setCompleter(self.completer) - def setCol(self, col): + def setCol(self, col: Collection) -> None: "Set the current col, updating list of available tags." self.col = col + l: Iterable[str] if self.type == 0: l = self.col.tags.all() else: l = (d.name for d in self.col.decks.all_names_and_ids()) self.model.setStringList(l) - def focusInEvent(self, evt): + def focusInEvent(self, evt: QFocusEvent) -> None: QLineEdit.focusInEvent(self, evt) - def keyPressEvent(self, evt): + def keyPressEvent(self, evt: QKeyEvent) -> None: if evt.key() in (Qt.Key_Up, Qt.Key_Down): # show completer on arrow key up/down if not self.completer.popup().isVisible(): @@ -85,7 +88,7 @@ class TagEdit(QLineEdit): self.showCompleter() gui_hooks.tag_editor_did_process_key(self, evt) - def showCompleter(self): + def showCompleter(self) -> None: self.completer.setCompletionPrefix(self.text()) self.completer.complete() @@ -94,20 +97,26 @@ class TagEdit(QLineEdit): self.lostFocus.emit() # type: ignore self.completer.popup().hide() - def hideCompleter(self): + def hideCompleter(self) -> None: if sip.isdeleted(self.completer): return self.completer.popup().hide() class TagCompleter(QCompleter): - def __init__(self, model, parent, edit, *args): + def __init__( + self, + model: QStringListModel, + parent: QWidget, + edit: TagEdit, + *args, + ) -> None: QCompleter.__init__(self, model, parent) - self.tags = [] + self.tags: List[str] = [] self.edit = edit - self.cursor = None + self.cursor: Optional[int] = None - def splitPath(self, tags): + def splitPath(self, tags: str) -> List[str]: stripped_tags = tags.strip() stripped_tags = re.sub(" +", " ", stripped_tags) self.tags = self.edit.col.tags.split(stripped_tags) @@ -119,7 +128,7 @@ class TagCompleter(QCompleter): self.cursor = stripped_tags.count(" ", 0, p) return [self.tags[self.cursor]] - def pathFromIndex(self, idx): + def pathFromIndex(self, idx: QModelIndex) -> str: if self.cursor is None: return self.edit.text() ret = QCompleter.pathFromIndex(self, idx) diff --git a/qt/aqt/taglimit.py b/qt/aqt/taglimit.py index cd79dedce..c28392a6d 100644 --- a/qt/aqt/taglimit.py +++ b/qt/aqt/taglimit.py @@ -3,14 +3,17 @@ from typing import List, Optional import aqt +from aqt.customstudy import CustomStudy +from aqt.main import AnkiQt from aqt.qt import * from aqt.utils import disable_help_button, restoreGeom, saveGeom class TagLimit(QDialog): - def __init__(self, mw, parent): + def __init__(self, mw: AnkiQt, parent: CustomStudy) -> None: QDialog.__init__(self, parent, Qt.Window) - self.tags: Union[str, List] = "" + self.tags: str = "" + self.tags_list: List[str] = [] self.mw = mw self.parent: Optional[QWidget] = parent self.deck = self.parent.deck @@ -29,7 +32,7 @@ class TagLimit(QDialog): restoreGeom(self, "tagLimit") self.exec_() - def rebuildTagList(self): + def rebuildTagList(self) -> None: usertags = self.mw.col.tags.byDeck(self.deck["id"], True) yes = self.deck.get("activeTags", []) no = self.deck.get("inactiveTags", []) @@ -42,10 +45,10 @@ class TagLimit(QDialog): groupedTags = [] usertags.sort() groupedTags.append(usertags) - self.tags = [] + self.tags_list = [] for tags in groupedTags: for t in tags: - self.tags.append(t) + self.tags_list.append(t) item = QListWidgetItem(t.replace("_", " ")) self.dialog.activeList.addItem(item) if t in yesHash: @@ -69,7 +72,7 @@ class TagLimit(QDialog): self.tags = "" QDialog.reject(self) - def accept(self): + def accept(self) -> None: self.hide() # gather yes/no tags yes = [] @@ -80,12 +83,12 @@ class TagLimit(QDialog): item = self.dialog.activeList.item(c) idx = self.dialog.activeList.indexFromItem(item) if self.dialog.activeList.selectionModel().isSelected(idx): - yes.append(self.tags[c]) + yes.append(self.tags_list[c]) # inactive item = self.dialog.inactiveList.item(c) idx = self.dialog.inactiveList.indexFromItem(item) if self.dialog.inactiveList.selectionModel().isSelected(idx): - no.append(self.tags[c]) + no.append(self.tags_list[c]) # save in the deck for future invocations self.deck["activeTags"] = yes self.deck["inactiveTags"] = no diff --git a/qt/aqt/taskman.py b/qt/aqt/taskman.py index fa103199f..264b4f6c1 100644 --- a/qt/aqt/taskman.py +++ b/qt/aqt/taskman.py @@ -78,7 +78,7 @@ class TaskManager(QObject): self.run_in_background(task, wrapped_done) - def _on_closures_pending(self): + def _on_closures_pending(self) -> None: """Run any pending closures. This runs in the main thread.""" with self._closures_lock: closures = self._closures diff --git a/qt/aqt/update.py b/qt/aqt/update.py index d1178350a..32f956eb6 100644 --- a/qt/aqt/update.py +++ b/qt/aqt/update.py @@ -7,6 +7,7 @@ import requests import aqt from anki.utils import platDesc, versionWithBuild +from aqt.main import AnkiQt from aqt.qt import * from aqt.utils import TR, openLink, showText, tr @@ -17,7 +18,7 @@ class LatestVersionFinder(QThread): newMsg = pyqtSignal(dict) clockIsOff = pyqtSignal(float) - def __init__(self, main): + def __init__(self, main: AnkiQt) -> None: QThread.__init__(self) self.main = main self.config = main.pm.meta