diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 1127a5ceb..80ea1f6ce 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -381,7 +381,11 @@ class DataModel(QAbstractTableModel): if count < 500: # discard large selections; they're too slow sm.select( - items, QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows + items, + cast( + QItemSelectionModel.SelectionFlags, + QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows, + ), ) else: tv.selectRow(0) @@ -1361,7 +1365,13 @@ where id in %s""" sm = self.form.tableView.selectionModel() items = sm.selection() self.form.tableView.selectAll() - sm.select(items, QItemSelectionModel.Deselect | QItemSelectionModel.Rows) + sm.select( + items, + cast( + QItemSelectionModel.SelectionFlags, + QItemSelectionModel.Deselect | QItemSelectionModel.Rows, + ), + ) # Hooks ###################################################################### @@ -1432,10 +1442,10 @@ where id in %s""" ) frm.fields.addItems(fields) restore_combo_index_for_session(frm.fields, fields, "findDupesFields") - self._dupesButton = None + self._dupesButton: Optional[QPushButton] = None # links - frm.webView.title = "find duplicates" + frm.webView.set_title("find duplicates") web_context = FindDupesDialog(dialog=d, browser=self) frm.webView.set_bridge_command(self.dupeLinkClicked, web_context) frm.webView.stdHtml("", context=web_context) @@ -1522,17 +1532,22 @@ where id in %s""" # Jumping ###################################################################### - def _moveCur(self, dir: int, idx: QModelIndex = None) -> None: + def _moveCur( + self, dir: Optional[QTableView.CursorAction], idx: QModelIndex = None + ) -> None: if not self.model.cards: return tv = self.form.tableView - if idx is None: + if dir is not None: idx = tv.moveCursor(dir, self.mw.app.keyboardModifiers()) tv.selectionModel().setCurrentIndex( idx, - QItemSelectionModel.Clear - | QItemSelectionModel.Select - | QItemSelectionModel.Rows, + cast( + QItemSelectionModel.SelectionFlags, + QItemSelectionModel.Clear + | QItemSelectionModel.Select + | QItemSelectionModel.Rows, + ), ) def onPreviousCard(self) -> None: @@ -1557,7 +1572,13 @@ where id in %s""" return idx2 = sm.currentIndex() item = QItemSelection(idx2, idx) - sm.select(item, QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows) + sm.select( + item, + cast( + QItemSelectionModel.SelectionFlags, + QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows, + ), + ) def onLastCard(self) -> None: sm = self.form.tableView.selectionModel() @@ -1567,7 +1588,13 @@ where id in %s""" return idx2 = sm.currentIndex() item = QItemSelection(idx, idx2) - sm.select(item, QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows) + sm.select( + item, + cast( + QItemSelectionModel.SelectionFlags, + QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows, + ), + ) def onFind(self) -> None: # workaround for PyQt focus bug diff --git a/qt/aqt/emptycards.py b/qt/aqt/emptycards.py index 7b168f393..db7cc2c6e 100644 --- a/qt/aqt/emptycards.py +++ b/qt/aqt/emptycards.py @@ -43,7 +43,7 @@ class EmptyCardsDialog(QDialog): self.setWindowTitle(tr.empty_cards_window_title()) disable_help_button(self) self.form.keep_notes.setText(tr.empty_cards_preserve_notes_checkbox()) - self.form.webview.title = "empty cards" + self.form.webview.set_title("empty cards") self.form.webview.set_bridge_command(self._on_note_link_clicked, self) gui_hooks.empty_cards_will_show(self) @@ -66,7 +66,7 @@ class EmptyCardsDialog(QDialog): tr.empty_cards_delete_button(), QDialogButtonBox.ActionRole ) self._delete_button.setAutoDefault(False) - self._delete_button.clicked.connect(self._on_delete) + qconnect(self._delete_button.clicked, self._on_delete) def _on_note_link_clicked(self, link: str) -> None: aqt.dialogs.open("Browser", self.mw, search=(link,)) diff --git a/qt/aqt/fields.py b/qt/aqt/fields.py index 9fc0f35e4..2d5ed994a 100644 --- a/qt/aqt/fields.py +++ b/qt/aqt/fields.py @@ -49,7 +49,7 @@ class FieldDialog(QDialog): self.fillFields() self.setupSignals() self.form.fieldList.setDragDropMode(QAbstractItemView.InternalMove) - self.form.fieldList.dropEvent = self.onDrop + self.form.fieldList.dropEvent = self.onDrop # type: ignore[assignment] self.form.fieldList.setCurrentRow(0) self.exec_() diff --git a/qt/aqt/filtered_deck.py b/qt/aqt/filtered_deck.py index 21450e1aa..d06cfb40c 100644 --- a/qt/aqt/filtered_deck.py +++ b/qt/aqt/filtered_deck.py @@ -273,7 +273,7 @@ class FilteredDeckConfigDialog(QDialog): FilteredDeckConfig.SearchTerm( search=form.search.text(), limit=form.limit.value(), - order=form.order.currentIndex(), + order=form.order.currentIndex(), # type: ignore[arg-type] ) ] @@ -282,7 +282,7 @@ class FilteredDeckConfigDialog(QDialog): FilteredDeckConfig.SearchTerm( search=form.search_2.text(), limit=form.limit_2.value(), - order=form.order_2.currentIndex(), + order=form.order_2.currentIndex(), # type: ignore[arg-type] ) ) diff --git a/qt/aqt/find_and_replace.py b/qt/aqt/find_and_replace.py index 4cbbd2349..182f71cb3 100644 --- a/qt/aqt/find_and_replace.py +++ b/qt/aqt/find_and_replace.py @@ -111,11 +111,11 @@ class FindAndReplaceDialog(QDialog): self._find_history = restore_combo_history( self.form.find, self.COMBO_NAME + "Find" ) - self.form.find.completer().setCaseSensitivity(True) + self.form.find.completer().setCaseSensitivity(Qt.CaseSensitive) self._replace_history = restore_combo_history( self.form.replace, self.COMBO_NAME + "Replace" ) - self.form.replace.completer().setCaseSensitivity(True) + self.form.replace.completer().setCaseSensitivity(Qt.CaseSensitive) restore_is_checked(self.form.re, self.COMBO_NAME + "Regex") restore_is_checked(self.form.ignoreCase, self.COMBO_NAME + "ignoreCase") diff --git a/qt/aqt/forms/build_ui.py b/qt/aqt/forms/build_ui.py index 5b05fda42..9c13a379d 100644 --- a/qt/aqt/forms/build_ui.py +++ b/qt/aqt/forms/build_ui.py @@ -16,5 +16,15 @@ outdata = re.sub( r'(?:QtGui\.QApplication\.)?_?translate\(".*?", "(.*?)"', "tr.\\1(", outdata ) + +outlines = [] +qt_bad_types = [".connect(", "setStandardButtons", "setTextInteractionFlags", "setAlignment"] +for line in outdata.splitlines(): + for substr in qt_bad_types: + if substr in line: + line = line + " # type: ignore" + break + outlines.append(line) + with open(py_file, "w") as file: - file.write(outdata) + file.write("\n".join(outlines)) diff --git a/qt/aqt/main.py b/qt/aqt/main.py index a1e8cee54..839dfda36 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -1622,22 +1622,24 @@ title="%s" %s>%s""" % ( s = self.debugDiagShort = QShortcut(QKeySequence("ctrl+shift+l"), d) qconnect(s.activated, frm.text.clear) - def addContextMenu(ev: QCloseEvent, name: str) -> None: + def addContextMenu( + ev: Union[QCloseEvent, QContextMenuEvent], name: str + ) -> None: ev.accept() menu = frm.log.createStandardContextMenu(QCursor.pos()) menu.addSeparator() if name == "log": a = menu.addAction("Clear Log") - a.setShortcuts(QKeySequence("ctrl+l")) + a.setShortcut(QKeySequence("ctrl+l")) qconnect(a.triggered, frm.log.clear) elif name == "text": a = menu.addAction("Clear Code") - a.setShortcuts(QKeySequence("ctrl+shift+l")) + a.setShortcut(QKeySequence("ctrl+shift+l")) qconnect(a.triggered, frm.text.clear) menu.exec_(QCursor.pos()) - frm.log.contextMenuEvent = lambda ev: addContextMenu(ev, "log") - frm.text.contextMenuEvent = lambda ev: addContextMenu(ev, "text") + frm.log.contextMenuEvent = lambda ev: addContextMenu(ev, "log") # type: ignore[assignment] + frm.text.contextMenuEvent = lambda ev: addContextMenu(ev, "text") # type: ignore[assignment] gui_hooks.debug_console_will_show(d) d.show() diff --git a/qt/aqt/models.py b/qt/aqt/models.py index 82d022e2a..ede4a535d 100644 --- a/qt/aqt/models.py +++ b/qt/aqt/models.py @@ -3,10 +3,10 @@ from concurrent.futures import Future from operator import itemgetter -from typing import Any, List, Optional, Sequence +from typing import List, Optional, Sequence import aqt.clayout -from anki import stdmodels +from anki import Collection, stdmodels from anki.lang import without_unicode_isolation from anki.models import NoteType, NoteTypeID, NoteTypeNameIDUseCount from anki.notes import Note @@ -133,7 +133,7 @@ class Models(QDialog): def current_notetype(self) -> NoteType: row = self.form.modelsList.currentRow() - return self.mm.get(self.models[row].id) + return self.mm.get(NoteTypeID(self.models[row].id)) def onAdd(self) -> None: m = AddModel(self.mw, self).get() @@ -229,16 +229,16 @@ class AddModel(QDialog): self.dialog.setupUi(self) disable_help_button(self) # standard models - self.models = [] + self.notetypes: List[Union[NoteType, Callable[[Collection], NoteType]]] = [] for (name, func) in stdmodels.get_stock_notetypes(self.col): item = QListWidgetItem(tr.notetypes_add(val=name)) self.dialog.models.addItem(item) - self.models.append((True, func)) + self.notetypes.append(func) # add copies for m in sorted(self.col.models.all(), key=itemgetter("name")): item = QListWidgetItem(tr.notetypes_clone(val=m["name"])) self.dialog.models.addItem(item) - self.models.append((False, m)) # type: ignore + self.notetypes.append(m) self.dialog.models.setCurrentRow(0) # the list widget will swallow the enter key s = QShortcut(QKeySequence("Return"), self) @@ -246,7 +246,7 @@ class AddModel(QDialog): # help qconnect(self.dialog.buttonBox.helpRequested, self.onHelp) - def get(self) -> Any: + def get(self) -> Optional[NoteType]: self.exec_() return self.model @@ -254,14 +254,14 @@ class AddModel(QDialog): QDialog.reject(self) def accept(self) -> None: - (isStd, model) = self.models[self.dialog.models.currentRow()] - if isStd: - # create - self.model = model(self.col) - else: + model = self.notetypes[self.dialog.models.currentRow()] + if isinstance(model, dict): # add copy to deck self.model = self.mw.col.models.copy(model) self.mw.col.models.setCurrent(self.model) + else: + # create + self.model = model(self.col) QDialog.accept(self) def onHelp(self) -> None: diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py index 31f8fd432..758f769d2 100644 --- a/qt/aqt/preferences.py +++ b/qt/aqt/preferences.py @@ -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 typing import Any, cast + import anki.lang import aqt from anki.consts import newCardSchedulingLabels @@ -82,7 +84,7 @@ class Preferences(QDialog): form = self.form scheduling = self.prefs.scheduling - scheduling.new_review_mix = form.newSpread.currentIndex() + scheduling.new_review_mix = cast(Any, form.newSpread.currentIndex()) scheduling.learn_ahead_secs = form.lrnCutoff.value() * 60 scheduling.day_learn_first = form.dayLearnFirst.isChecked() scheduling.rollover = form.dayOffset.value() diff --git a/qt/aqt/stats.py b/qt/aqt/stats.py index 3d8c94168..755a3d355 100644 --- a/qt/aqt/stats.py +++ b/qt/aqt/stats.py @@ -182,7 +182,7 @@ class DeckStats(QDialog): stats = self.mw.col.stats() stats.wholeCollection = self.wholeCollection self.report = stats.report(type=self.period) - self.form.web.title = "deck stats" + self.form.web.set_title("deck stats") self.form.web.stdHtml( f"{self.report}", js=["js/vendor/jquery.min.js", "js/vendor/plot.js"], diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index 9c91a3ca6..029df2769 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -213,7 +213,7 @@ class AnkiWebView(QWebEngineView): self, parent: Optional[QWidget] = None, title: str = "default" ) -> None: QWebEngineView.__init__(self, parent=parent) - self.title = title # type: ignore + self.set_title(title) self._page = AnkiWebPage(self._onBridgeCmd) self._page.setBackgroundColor(self._getWindowColor()) # reduce flicker @@ -252,6 +252,9 @@ class AnkiWebView(QWebEngineView): activated=self.onPaste, ) + def set_title(self, title: str) -> None: + self.title = title # type: ignore[assignment] + def eventFilter(self, obj: QObject, evt: QEvent) -> bool: # disable pinch to zoom gesture if isinstance(evt, QNativeGestureEvent): diff --git a/qt/mypy.ini b/qt/mypy.ini index 089683636..d14f07fba 100644 --- a/qt/mypy.ini +++ b/qt/mypy.ini @@ -72,7 +72,6 @@ ignore_missing_imports = True ignore_missing_imports = True [mypy-aqt.forms.*] -check_untyped_defs=false disallow_untyped_defs=false [mypy-anki.*] disallow_untyped_defs=false