mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
enable type checking of aqt/forms, and fix the new typing issues
Referencing an invalid translation should now break the build
This commit is contained in:
parent
3079eaa460
commit
5a094e78fa
12 changed files with 83 additions and 40 deletions
|
@ -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
|
||||
|
|
|
@ -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,))
|
||||
|
|
|
@ -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_()
|
||||
|
||||
|
|
|
@ -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]
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -1622,22 +1622,24 @@ title="%s" %s>%s</button>""" % (
|
|||
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()
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"<html><body>{self.report}</body></html>",
|
||||
js=["js/vendor/jquery.min.js", "js/vendor/plot.js"],
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue